From 97fe9cfd9f81fe96a70e1ce80fce04b0c937bfac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Langa?= Date: Tue, 19 May 2020 01:07:09 +0200 Subject: [PATCH 0001/1314] Python 3.9.0b1 --- Doc/tools/extensions/pyspecific.py | 2 +- Include/patchlevel.h | 6 +- Lib/pydoc_data/topics.py | 2 +- Misc/NEWS.d/3.9.0b1.rst | 960 ++++++++++++++++++ .../2020-05-05-15-39-11.bpo-40514.bZZmuS.rst | 2 - .../2020-05-17-03-33-00.bpo-40653.WI8UGn.rst | 1 - .../2020-01-22-12-38-59.bpo-38787.HUH6hd.rst | 2 - .../2020-04-27-14-00-38.bpo-40217.sgn6c8.rst | 5 - .../2020-04-28-15-47-58.bpo-40421.ZIzOV0.rst | 2 - .../2020-04-28-19-29-36.bpo-40421.3uIIaB.rst | 1 - .../2020-04-28-23-17-27.bpo-40428.rmtpru.rst | 11 - .../2020-04-29-01-39-41.bpo-40429.VQfvta.rst | 2 - .../2020-05-01-17-28-04.bpo-40412.dE0D8N.rst | 1 - .../2020-05-07-11-41-13.bpo-40545.51DzF1.rst | 3 - .../2020-05-10-16-39-08.bpo-38787.XzQ59O.rst | 2 - .../2020-05-14-00-36-19.bpo-39465.3a5g-X.rst | 1 - .../2019-11-20-09-50-58.bpo-37986.o0lmA7.rst | 2 - .../2019-11-22-14-34-47.bpo-38880.evcCPa.rst | 1 - .../2020-04-08-17-02-35.bpo-40228.bRaaJ-.rst | 1 - .../2020-04-19-22-23-32.bpo-40328.gWJ53f.rst | 1 - .../2020-04-30-00-50-25.bpo-29587.oEwSq.rst | 1 - ...2020-04-30-01-44-42.bpo-1635741.GKtjqr.rst | 1 - .../2020-05-01-15-36-14.bpo-40408.XzQI59.rst | 2 - .../2020-05-01-19-04-52.bpo-40417.Sti2lJ.rst | 1 - .../2020-05-03-23-28-11.bpo-40246.c1D7x8.rst | 1 - ...2020-05-05-03-36-27.bpo-1635741.ARv1YV.rst | 1 - .../2020-05-05-20-36-15.bpo-40523.hKZVTB.rst | 2 - ...2020-05-05-21-11-35.bpo-1635741.ggwD3C.rst | 1 - .../2020-05-06-14-52-35.bpo-40527.gTNKuy.rst | 2 - .../2020-05-08-03-25-26.bpo-40502.e-VCyL.rst | 2 - .../2020-05-09-01-39-16.bpo-40566.wlcjW_.rst | 1 - .../2020-05-11-00-19-42.bpo-40585.yusknY.rst | 2 - .../2020-05-11-13-50-52.bpo-40593.yuOXj3.rst | 1 - .../2020-05-11-20-53-52.bpo-40596.dwOH_X.rst | 2 - .../2020-05-17-20-38-12.bpo-40663.u2aiZf.rst | 2 - .../2020-01-24-05-42-57.bpo-39435.EFcdFU.rst | 1 - .../2020-03-14-18-37-06.bpo-39705.nQVqig.rst | 2 - .../2020-05-04-14-20-02.bpo-40499.tjLSo8.rst | 1 - .../2020-05-08-08-39-40.bpo-40561.ZMB_2i.rst | 1 - .../2020-05-08-20-18-55.bpo-34790.t6kW_1.rst | 1 - .../2019-09-01-15-17-49.bpo-24416.G8Ww1U.rst | 3 - .../2019-12-15-19-17-10.bpo-39058.7ci-vd.rst | 4 - .../2020-03-21-05-26-38.bpo-40025.DTLtyq.rst | 1 - .../2020-04-05-04-16-14.bpo-40192.nk8uRJ.rst | 4 - .../2020-04-07-23-44-06.bpo-39075.hgck3j.rst | 2 - .../2020-04-14-09-54-35.bpo-40273.IN73Ks.rst | 1 - .../2020-04-14-22-31-27.bpo-40291._O8hXn.rst | 1 - .../2020-04-25-20-00-58.bpo-40389.FPA6f0.rst | 1 - .../2020-04-25-23-14-11.bpo-40375.5GuK2A.rst | 1 - .../2020-04-27-00-51-40.bpo-39791.wv8Dxn.rst | 1 - .../2020-04-27-14-48-43.bpo-39966.N5yXUe.rst | 2 - .../2020-04-27-17-19-09.bpo-30966._5lDx-.rst | 2 - .../2020-04-27-20-27-39.bpo-30966.Xmtlqu.rst | 2 - .../2020-04-28-18-25-27.bpo-39995.WmA3Gk.rst | 2 - .../2020-04-28-18-59-48.bpo-40394.Yi5uuM.rst | 1 - .../2020-04-29-18-02-16.bpo-40286.txbQNx.rst | 3 - .../2020-04-30-22-04-58.bpo-40453.ggz7sl.rst | 3 - .../2020-04-30-22-25-08.bpo-32494.1xaU5l.rst | 2 - .../2020-05-01-00-22-58.bpo-39305.Cuwu_H.rst | 2 - .../2020-05-01-23-24-25.bpo-39435.mgb6ib.rst | 1 - .../2020-05-02-04-29-31.bpo-40459.fSAYVD.rst | 1 - .../2020-05-02-12-00-28.bpo-40465.qfCjOD.rst | 1 - .../2020-05-02-14-24-48.bpo-40355.xTujaB.rst | 2 - .../2020-05-02-17-17-37.bpo-40457.EXReI1.rst | 1 - .../2020-05-04-11-20-49.bpo-40495.TyTc2O.rst | 2 - .../2020-05-04-21-21-43.bpo-40480.mjldWa.rst | 1 - .../2020-05-05-08-12-51.bpo-40559.112wwa.rst | 1 - .../2020-05-05-17-12-47.bpo-40504.EX6wPn.rst | 1 - .../2020-05-06-02-33-00.bpo-31033.aX12pw.rst | 2 - .../2020-05-06-13-51-19.bpo-40515.TUCvYB.rst | 3 - .../2020-05-06-15-36-47.bpo-40541.LlYghL.rst | 1 - .../2020-05-07-06-41-20.bpo-31033.waCj3n.rst | 1 - .../2020-05-07-20-11-51.bpo-40549.6FiRSV.rst | 2 - .../2020-05-07-21-22-04.bpo-40397.PVWFAn.rst | 2 - .../2020-05-08-15-48-39.bpo-40503.elZyxc.rst | 1 - .../2020-05-09-15-38-25.bpo-40571.kOXZGC.rst | 2 - .../2020-05-11-19-17-23.bpo-40597.4SGfgm.rst | 1 - .../2020-05-13-10-23-29.bpo-40612.gOIreM.rst | 2 - .../2020-05-13-15-32-13.bpo-40607.uSPFCi.rst | 3 - .../2020-05-13-23-10-25.bpo-40257.aR4TGp.rst | 1 - .../2020-05-15-17-38-21.bpo-40479.yamSCh.rst | 1 - .../2020-05-15-19-53-18.bpo-37630.O5kgAw.rst | 2 - .../2020-05-15-21-57-10.bpo-40637.lb3Bnp.rst | 2 - .../2020-05-16-17-05-02.bpo-40645.wYSkjT.rst | 1 - .../2020-05-16-19-34-38.bpo-40645.7ibMt-.rst | 3 - .../2020-05-17-14-00-12.bpo-40536.FCpoRA.rst | 2 - .../2020-05-17-21-56-38.bpo-40665.msB7u5.rst | 1 - .../2020-05-18-12-56-45.bpo-40662.dfornR.rst | 1 - .../2020-05-06-00-41-11.bpo-40501._61wv_.rst | 2 - .../2020-04-29-16-08-24.bpo-40436.gDMnYl.rst | 1 - .../2020-05-15-01-21-44.bpo-40055.Xp4aP9.rst | 3 - .../2020-04-03-08-32-31.bpo-40163.lX8K4B.rst | 3 - .../2020-04-29-01-32-17.bpo-40431.B_aEZ0.rst | 1 - .../2020-05-15-17-48-25.bpo-40479.B1gBl-.rst | 2 - .../2020-03-23-19-07-55.bpo-39148.W1YJEb.rst | 3 - .../2020-05-01-20-57-57.bpo-40458.Eb0ueI.rst | 1 - .../2020-05-17-00-08-13.bpo-40650.4euMtU.rst | 1 - .../2020-04-15-00-02-47.bpo-35569.02_1MV.rst | 1 - .../2020-05-18-02-43-11.bpo-34956.35IcGF.rst | 6 - README.rst | 4 +- 100 files changed, 967 insertions(+), 180 deletions(-) create mode 100644 Misc/NEWS.d/3.9.0b1.rst delete mode 100644 Misc/NEWS.d/next/Build/2020-05-05-15-39-11.bpo-40514.bZZmuS.rst delete mode 100644 Misc/NEWS.d/next/Build/2020-05-17-03-33-00.bpo-40653.WI8UGn.rst delete mode 100644 Misc/NEWS.d/next/C API/2020-01-22-12-38-59.bpo-38787.HUH6hd.rst delete mode 100644 Misc/NEWS.d/next/C API/2020-04-27-14-00-38.bpo-40217.sgn6c8.rst delete mode 100644 Misc/NEWS.d/next/C API/2020-04-28-15-47-58.bpo-40421.ZIzOV0.rst delete mode 100644 Misc/NEWS.d/next/C API/2020-04-28-19-29-36.bpo-40421.3uIIaB.rst delete mode 100644 Misc/NEWS.d/next/C API/2020-04-28-23-17-27.bpo-40428.rmtpru.rst delete mode 100644 Misc/NEWS.d/next/C API/2020-04-29-01-39-41.bpo-40429.VQfvta.rst delete mode 100644 Misc/NEWS.d/next/C API/2020-05-01-17-28-04.bpo-40412.dE0D8N.rst delete mode 100644 Misc/NEWS.d/next/C API/2020-05-07-11-41-13.bpo-40545.51DzF1.rst delete mode 100644 Misc/NEWS.d/next/C API/2020-05-10-16-39-08.bpo-38787.XzQ59O.rst delete mode 100644 Misc/NEWS.d/next/C API/2020-05-14-00-36-19.bpo-39465.3a5g-X.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2019-11-20-09-50-58.bpo-37986.o0lmA7.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2019-11-22-14-34-47.bpo-38880.evcCPa.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2020-04-08-17-02-35.bpo-40228.bRaaJ-.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2020-04-19-22-23-32.bpo-40328.gWJ53f.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2020-04-30-00-50-25.bpo-29587.oEwSq.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2020-04-30-01-44-42.bpo-1635741.GKtjqr.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2020-05-01-15-36-14.bpo-40408.XzQI59.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2020-05-01-19-04-52.bpo-40417.Sti2lJ.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2020-05-03-23-28-11.bpo-40246.c1D7x8.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2020-05-05-03-36-27.bpo-1635741.ARv1YV.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2020-05-05-20-36-15.bpo-40523.hKZVTB.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2020-05-05-21-11-35.bpo-1635741.ggwD3C.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2020-05-06-14-52-35.bpo-40527.gTNKuy.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2020-05-08-03-25-26.bpo-40502.e-VCyL.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2020-05-09-01-39-16.bpo-40566.wlcjW_.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2020-05-11-00-19-42.bpo-40585.yusknY.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2020-05-11-13-50-52.bpo-40593.yuOXj3.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2020-05-11-20-53-52.bpo-40596.dwOH_X.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2020-05-17-20-38-12.bpo-40663.u2aiZf.rst delete mode 100644 Misc/NEWS.d/next/Documentation/2020-01-24-05-42-57.bpo-39435.EFcdFU.rst delete mode 100644 Misc/NEWS.d/next/Documentation/2020-03-14-18-37-06.bpo-39705.nQVqig.rst delete mode 100644 Misc/NEWS.d/next/Documentation/2020-05-04-14-20-02.bpo-40499.tjLSo8.rst delete mode 100644 Misc/NEWS.d/next/Documentation/2020-05-08-08-39-40.bpo-40561.ZMB_2i.rst delete mode 100644 Misc/NEWS.d/next/Documentation/2020-05-08-20-18-55.bpo-34790.t6kW_1.rst delete mode 100644 Misc/NEWS.d/next/Library/2019-09-01-15-17-49.bpo-24416.G8Ww1U.rst delete mode 100644 Misc/NEWS.d/next/Library/2019-12-15-19-17-10.bpo-39058.7ci-vd.rst delete mode 100644 Misc/NEWS.d/next/Library/2020-03-21-05-26-38.bpo-40025.DTLtyq.rst delete mode 100644 Misc/NEWS.d/next/Library/2020-04-05-04-16-14.bpo-40192.nk8uRJ.rst delete mode 100644 Misc/NEWS.d/next/Library/2020-04-07-23-44-06.bpo-39075.hgck3j.rst delete mode 100644 Misc/NEWS.d/next/Library/2020-04-14-09-54-35.bpo-40273.IN73Ks.rst delete mode 100644 Misc/NEWS.d/next/Library/2020-04-14-22-31-27.bpo-40291._O8hXn.rst delete mode 100644 Misc/NEWS.d/next/Library/2020-04-25-20-00-58.bpo-40389.FPA6f0.rst delete mode 100644 Misc/NEWS.d/next/Library/2020-04-25-23-14-11.bpo-40375.5GuK2A.rst delete mode 100644 Misc/NEWS.d/next/Library/2020-04-27-00-51-40.bpo-39791.wv8Dxn.rst delete mode 100644 Misc/NEWS.d/next/Library/2020-04-27-14-48-43.bpo-39966.N5yXUe.rst delete mode 100644 Misc/NEWS.d/next/Library/2020-04-27-17-19-09.bpo-30966._5lDx-.rst delete mode 100644 Misc/NEWS.d/next/Library/2020-04-27-20-27-39.bpo-30966.Xmtlqu.rst delete mode 100644 Misc/NEWS.d/next/Library/2020-04-28-18-25-27.bpo-39995.WmA3Gk.rst delete mode 100644 Misc/NEWS.d/next/Library/2020-04-28-18-59-48.bpo-40394.Yi5uuM.rst delete mode 100644 Misc/NEWS.d/next/Library/2020-04-29-18-02-16.bpo-40286.txbQNx.rst delete mode 100644 Misc/NEWS.d/next/Library/2020-04-30-22-04-58.bpo-40453.ggz7sl.rst delete mode 100644 Misc/NEWS.d/next/Library/2020-04-30-22-25-08.bpo-32494.1xaU5l.rst delete mode 100644 Misc/NEWS.d/next/Library/2020-05-01-00-22-58.bpo-39305.Cuwu_H.rst delete mode 100644 Misc/NEWS.d/next/Library/2020-05-01-23-24-25.bpo-39435.mgb6ib.rst delete mode 100644 Misc/NEWS.d/next/Library/2020-05-02-04-29-31.bpo-40459.fSAYVD.rst delete mode 100644 Misc/NEWS.d/next/Library/2020-05-02-12-00-28.bpo-40465.qfCjOD.rst delete mode 100644 Misc/NEWS.d/next/Library/2020-05-02-14-24-48.bpo-40355.xTujaB.rst delete mode 100644 Misc/NEWS.d/next/Library/2020-05-02-17-17-37.bpo-40457.EXReI1.rst delete mode 100644 Misc/NEWS.d/next/Library/2020-05-04-11-20-49.bpo-40495.TyTc2O.rst delete mode 100644 Misc/NEWS.d/next/Library/2020-05-04-21-21-43.bpo-40480.mjldWa.rst delete mode 100644 Misc/NEWS.d/next/Library/2020-05-05-08-12-51.bpo-40559.112wwa.rst delete mode 100644 Misc/NEWS.d/next/Library/2020-05-05-17-12-47.bpo-40504.EX6wPn.rst delete mode 100644 Misc/NEWS.d/next/Library/2020-05-06-02-33-00.bpo-31033.aX12pw.rst delete mode 100644 Misc/NEWS.d/next/Library/2020-05-06-13-51-19.bpo-40515.TUCvYB.rst delete mode 100644 Misc/NEWS.d/next/Library/2020-05-06-15-36-47.bpo-40541.LlYghL.rst delete mode 100644 Misc/NEWS.d/next/Library/2020-05-07-06-41-20.bpo-31033.waCj3n.rst delete mode 100644 Misc/NEWS.d/next/Library/2020-05-07-20-11-51.bpo-40549.6FiRSV.rst delete mode 100644 Misc/NEWS.d/next/Library/2020-05-07-21-22-04.bpo-40397.PVWFAn.rst delete mode 100644 Misc/NEWS.d/next/Library/2020-05-08-15-48-39.bpo-40503.elZyxc.rst delete mode 100644 Misc/NEWS.d/next/Library/2020-05-09-15-38-25.bpo-40571.kOXZGC.rst delete mode 100644 Misc/NEWS.d/next/Library/2020-05-11-19-17-23.bpo-40597.4SGfgm.rst delete mode 100644 Misc/NEWS.d/next/Library/2020-05-13-10-23-29.bpo-40612.gOIreM.rst delete mode 100644 Misc/NEWS.d/next/Library/2020-05-13-15-32-13.bpo-40607.uSPFCi.rst delete mode 100644 Misc/NEWS.d/next/Library/2020-05-13-23-10-25.bpo-40257.aR4TGp.rst delete mode 100644 Misc/NEWS.d/next/Library/2020-05-15-17-38-21.bpo-40479.yamSCh.rst delete mode 100644 Misc/NEWS.d/next/Library/2020-05-15-19-53-18.bpo-37630.O5kgAw.rst delete mode 100644 Misc/NEWS.d/next/Library/2020-05-15-21-57-10.bpo-40637.lb3Bnp.rst delete mode 100644 Misc/NEWS.d/next/Library/2020-05-16-17-05-02.bpo-40645.wYSkjT.rst delete mode 100644 Misc/NEWS.d/next/Library/2020-05-16-19-34-38.bpo-40645.7ibMt-.rst delete mode 100644 Misc/NEWS.d/next/Library/2020-05-17-14-00-12.bpo-40536.FCpoRA.rst delete mode 100644 Misc/NEWS.d/next/Library/2020-05-17-21-56-38.bpo-40665.msB7u5.rst delete mode 100644 Misc/NEWS.d/next/Library/2020-05-18-12-56-45.bpo-40662.dfornR.rst delete mode 100644 Misc/NEWS.d/next/Security/2020-05-06-00-41-11.bpo-40501._61wv_.rst delete mode 100644 Misc/NEWS.d/next/Tests/2020-04-29-16-08-24.bpo-40436.gDMnYl.rst delete mode 100644 Misc/NEWS.d/next/Tests/2020-05-15-01-21-44.bpo-40055.Xp4aP9.rst delete mode 100644 Misc/NEWS.d/next/Tools-Demos/2020-04-03-08-32-31.bpo-40163.lX8K4B.rst delete mode 100644 Misc/NEWS.d/next/Tools-Demos/2020-04-29-01-32-17.bpo-40431.B_aEZ0.rst delete mode 100644 Misc/NEWS.d/next/Tools-Demos/2020-05-15-17-48-25.bpo-40479.B1gBl-.rst delete mode 100644 Misc/NEWS.d/next/Windows/2020-03-23-19-07-55.bpo-39148.W1YJEb.rst delete mode 100644 Misc/NEWS.d/next/Windows/2020-05-01-20-57-57.bpo-40458.Eb0ueI.rst delete mode 100644 Misc/NEWS.d/next/Windows/2020-05-17-00-08-13.bpo-40650.4euMtU.rst delete mode 100644 Misc/NEWS.d/next/macOS/2020-04-15-00-02-47.bpo-35569.02_1MV.rst delete mode 100644 Misc/NEWS.d/next/macOS/2020-05-18-02-43-11.bpo-34956.35IcGF.rst diff --git a/Doc/tools/extensions/pyspecific.py b/Doc/tools/extensions/pyspecific.py index bc51555fa0512b..6751f0131e7f7a 100644 --- a/Doc/tools/extensions/pyspecific.py +++ b/Doc/tools/extensions/pyspecific.py @@ -39,7 +39,7 @@ ISSUE_URI = 'https://bugs.python.org/issue%s' -SOURCE_URI = 'https://github.com/python/cpython/tree/master/%s' +SOURCE_URI = 'https://github.com/python/cpython/tree/3.9/%s' # monkey-patch reST parser to disable alphabetic and roman enumerated lists from docutils.parsers.rst.states import Body diff --git a/Include/patchlevel.h b/Include/patchlevel.h index 3cbd3db76b2d86..c028eea7b56d6a 100644 --- a/Include/patchlevel.h +++ b/Include/patchlevel.h @@ -19,11 +19,11 @@ #define PY_MAJOR_VERSION 3 #define PY_MINOR_VERSION 9 #define PY_MICRO_VERSION 0 -#define PY_RELEASE_LEVEL PY_RELEASE_LEVEL_ALPHA -#define PY_RELEASE_SERIAL 6 +#define PY_RELEASE_LEVEL PY_RELEASE_LEVEL_BETA +#define PY_RELEASE_SERIAL 1 /* Version as a string */ -#define PY_VERSION "3.9.0a6+" +#define PY_VERSION "3.9.0b1" /*--end constants--*/ /* Version as a single 4-byte hex number, e.g. 0x010502B2 == 1.5.2b2. diff --git a/Lib/pydoc_data/topics.py b/Lib/pydoc_data/topics.py index 8aca5c0cb88e38..e2df3fc58fa0d2 100644 --- a/Lib/pydoc_data/topics.py +++ b/Lib/pydoc_data/topics.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -# Autogenerated by Sphinx on Mon Apr 27 22:35:16 2020 +# Autogenerated by Sphinx on Tue May 19 00:56:40 2020 topics = {'assert': 'The "assert" statement\n' '**********************\n' '\n' diff --git a/Misc/NEWS.d/3.9.0b1.rst b/Misc/NEWS.d/3.9.0b1.rst new file mode 100644 index 00000000000000..25dd405c13039d --- /dev/null +++ b/Misc/NEWS.d/3.9.0b1.rst @@ -0,0 +1,960 @@ +.. bpo: 40501 +.. date: 2020-05-06-00-41-11 +.. nonce: _61wv_ +.. release date: 2020-05-19 +.. section: Security + +:mod:`uuid` no longer uses :mod:`ctypes` to load :file:`libuuid` or +:file:`rpcrt4.dll` at runtime. + +.. + +.. bpo: 40663 +.. date: 2020-05-17-20-38-12 +.. nonce: u2aiZf +.. section: Core and Builtins + +Correctly generate annotations where parentheses are omitted but required +(e.g: ``Type[(str, int, *other))]``. + +.. + +.. bpo: 40596 +.. date: 2020-05-11-20-53-52 +.. nonce: dwOH_X +.. section: Core and Builtins + +Fixed :meth:`str.isidentifier` for non-canonicalized strings containing +non-BMP characters on Windows. + +.. + +.. bpo: 40593 +.. date: 2020-05-11-13-50-52 +.. nonce: yuOXj3 +.. section: Core and Builtins + +Improved syntax errors for invalid characters in source code. + +.. + +.. bpo: 40585 +.. date: 2020-05-11-00-19-42 +.. nonce: yusknY +.. section: Core and Builtins + +Fixed a bug when using :func:`codeop.compile_command` that was causing +exceptions to be swallowed with the new parser. Patch by Pablo Galindo + +.. + +.. bpo: 40566 +.. date: 2020-05-09-01-39-16 +.. nonce: wlcjW_ +.. section: Core and Builtins + +Apply :pep:`573` to :mod:`abc`. + +.. + +.. bpo: 40502 +.. date: 2020-05-08-03-25-26 +.. nonce: e-VCyL +.. section: Core and Builtins + +Initialize ``n->n_col_offset``. (Patch by Joannah Nanjekye) + +.. + +.. bpo: 40527 +.. date: 2020-05-06-14-52-35 +.. nonce: gTNKuy +.. section: Core and Builtins + +Fix command line argument parsing: no longer write errors multiple times +into stderr. + +.. + +.. bpo: 1635741 +.. date: 2020-05-05-21-11-35 +.. nonce: ggwD3C +.. section: Core and Builtins + +Port :mod:`errno` to multiphase initialization (:pep:`489`). + +.. + +.. bpo: 40523 +.. date: 2020-05-05-20-36-15 +.. nonce: hKZVTB +.. section: Core and Builtins + +Add pass-throughs for :func:`hash` and :func:`reversed` to +:class:`weakref.proxy` objects. Patch by Pablo Galindo. + +.. + +.. bpo: 1635741 +.. date: 2020-05-05-03-36-27 +.. nonce: ARv1YV +.. section: Core and Builtins + +Port :mod:`syslog` to multiphase initialization (:pep:`489`). + +.. + +.. bpo: 40246 +.. date: 2020-05-03-23-28-11 +.. nonce: c1D7x8 +.. section: Core and Builtins + +Reporting a specialised error message for invalid string prefixes, which was +introduced in :issue:`40246`, is being reverted due to backwards +compatibility concerns for strings that immediately follow a reserved +keyword without whitespace between them. Constructs like `bg="#d00" if clear +else"#fca"` were failing to parse, which is not an acceptable breakage on +such short notice. + +.. + +.. bpo: 40417 +.. date: 2020-05-01-19-04-52 +.. nonce: Sti2lJ +.. section: Core and Builtins + +Fix imp module deprecation warning when PyImport_ReloadModule is called. +Patch by Robert Rouhani. + +.. + +.. bpo: 40408 +.. date: 2020-05-01-15-36-14 +.. nonce: XzQI59 +.. section: Core and Builtins + +Fixed support of nested type variables in GenericAlias (e.g. +``list[list[T]]``). + +.. + +.. bpo: 1635741 +.. date: 2020-04-30-01-44-42 +.. nonce: GKtjqr +.. section: Core and Builtins + +Port _stat module to multiphase initialization (:pep:`489`). + +.. + +.. bpo: 29587 +.. date: 2020-04-30-00-50-25 +.. nonce: oEwSq +.. section: Core and Builtins + +Enable implicit exception chaining when calling :meth:`generator.throw`. + +.. + +.. bpo: 40328 +.. date: 2020-04-19-22-23-32 +.. nonce: gWJ53f +.. section: Core and Builtins + +Add tools for generating mappings headers for CJKCodecs. + +.. + +.. bpo: 40228 +.. date: 2020-04-08-17-02-35 +.. nonce: bRaaJ- +.. section: Core and Builtins + +Setting frame.f_lineno is now robust w.r.t. changes in the +source-to-bytecode compiler + +.. + +.. bpo: 38880 +.. date: 2019-11-22-14-34-47 +.. nonce: evcCPa +.. section: Core and Builtins + +Added the ability to list interpreters associated with channel ends in the +internal subinterpreters module. + +.. + +.. bpo: 37986 +.. date: 2019-11-20-09-50-58 +.. nonce: o0lmA7 +.. section: Core and Builtins + +Improve performance of :c:func:`PyLong_FromDouble` for values that fit into +:c:type:`long`. + +.. + +.. bpo: 40662 +.. date: 2020-05-18-12-56-45 +.. nonce: dfornR +.. section: Library + +Fixed :func:`ast.get_source_segment` for ast nodes that have incomplete +location information. Patch by Irit Katriel. + +.. + +.. bpo: 40665 +.. date: 2020-05-17-21-56-38 +.. nonce: msB7u5 +.. section: Library + +Convert :mod:`bisect` to use Argument Clinic. + +.. + +.. bpo: 40536 +.. date: 2020-05-17-14-00-12 +.. nonce: FCpoRA +.. section: Library + +Added the :func:`~zoneinfo.available_timezones` function to the +:mod:`zoneinfo` module. Patch by Paul Ganssle. + +.. + +.. bpo: 40645 +.. date: 2020-05-16-19-34-38 +.. nonce: 7ibMt- +.. section: Library + +The :class:`hmac.HMAC` exposes internal implementation details. The +attributes ``digest_cons``, ``inner``, and ``outer`` are deprecated and will +be removed in the future. + +.. + +.. bpo: 40645 +.. date: 2020-05-16-17-05-02 +.. nonce: wYSkjT +.. section: Library + +The internal module ``_hashlib`` wraps and exposes OpenSSL's HMAC API. The +new code will be used in Python 3.10 after the internal implementation +details of the pure Python HMAC module are no longer part of the public API. + +.. + +.. bpo: 40637 +.. date: 2020-05-15-21-57-10 +.. nonce: lb3Bnp +.. section: Library + +Builtin hash modules can now be disabled or selectively enabled with +``configure --with-builtin-hashlib-hashes=sha3,blake1`` or +``--without-builtin-hashlib-hashes``. + +.. + +.. bpo: 37630 +.. date: 2020-05-15-19-53-18 +.. nonce: O5kgAw +.. section: Library + +The :mod:`hashlib` module can now use SHA3 hashes and SHAKE XOF from OpenSSL +when available. + +.. + +.. bpo: 40479 +.. date: 2020-05-15-17-38-21 +.. nonce: yamSCh +.. section: Library + +The :mod:`hashlib` now compiles with OpenSSL 3.0.0-alpha2. + +.. + +.. bpo: 40257 +.. date: 2020-05-13-23-10-25 +.. nonce: aR4TGp +.. section: Library + +Revert changes to :func:`inspect.getdoc`. + +.. + +.. bpo: 40607 +.. date: 2020-05-13-15-32-13 +.. nonce: uSPFCi +.. section: Library + +When cancelling a task due to timeout, :meth:`asyncio.wait_for` will now +propagate the exception if an error happens during cancellation. Patch by +Roman Skurikhin. + +.. + +.. bpo: 40612 +.. date: 2020-05-13-10-23-29 +.. nonce: gOIreM +.. section: Library + +Fix edge cases in SyntaxError formatting. If the offset is <= 0, no caret is +printed. If the offset is > line length, the caret is printed pointing just +after the last character. + +.. + +.. bpo: 40597 +.. date: 2020-05-11-19-17-23 +.. nonce: 4SGfgm +.. section: Library + +If text content lines are longer than policy.max_line_length, always use a +content-encoding to make sure they are wrapped. + +.. + +.. bpo: 40571 +.. date: 2020-05-09-15-38-25 +.. nonce: kOXZGC +.. section: Library + +Added functools.cache() as a simpler, more discoverable way to access the +unbounded cache variant of lru_cache(maxsize=None). + +.. + +.. bpo: 40503 +.. date: 2020-05-08-15-48-39 +.. nonce: elZyxc +.. section: Library + +:pep:`615`, the :mod:`zoneinfo` module. Adds support for the IANA time zone +database. + +.. + +.. bpo: 40397 +.. date: 2020-05-07-21-22-04 +.. nonce: PVWFAn +.. section: Library + +Removed attributes ``__args__`` and ``__parameters__`` from special generic +aliases like ``typing.List`` (not subscripted). + +.. + +.. bpo: 40549 +.. date: 2020-05-07-20-11-51 +.. nonce: 6FiRSV +.. section: Library + +Convert posixmodule.c ("posix" or "nt" module) to the multiphase +initialization (PEP 489). + +.. + +.. bpo: 31033 +.. date: 2020-05-07-06-41-20 +.. nonce: waCj3n +.. section: Library + +Add a ``msg`` argument to :meth:`Future.cancel` and :meth:`Task.cancel`. + +.. + +.. bpo: 40541 +.. date: 2020-05-06-15-36-47 +.. nonce: LlYghL +.. section: Library + +Added an optional *counts* parameter to random.sample(). + +.. + +.. bpo: 40515 +.. date: 2020-05-06-13-51-19 +.. nonce: TUCvYB +.. section: Library + +The :mod:`ssl` and :mod:`hashlib` modules now actively check that OpenSSL is +build with thread support. Python 3.7.0 made thread support mandatory and no +longer works safely with a no-thread builds. + +.. + +.. bpo: 31033 +.. date: 2020-05-06-02-33-00 +.. nonce: aX12pw +.. section: Library + +When a :class:`asyncio.Task` is cancelled, the exception traceback now +chains all the way back to where the task was first interrupted. + +.. + +.. bpo: 40504 +.. date: 2020-05-05-17-12-47 +.. nonce: EX6wPn +.. section: Library + +:func:`functools.lru_cache` objects can now be the targets of weakrefs. + +.. + +.. bpo: 40559 +.. date: 2020-05-05-08-12-51 +.. nonce: 112wwa +.. section: Library + +Fix possible memory leak in the C implementation of :class:`asyncio.Task`. + +.. + +.. bpo: 40480 +.. date: 2020-05-04-21-21-43 +.. nonce: mjldWa +.. section: Library + +``fnmatch.fnmatch()`` could take exponential time in the presence of +multiple ``*`` pattern characters. This was repaired by generating more +elaborate regular expressions to avoid futile backtracking. + +.. + +.. bpo: 40495 +.. date: 2020-05-04-11-20-49 +.. nonce: TyTc2O +.. section: Library + +:mod:`compileall` is now able to use hardlinks to prevent duplicates in a +case when ``.pyc`` files for different optimization levels have the same +content. + +.. + +.. bpo: 40457 +.. date: 2020-05-02-17-17-37 +.. nonce: EXReI1 +.. section: Library + +The ssl module now support OpenSSL builds without TLS 1.0 and 1.1 methods. + +.. + +.. bpo: 40355 +.. date: 2020-05-02-14-24-48 +.. nonce: xTujaB +.. section: Library + +Improve error reporting in :func:`ast.literal_eval` in the presence of +malformed :class:`ast.Dict` nodes instead of silently ignoring any +non-conforming elements. Patch by Curtis Bucher. + +.. + +.. bpo: 40465 +.. date: 2020-05-02-12-00-28 +.. nonce: qfCjOD +.. section: Library + +Deprecated the optional *random* argument to *random.shuffle()*. + +.. + +.. bpo: 40459 +.. date: 2020-05-02-04-29-31 +.. nonce: fSAYVD +.. section: Library + +:func:`platform.win32_ver` now produces correct *ptype* strings instead of +empty strings. + +.. + +.. bpo: 39435 +.. date: 2020-05-01-23-24-25 +.. nonce: mgb6ib +.. section: Library + +The first argument of :func:`pickle.loads` is now positional-only. + +.. + +.. bpo: 39305 +.. date: 2020-05-01-00-22-58 +.. nonce: Cuwu_H +.. section: Library + +Update :mod:`nntplib` to merge :class:`nntplib.NNTP` and +:class:`nntplib._NNTPBase`. Patch by Dong-hee Na. + +.. + +.. bpo: 32494 +.. date: 2020-04-30-22-25-08 +.. nonce: 1xaU5l +.. section: Library + +Update :mod:`dbm.gnu` to use gdbm_count if possible when calling +:func:`len`. Patch by Dong-hee Na. + +.. + +.. bpo: 40453 +.. date: 2020-04-30-22-04-58 +.. nonce: ggz7sl +.. section: Library + +Add ``isolated=True`` keyword-only parameter to +``_xxsubinterpreters.create()``. An isolated subinterpreter cannot spawn +threads, spawn a child process or call ``os.fork()``. + +.. + +.. bpo: 40286 +.. date: 2020-04-29-18-02-16 +.. nonce: txbQNx +.. section: Library + +Remove ``_random.Random.randbytes()``: the C implementation of +``randbytes()``. Implement the method in Python to ease subclassing: +``randbytes()`` now directly reuses ``getrandbits()``. + +.. + +.. bpo: 40394 +.. date: 2020-04-28-18-59-48 +.. nonce: Yi5uuM +.. section: Library + +Added default arguments to +:meth:`difflib.SequenceMatcher.find_longest_match()`. + +.. + +.. bpo: 39995 +.. date: 2020-04-28-18-25-27 +.. nonce: WmA3Gk +.. section: Library + +Fix a race condition in concurrent.futures._ThreadWakeup: access to +_ThreadWakeup is now protected with the shutdown lock. + +.. + +.. bpo: 30966 +.. date: 2020-04-27-20-27-39 +.. nonce: Xmtlqu +.. section: Library + +``Process.shutdown(wait=True)`` of :mod:`concurrent.futures` now closes +explicitly the result queue. + +.. + +.. bpo: 30966 +.. date: 2020-04-27-17-19-09 +.. nonce: _5lDx- +.. section: Library + +Add a new :meth:`~multiprocessing.SimpleQueue.close` method to the +:class:`~multiprocessing.SimpleQueue` class to explicitly close the queue. + +.. + +.. bpo: 39966 +.. date: 2020-04-27-14-48-43 +.. nonce: N5yXUe +.. section: Library + +Revert bpo-25597. :class:`unittest.mock.MagicMock` with wraps' set uses +default return values for magic methods. + +.. + +.. bpo: 39791 +.. date: 2020-04-27-00-51-40 +.. nonce: wv8Dxn +.. section: Library + +Added ``files()`` function to importlib.resources with support for +subdirectories in package data, matching backport in importlib_resources +1.5. + +.. + +.. bpo: 40375 +.. date: 2020-04-25-23-14-11 +.. nonce: 5GuK2A +.. section: Library + +:meth:`imaplib.IMAP4.unselect` is added. Patch by Dong-hee Na. + +.. + +.. bpo: 40389 +.. date: 2020-04-25-20-00-58 +.. nonce: FPA6f0 +.. section: Library + +``repr()`` now returns ``typing.Optional[T]`` when called for +``typing.Union`` of two types, one of which is ``NoneType``. + +.. + +.. bpo: 40291 +.. date: 2020-04-14-22-31-27 +.. nonce: _O8hXn +.. section: Library + +Add support for CAN_J1939 sockets (available on Linux 5.4+) + +.. + +.. bpo: 40273 +.. date: 2020-04-14-09-54-35 +.. nonce: IN73Ks +.. section: Library + +:class:`types.MappingProxyType` is now reversible. + +.. + +.. bpo: 39075 +.. date: 2020-04-07-23-44-06 +.. nonce: hgck3j +.. section: Library + +The repr for :class:`types.SimpleNamespace` is now insertion ordered rather +than alphabetical. + +.. + +.. bpo: 40192 +.. date: 2020-04-05-04-16-14 +.. nonce: nk8uRJ +.. section: Library + +On AIX, :func:`~time.thread_time` is now implemented with +``thread_cputime()`` which has nanosecond resolution, rather than +``clock_gettime(CLOCK_THREAD_CPUTIME_ID)`` which has a resolution of 10 ms. +Patch by Batuhan Taskaya. + +.. + +.. bpo: 40025 +.. date: 2020-03-21-05-26-38 +.. nonce: DTLtyq +.. section: Library + +Raise TypeError when _generate_next_value_ is defined after members. Patch +by Ethan Onstott. + +.. + +.. bpo: 39058 +.. date: 2019-12-15-19-17-10 +.. nonce: 7ci-vd +.. section: Library + +In the argparse module, the repr for Namespace() and other argument holders +now displayed in the order attributes were added. Formerly, it displayed in +alphabetical order even though argument order is preserved the user visible +parts of the module. + +.. + +.. bpo: 24416 +.. date: 2019-09-01-15-17-49 +.. nonce: G8Ww1U +.. section: Library + +The ``isocalendar()`` methods of :class:`datetime.date` and +:class:`datetime.datetime` now return a :term:`named tuple` instead of a +:class:`tuple`. + +.. + +.. bpo: 34790 +.. date: 2020-05-08-20-18-55 +.. nonce: t6kW_1 +.. section: Documentation + +Add version of removal for explicit passing of coros to `asyncio.wait()`'s +documentation + +.. + +.. bpo: 40561 +.. date: 2020-05-08-08-39-40 +.. nonce: ZMB_2i +.. section: Documentation + +Provide docstrings for webbrowser open functions. + +.. + +.. bpo: 40499 +.. date: 2020-05-04-14-20-02 +.. nonce: tjLSo8 +.. section: Documentation + +Mention that :func:`asyncio.wait` requires a non-empty set of awaitables. + +.. + +.. bpo: 39705 +.. date: 2020-03-14-18-37-06 +.. nonce: nQVqig +.. section: Documentation + +Tutorial example for sorted() in the Loop Techniques section is given a +better explanation. Also a new example is included to explain sorted()'s +basic behavior. + +.. + +.. bpo: 39435 +.. date: 2020-01-24-05-42-57 +.. nonce: EFcdFU +.. section: Documentation + +Fix an incorrect signature for :func:`pickle.loads` in the docs + +.. + +.. bpo: 40055 +.. date: 2020-05-15-01-21-44 +.. nonce: Xp4aP9 +.. section: Tests + +distutils.tests now saves/restores warnings filters to leave them unchanged. +Importing tests imports docutils which imports pkg_resources which adds a +warnings filter. + +.. + +.. bpo: 40436 +.. date: 2020-04-29-16-08-24 +.. nonce: gDMnYl +.. section: Tests + +test_gdb and test.pythoninfo now check gdb command exit code. + +.. + +.. bpo: 40653 +.. date: 2020-05-17-03-33-00 +.. nonce: WI8UGn +.. section: Build + +Move _dirnameW out of HAVE_SYMLINK to fix a potential compiling issue. + +.. + +.. bpo: 40514 +.. date: 2020-05-05-15-39-11 +.. nonce: bZZmuS +.. section: Build + +Add ``--with-experimental-isolated-subinterpreters`` build option to +``configure``: better isolate subinterpreters, experimental build mode. + +.. + +.. bpo: 40650 +.. date: 2020-05-17-00-08-13 +.. nonce: 4euMtU +.. section: Windows + +Include winsock2.h in pytime.c for timeval. + +.. + +.. bpo: 40458 +.. date: 2020-05-01-20-57-57 +.. nonce: Eb0ueI +.. section: Windows + +Increase reserved stack space to prevent overflow crash on Windows. + +.. + +.. bpo: 39148 +.. date: 2020-03-23-19-07-55 +.. nonce: W1YJEb +.. section: Windows + +Add IPv6 support to :mod:`asyncio` datagram endpoints in ProactorEventLoop. +Change the raised exception for unknown address families to ValueError as +it's not coming from Windows API. + +.. + +.. bpo: 34956 +.. date: 2020-05-18-02-43-11 +.. nonce: 35IcGF +.. section: macOS + +_tkinter now builds and links with non-system Tcl and Tk frameworks if they +are installed in /Library/Frameworks as had been the case on older releases +of macOS. If a macOS SDK is explicitly configured, by using ./configure +--enable-universalsdk= or -isysroot, only a Library/Frameworks directory in +the SDK itself is searched. The default behavior can still be overridden +with configure --with-tcltk-includes and --with-tcltk-libs. + +.. + +.. bpo: 35569 +.. date: 2020-04-15-00-02-47 +.. nonce: 02_1MV +.. section: macOS + +Expose RFC 3542 IPv6 socket options. + +.. + +.. bpo: 40479 +.. date: 2020-05-15-17-48-25 +.. nonce: B1gBl- +.. section: Tools/Demos + +Update multissltest helper to test with latest OpenSSL 1.0.2, 1.1.0, 1.1.1, +and 3.0.0-alpha. + +.. + +.. bpo: 40431 +.. date: 2020-04-29-01-32-17 +.. nonce: B_aEZ0 +.. section: Tools/Demos + +Fix a syntax typo in ``turtledemo`` that now raises a ``SyntaxError``. + +.. + +.. bpo: 40163 +.. date: 2020-04-03-08-32-31 +.. nonce: lX8K4B +.. section: Tools/Demos + +Fix multissltest tool. OpenSSL has changed download URL for old releases. +The multissltest tool now tries to download from current and old download +URLs. + +.. + +.. bpo: 39465 +.. date: 2020-05-14-00-36-19 +.. nonce: 3a5g-X +.. section: C API + +Remove the ``_PyUnicode_ClearStaticStrings()`` function from the C API. + +.. + +.. bpo: 38787 +.. date: 2020-05-10-16-39-08 +.. nonce: XzQ59O +.. section: C API + +Add PyCFunction_CheckExact() macro for exact type checks now that we allow +subtypes of PyCFunction, as well as PyCMethod_CheckExact() and +PyCMethod_Check() for the new PyCMethod subtype. + +.. + +.. bpo: 40545 +.. date: 2020-05-07-11-41-13 +.. nonce: 51DzF1 +.. section: C API + +Declare ``_PyErr_GetTopmostException()`` with ``PyAPI_FUNC()`` to properly +export the function in the C API. The function remains private (``_Py``) +prefix. + +.. + +.. bpo: 40412 +.. date: 2020-05-01-17-28-04 +.. nonce: dE0D8N +.. section: C API + +Nullify inittab_copy during finalization, preventing future interpreter +initializations in an embedded situation from crashing. Patch by Gregory +Szorc. + +.. + +.. bpo: 40429 +.. date: 2020-04-29-01-39-41 +.. nonce: VQfvta +.. section: C API + +The :c:func:`PyThreadState_GetFrame` function now returns a strong reference +to the frame. + +.. + +.. bpo: 40428 +.. date: 2020-04-28-23-17-27 +.. nonce: rmtpru +.. section: C API + +Remove the following functions from the C API. Call :c:func:`PyGC_Collect` +explicitly to free all free lists. + +* ``PyAsyncGen_ClearFreeLists()`` +* ``PyContext_ClearFreeList()`` +* ``PyDict_ClearFreeList()`` +* ``PyFloat_ClearFreeList()`` +* ``PyFrame_ClearFreeList()`` +* ``PyList_ClearFreeList()`` +* ``PySet_ClearFreeList()`` +* ``PyTuple_ClearFreeList()`` + +.. + +.. bpo: 40421 +.. date: 2020-04-28-19-29-36 +.. nonce: 3uIIaB +.. section: C API + +New :c:func:`PyFrame_GetBack` function: get the frame next outer frame. + +.. + +.. bpo: 40421 +.. date: 2020-04-28-15-47-58 +.. nonce: ZIzOV0 +.. section: C API + +New :c:func:`PyFrame_GetCode` function: return a borrowed reference to the +frame code. + +.. + +.. bpo: 40217 +.. date: 2020-04-27-14-00-38 +.. nonce: sgn6c8 +.. section: C API + +Ensure that instances of types created with +:c:func:`PyType_FromSpecWithBases` will visit its class object when +traversing references in the garbage collector (implemented as an extension +of the provided :c:member:`~PyTypeObject.tp_traverse`). Patch by Pablo +Galindo. + +.. + +.. bpo: 38787 +.. date: 2020-01-22-12-38-59 +.. nonce: HUH6hd +.. section: C API + +Module C state is now accessible from C-defined heap type methods +(:pep:`573`). Patch by Marcel Plch and Petr Viktorin. diff --git a/Misc/NEWS.d/next/Build/2020-05-05-15-39-11.bpo-40514.bZZmuS.rst b/Misc/NEWS.d/next/Build/2020-05-05-15-39-11.bpo-40514.bZZmuS.rst deleted file mode 100644 index ab9062c28f4bb9..00000000000000 --- a/Misc/NEWS.d/next/Build/2020-05-05-15-39-11.bpo-40514.bZZmuS.rst +++ /dev/null @@ -1,2 +0,0 @@ -Add ``--with-experimental-isolated-subinterpreters`` build option to -``configure``: better isolate subinterpreters, experimental build mode. diff --git a/Misc/NEWS.d/next/Build/2020-05-17-03-33-00.bpo-40653.WI8UGn.rst b/Misc/NEWS.d/next/Build/2020-05-17-03-33-00.bpo-40653.WI8UGn.rst deleted file mode 100644 index 1e6c5cb32b722a..00000000000000 --- a/Misc/NEWS.d/next/Build/2020-05-17-03-33-00.bpo-40653.WI8UGn.rst +++ /dev/null @@ -1 +0,0 @@ -Move _dirnameW out of HAVE_SYMLINK to fix a potential compiling issue. \ No newline at end of file diff --git a/Misc/NEWS.d/next/C API/2020-01-22-12-38-59.bpo-38787.HUH6hd.rst b/Misc/NEWS.d/next/C API/2020-01-22-12-38-59.bpo-38787.HUH6hd.rst deleted file mode 100644 index 785ea323c316de..00000000000000 --- a/Misc/NEWS.d/next/C API/2020-01-22-12-38-59.bpo-38787.HUH6hd.rst +++ /dev/null @@ -1,2 +0,0 @@ -Module C state is now accessible from C-defined heap type methods (:pep:`573`). -Patch by Marcel Plch and Petr Viktorin. diff --git a/Misc/NEWS.d/next/C API/2020-04-27-14-00-38.bpo-40217.sgn6c8.rst b/Misc/NEWS.d/next/C API/2020-04-27-14-00-38.bpo-40217.sgn6c8.rst deleted file mode 100644 index 72df4a7b56d40c..00000000000000 --- a/Misc/NEWS.d/next/C API/2020-04-27-14-00-38.bpo-40217.sgn6c8.rst +++ /dev/null @@ -1,5 +0,0 @@ -Ensure that instances of types created with -:c:func:`PyType_FromSpecWithBases` will visit its class object when -traversing references in the garbage collector (implemented as an extension -of the provided :c:member:`~PyTypeObject.tp_traverse`). Patch by Pablo -Galindo. diff --git a/Misc/NEWS.d/next/C API/2020-04-28-15-47-58.bpo-40421.ZIzOV0.rst b/Misc/NEWS.d/next/C API/2020-04-28-15-47-58.bpo-40421.ZIzOV0.rst deleted file mode 100644 index 11cf87872d513b..00000000000000 --- a/Misc/NEWS.d/next/C API/2020-04-28-15-47-58.bpo-40421.ZIzOV0.rst +++ /dev/null @@ -1,2 +0,0 @@ -New :c:func:`PyFrame_GetCode` function: return a borrowed reference to the -frame code. diff --git a/Misc/NEWS.d/next/C API/2020-04-28-19-29-36.bpo-40421.3uIIaB.rst b/Misc/NEWS.d/next/C API/2020-04-28-19-29-36.bpo-40421.3uIIaB.rst deleted file mode 100644 index aadfb339b1711e..00000000000000 --- a/Misc/NEWS.d/next/C API/2020-04-28-19-29-36.bpo-40421.3uIIaB.rst +++ /dev/null @@ -1 +0,0 @@ -New :c:func:`PyFrame_GetBack` function: get the frame next outer frame. diff --git a/Misc/NEWS.d/next/C API/2020-04-28-23-17-27.bpo-40428.rmtpru.rst b/Misc/NEWS.d/next/C API/2020-04-28-23-17-27.bpo-40428.rmtpru.rst deleted file mode 100644 index f8710efb6c3293..00000000000000 --- a/Misc/NEWS.d/next/C API/2020-04-28-23-17-27.bpo-40428.rmtpru.rst +++ /dev/null @@ -1,11 +0,0 @@ -Remove the following functions from the C API. Call :c:func:`PyGC_Collect` -explicitly to free all free lists. - -* ``PyAsyncGen_ClearFreeLists()`` -* ``PyContext_ClearFreeList()`` -* ``PyDict_ClearFreeList()`` -* ``PyFloat_ClearFreeList()`` -* ``PyFrame_ClearFreeList()`` -* ``PyList_ClearFreeList()`` -* ``PySet_ClearFreeList()`` -* ``PyTuple_ClearFreeList()`` diff --git a/Misc/NEWS.d/next/C API/2020-04-29-01-39-41.bpo-40429.VQfvta.rst b/Misc/NEWS.d/next/C API/2020-04-29-01-39-41.bpo-40429.VQfvta.rst deleted file mode 100644 index e02aaf9003225b..00000000000000 --- a/Misc/NEWS.d/next/C API/2020-04-29-01-39-41.bpo-40429.VQfvta.rst +++ /dev/null @@ -1,2 +0,0 @@ -The :c:func:`PyThreadState_GetFrame` function now returns a strong reference -to the frame. diff --git a/Misc/NEWS.d/next/C API/2020-05-01-17-28-04.bpo-40412.dE0D8N.rst b/Misc/NEWS.d/next/C API/2020-05-01-17-28-04.bpo-40412.dE0D8N.rst deleted file mode 100644 index 92bfcddf115a68..00000000000000 --- a/Misc/NEWS.d/next/C API/2020-05-01-17-28-04.bpo-40412.dE0D8N.rst +++ /dev/null @@ -1 +0,0 @@ -Nullify inittab_copy during finalization, preventing future interpreter initializations in an embedded situation from crashing. Patch by Gregory Szorc. diff --git a/Misc/NEWS.d/next/C API/2020-05-07-11-41-13.bpo-40545.51DzF1.rst b/Misc/NEWS.d/next/C API/2020-05-07-11-41-13.bpo-40545.51DzF1.rst deleted file mode 100644 index d7f256a2a6b527..00000000000000 --- a/Misc/NEWS.d/next/C API/2020-05-07-11-41-13.bpo-40545.51DzF1.rst +++ /dev/null @@ -1,3 +0,0 @@ -Declare ``_PyErr_GetTopmostException()`` with ``PyAPI_FUNC()`` to properly -export the function in the C API. The function remains private (``_Py``) -prefix. diff --git a/Misc/NEWS.d/next/C API/2020-05-10-16-39-08.bpo-38787.XzQ59O.rst b/Misc/NEWS.d/next/C API/2020-05-10-16-39-08.bpo-38787.XzQ59O.rst deleted file mode 100644 index f80be666c1c200..00000000000000 --- a/Misc/NEWS.d/next/C API/2020-05-10-16-39-08.bpo-38787.XzQ59O.rst +++ /dev/null @@ -1,2 +0,0 @@ -Add PyCFunction_CheckExact() macro for exact type checks now that we allow subtypes of PyCFunction, -as well as PyCMethod_CheckExact() and PyCMethod_Check() for the new PyCMethod subtype. diff --git a/Misc/NEWS.d/next/C API/2020-05-14-00-36-19.bpo-39465.3a5g-X.rst b/Misc/NEWS.d/next/C API/2020-05-14-00-36-19.bpo-39465.3a5g-X.rst deleted file mode 100644 index a08c3da5660455..00000000000000 --- a/Misc/NEWS.d/next/C API/2020-05-14-00-36-19.bpo-39465.3a5g-X.rst +++ /dev/null @@ -1 +0,0 @@ -Remove the ``_PyUnicode_ClearStaticStrings()`` function from the C API. diff --git a/Misc/NEWS.d/next/Core and Builtins/2019-11-20-09-50-58.bpo-37986.o0lmA7.rst b/Misc/NEWS.d/next/Core and Builtins/2019-11-20-09-50-58.bpo-37986.o0lmA7.rst deleted file mode 100644 index 62446e35ae01ba..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2019-11-20-09-50-58.bpo-37986.o0lmA7.rst +++ /dev/null @@ -1,2 +0,0 @@ -Improve performance of :c:func:`PyLong_FromDouble` for values that fit into -:c:type:`long`. diff --git a/Misc/NEWS.d/next/Core and Builtins/2019-11-22-14-34-47.bpo-38880.evcCPa.rst b/Misc/NEWS.d/next/Core and Builtins/2019-11-22-14-34-47.bpo-38880.evcCPa.rst deleted file mode 100644 index 07a7f5ec22aa10..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2019-11-22-14-34-47.bpo-38880.evcCPa.rst +++ /dev/null @@ -1 +0,0 @@ -Added the ability to list interpreters associated with channel ends in the internal subinterpreters module. diff --git a/Misc/NEWS.d/next/Core and Builtins/2020-04-08-17-02-35.bpo-40228.bRaaJ-.rst b/Misc/NEWS.d/next/Core and Builtins/2020-04-08-17-02-35.bpo-40228.bRaaJ-.rst deleted file mode 100644 index 2a08cfd253925f..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2020-04-08-17-02-35.bpo-40228.bRaaJ-.rst +++ /dev/null @@ -1 +0,0 @@ -Setting frame.f_lineno is now robust w.r.t. changes in the source-to-bytecode compiler diff --git a/Misc/NEWS.d/next/Core and Builtins/2020-04-19-22-23-32.bpo-40328.gWJ53f.rst b/Misc/NEWS.d/next/Core and Builtins/2020-04-19-22-23-32.bpo-40328.gWJ53f.rst deleted file mode 100644 index ede446e0d500d7..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2020-04-19-22-23-32.bpo-40328.gWJ53f.rst +++ /dev/null @@ -1 +0,0 @@ -Add tools for generating mappings headers for CJKCodecs. diff --git a/Misc/NEWS.d/next/Core and Builtins/2020-04-30-00-50-25.bpo-29587.oEwSq.rst b/Misc/NEWS.d/next/Core and Builtins/2020-04-30-00-50-25.bpo-29587.oEwSq.rst deleted file mode 100644 index f44aa360cc2ef3..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2020-04-30-00-50-25.bpo-29587.oEwSq.rst +++ /dev/null @@ -1 +0,0 @@ -Enable implicit exception chaining when calling :meth:`generator.throw`. diff --git a/Misc/NEWS.d/next/Core and Builtins/2020-04-30-01-44-42.bpo-1635741.GKtjqr.rst b/Misc/NEWS.d/next/Core and Builtins/2020-04-30-01-44-42.bpo-1635741.GKtjqr.rst deleted file mode 100644 index 7b3c7511e139ec..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2020-04-30-01-44-42.bpo-1635741.GKtjqr.rst +++ /dev/null @@ -1 +0,0 @@ -Port _stat module to multiphase initialization (:pep:`489`). diff --git a/Misc/NEWS.d/next/Core and Builtins/2020-05-01-15-36-14.bpo-40408.XzQI59.rst b/Misc/NEWS.d/next/Core and Builtins/2020-05-01-15-36-14.bpo-40408.XzQI59.rst deleted file mode 100644 index e6822f9c24044a..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2020-05-01-15-36-14.bpo-40408.XzQI59.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fixed support of nested type variables in GenericAlias (e.g. -``list[list[T]]``). diff --git a/Misc/NEWS.d/next/Core and Builtins/2020-05-01-19-04-52.bpo-40417.Sti2lJ.rst b/Misc/NEWS.d/next/Core and Builtins/2020-05-01-19-04-52.bpo-40417.Sti2lJ.rst deleted file mode 100644 index 932e853a8933d1..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2020-05-01-19-04-52.bpo-40417.Sti2lJ.rst +++ /dev/null @@ -1 +0,0 @@ -Fix imp module deprecation warning when PyImport_ReloadModule is called. Patch by Robert Rouhani. diff --git a/Misc/NEWS.d/next/Core and Builtins/2020-05-03-23-28-11.bpo-40246.c1D7x8.rst b/Misc/NEWS.d/next/Core and Builtins/2020-05-03-23-28-11.bpo-40246.c1D7x8.rst deleted file mode 100644 index 62cd632ffd0707..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2020-05-03-23-28-11.bpo-40246.c1D7x8.rst +++ /dev/null @@ -1 +0,0 @@ -Reporting a specialised error message for invalid string prefixes, which was introduced in :issue:`40246`, is being reverted due to backwards compatibility concerns for strings that immediately follow a reserved keyword without whitespace between them. Constructs like `bg="#d00" if clear else"#fca"` were failing to parse, which is not an acceptable breakage on such short notice. diff --git a/Misc/NEWS.d/next/Core and Builtins/2020-05-05-03-36-27.bpo-1635741.ARv1YV.rst b/Misc/NEWS.d/next/Core and Builtins/2020-05-05-03-36-27.bpo-1635741.ARv1YV.rst deleted file mode 100644 index f484992c487bdc..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2020-05-05-03-36-27.bpo-1635741.ARv1YV.rst +++ /dev/null @@ -1 +0,0 @@ -Port :mod:`syslog` to multiphase initialization (:pep:`489`). diff --git a/Misc/NEWS.d/next/Core and Builtins/2020-05-05-20-36-15.bpo-40523.hKZVTB.rst b/Misc/NEWS.d/next/Core and Builtins/2020-05-05-20-36-15.bpo-40523.hKZVTB.rst deleted file mode 100644 index 14f05be59a1edd..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2020-05-05-20-36-15.bpo-40523.hKZVTB.rst +++ /dev/null @@ -1,2 +0,0 @@ -Add pass-throughs for :func:`hash` and :func:`reversed` to -:class:`weakref.proxy` objects. Patch by Pablo Galindo. diff --git a/Misc/NEWS.d/next/Core and Builtins/2020-05-05-21-11-35.bpo-1635741.ggwD3C.rst b/Misc/NEWS.d/next/Core and Builtins/2020-05-05-21-11-35.bpo-1635741.ggwD3C.rst deleted file mode 100644 index 197eae97c3d1ab..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2020-05-05-21-11-35.bpo-1635741.ggwD3C.rst +++ /dev/null @@ -1 +0,0 @@ -Port :mod:`errno` to multiphase initialization (:pep:`489`). diff --git a/Misc/NEWS.d/next/Core and Builtins/2020-05-06-14-52-35.bpo-40527.gTNKuy.rst b/Misc/NEWS.d/next/Core and Builtins/2020-05-06-14-52-35.bpo-40527.gTNKuy.rst deleted file mode 100644 index 19b8888230c659..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2020-05-06-14-52-35.bpo-40527.gTNKuy.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix command line argument parsing: no longer write errors multiple times -into stderr. diff --git a/Misc/NEWS.d/next/Core and Builtins/2020-05-08-03-25-26.bpo-40502.e-VCyL.rst b/Misc/NEWS.d/next/Core and Builtins/2020-05-08-03-25-26.bpo-40502.e-VCyL.rst deleted file mode 100644 index b0ea60234634c5..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2020-05-08-03-25-26.bpo-40502.e-VCyL.rst +++ /dev/null @@ -1,2 +0,0 @@ -Initialize ``n->n_col_offset``. -(Patch by Joannah Nanjekye) \ No newline at end of file diff --git a/Misc/NEWS.d/next/Core and Builtins/2020-05-09-01-39-16.bpo-40566.wlcjW_.rst b/Misc/NEWS.d/next/Core and Builtins/2020-05-09-01-39-16.bpo-40566.wlcjW_.rst deleted file mode 100644 index 92a5e3ce632172..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2020-05-09-01-39-16.bpo-40566.wlcjW_.rst +++ /dev/null @@ -1 +0,0 @@ -Apply :pep:`573` to :mod:`abc`. diff --git a/Misc/NEWS.d/next/Core and Builtins/2020-05-11-00-19-42.bpo-40585.yusknY.rst b/Misc/NEWS.d/next/Core and Builtins/2020-05-11-00-19-42.bpo-40585.yusknY.rst deleted file mode 100644 index 7a9258ef0a938b..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2020-05-11-00-19-42.bpo-40585.yusknY.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fixed a bug when using :func:`codeop.compile_command` that was causing -exceptions to be swallowed with the new parser. Patch by Pablo Galindo diff --git a/Misc/NEWS.d/next/Core and Builtins/2020-05-11-13-50-52.bpo-40593.yuOXj3.rst b/Misc/NEWS.d/next/Core and Builtins/2020-05-11-13-50-52.bpo-40593.yuOXj3.rst deleted file mode 100644 index 5587d4f49ccf97..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2020-05-11-13-50-52.bpo-40593.yuOXj3.rst +++ /dev/null @@ -1 +0,0 @@ -Improved syntax errors for invalid characters in source code. diff --git a/Misc/NEWS.d/next/Core and Builtins/2020-05-11-20-53-52.bpo-40596.dwOH_X.rst b/Misc/NEWS.d/next/Core and Builtins/2020-05-11-20-53-52.bpo-40596.dwOH_X.rst deleted file mode 100644 index 1252db4dc9848d..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2020-05-11-20-53-52.bpo-40596.dwOH_X.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fixed :meth:`str.isidentifier` for non-canonicalized strings containing -non-BMP characters on Windows. diff --git a/Misc/NEWS.d/next/Core and Builtins/2020-05-17-20-38-12.bpo-40663.u2aiZf.rst b/Misc/NEWS.d/next/Core and Builtins/2020-05-17-20-38-12.bpo-40663.u2aiZf.rst deleted file mode 100644 index 5041abc7e3eaa5..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2020-05-17-20-38-12.bpo-40663.u2aiZf.rst +++ /dev/null @@ -1,2 +0,0 @@ -Correctly generate annotations where parentheses are omitted but required -(e.g: ``Type[(str, int, *other))]``. diff --git a/Misc/NEWS.d/next/Documentation/2020-01-24-05-42-57.bpo-39435.EFcdFU.rst b/Misc/NEWS.d/next/Documentation/2020-01-24-05-42-57.bpo-39435.EFcdFU.rst deleted file mode 100644 index 40294c10df00af..00000000000000 --- a/Misc/NEWS.d/next/Documentation/2020-01-24-05-42-57.bpo-39435.EFcdFU.rst +++ /dev/null @@ -1 +0,0 @@ -Fix an incorrect signature for :func:`pickle.loads` in the docs \ No newline at end of file diff --git a/Misc/NEWS.d/next/Documentation/2020-03-14-18-37-06.bpo-39705.nQVqig.rst b/Misc/NEWS.d/next/Documentation/2020-03-14-18-37-06.bpo-39705.nQVqig.rst deleted file mode 100644 index 3454b928e70b47..00000000000000 --- a/Misc/NEWS.d/next/Documentation/2020-03-14-18-37-06.bpo-39705.nQVqig.rst +++ /dev/null @@ -1,2 +0,0 @@ -Tutorial example for sorted() in the Loop Techniques section is given a better explanation. -Also a new example is included to explain sorted()'s basic behavior. \ No newline at end of file diff --git a/Misc/NEWS.d/next/Documentation/2020-05-04-14-20-02.bpo-40499.tjLSo8.rst b/Misc/NEWS.d/next/Documentation/2020-05-04-14-20-02.bpo-40499.tjLSo8.rst deleted file mode 100644 index 2b7eccbf0efaf7..00000000000000 --- a/Misc/NEWS.d/next/Documentation/2020-05-04-14-20-02.bpo-40499.tjLSo8.rst +++ /dev/null @@ -1 +0,0 @@ -Mention that :func:`asyncio.wait` requires a non-empty set of awaitables. diff --git a/Misc/NEWS.d/next/Documentation/2020-05-08-08-39-40.bpo-40561.ZMB_2i.rst b/Misc/NEWS.d/next/Documentation/2020-05-08-08-39-40.bpo-40561.ZMB_2i.rst deleted file mode 100644 index bda24719b12cb3..00000000000000 --- a/Misc/NEWS.d/next/Documentation/2020-05-08-08-39-40.bpo-40561.ZMB_2i.rst +++ /dev/null @@ -1 +0,0 @@ -Provide docstrings for webbrowser open functions. diff --git a/Misc/NEWS.d/next/Documentation/2020-05-08-20-18-55.bpo-34790.t6kW_1.rst b/Misc/NEWS.d/next/Documentation/2020-05-08-20-18-55.bpo-34790.t6kW_1.rst deleted file mode 100644 index 4f349adff33460..00000000000000 --- a/Misc/NEWS.d/next/Documentation/2020-05-08-20-18-55.bpo-34790.t6kW_1.rst +++ /dev/null @@ -1 +0,0 @@ -Add version of removal for explicit passing of coros to `asyncio.wait()`'s documentation \ No newline at end of file diff --git a/Misc/NEWS.d/next/Library/2019-09-01-15-17-49.bpo-24416.G8Ww1U.rst b/Misc/NEWS.d/next/Library/2019-09-01-15-17-49.bpo-24416.G8Ww1U.rst deleted file mode 100644 index ee9af990f079db..00000000000000 --- a/Misc/NEWS.d/next/Library/2019-09-01-15-17-49.bpo-24416.G8Ww1U.rst +++ /dev/null @@ -1,3 +0,0 @@ -The ``isocalendar()`` methods of :class:`datetime.date` and -:class:`datetime.datetime` now return a :term:`named tuple` -instead of a :class:`tuple`. diff --git a/Misc/NEWS.d/next/Library/2019-12-15-19-17-10.bpo-39058.7ci-vd.rst b/Misc/NEWS.d/next/Library/2019-12-15-19-17-10.bpo-39058.7ci-vd.rst deleted file mode 100644 index fff13223bc4cde..00000000000000 --- a/Misc/NEWS.d/next/Library/2019-12-15-19-17-10.bpo-39058.7ci-vd.rst +++ /dev/null @@ -1,4 +0,0 @@ -In the argparse module, the repr for Namespace() and other argument holders -now displayed in the order attributes were added. Formerly, it displayed in -alphabetical order even though argument order is preserved the user visible -parts of the module. diff --git a/Misc/NEWS.d/next/Library/2020-03-21-05-26-38.bpo-40025.DTLtyq.rst b/Misc/NEWS.d/next/Library/2020-03-21-05-26-38.bpo-40025.DTLtyq.rst deleted file mode 100644 index 7b699de4e0726f..00000000000000 --- a/Misc/NEWS.d/next/Library/2020-03-21-05-26-38.bpo-40025.DTLtyq.rst +++ /dev/null @@ -1 +0,0 @@ -Raise TypeError when _generate_next_value_ is defined after members. Patch by Ethan Onstott. \ No newline at end of file diff --git a/Misc/NEWS.d/next/Library/2020-04-05-04-16-14.bpo-40192.nk8uRJ.rst b/Misc/NEWS.d/next/Library/2020-04-05-04-16-14.bpo-40192.nk8uRJ.rst deleted file mode 100644 index e1e7fcefe3f948..00000000000000 --- a/Misc/NEWS.d/next/Library/2020-04-05-04-16-14.bpo-40192.nk8uRJ.rst +++ /dev/null @@ -1,4 +0,0 @@ -On AIX, :func:`~time.thread_time` is now implemented with ``thread_cputime()`` -which has nanosecond resolution, rather than -``clock_gettime(CLOCK_THREAD_CPUTIME_ID)`` which has a resolution of 10 ms. -Patch by Batuhan Taskaya. diff --git a/Misc/NEWS.d/next/Library/2020-04-07-23-44-06.bpo-39075.hgck3j.rst b/Misc/NEWS.d/next/Library/2020-04-07-23-44-06.bpo-39075.hgck3j.rst deleted file mode 100644 index c447a191f07f3b..00000000000000 --- a/Misc/NEWS.d/next/Library/2020-04-07-23-44-06.bpo-39075.hgck3j.rst +++ /dev/null @@ -1,2 +0,0 @@ -The repr for :class:`types.SimpleNamespace` is now insertion ordered rather -than alphabetical. diff --git a/Misc/NEWS.d/next/Library/2020-04-14-09-54-35.bpo-40273.IN73Ks.rst b/Misc/NEWS.d/next/Library/2020-04-14-09-54-35.bpo-40273.IN73Ks.rst deleted file mode 100644 index 50f547f56c5208..00000000000000 --- a/Misc/NEWS.d/next/Library/2020-04-14-09-54-35.bpo-40273.IN73Ks.rst +++ /dev/null @@ -1 +0,0 @@ -:class:`types.MappingProxyType` is now reversible. diff --git a/Misc/NEWS.d/next/Library/2020-04-14-22-31-27.bpo-40291._O8hXn.rst b/Misc/NEWS.d/next/Library/2020-04-14-22-31-27.bpo-40291._O8hXn.rst deleted file mode 100644 index a560ef12302bbc..00000000000000 --- a/Misc/NEWS.d/next/Library/2020-04-14-22-31-27.bpo-40291._O8hXn.rst +++ /dev/null @@ -1 +0,0 @@ -Add support for CAN_J1939 sockets (available on Linux 5.4+) diff --git a/Misc/NEWS.d/next/Library/2020-04-25-20-00-58.bpo-40389.FPA6f0.rst b/Misc/NEWS.d/next/Library/2020-04-25-20-00-58.bpo-40389.FPA6f0.rst deleted file mode 100644 index e7a60a8d5f6f48..00000000000000 --- a/Misc/NEWS.d/next/Library/2020-04-25-20-00-58.bpo-40389.FPA6f0.rst +++ /dev/null @@ -1 +0,0 @@ -``repr()`` now returns ``typing.Optional[T]`` when called for ``typing.Union`` of two types, one of which is ``NoneType``. \ No newline at end of file diff --git a/Misc/NEWS.d/next/Library/2020-04-25-23-14-11.bpo-40375.5GuK2A.rst b/Misc/NEWS.d/next/Library/2020-04-25-23-14-11.bpo-40375.5GuK2A.rst deleted file mode 100644 index eb58e00bcf7d4d..00000000000000 --- a/Misc/NEWS.d/next/Library/2020-04-25-23-14-11.bpo-40375.5GuK2A.rst +++ /dev/null @@ -1 +0,0 @@ -:meth:`imaplib.IMAP4.unselect` is added. Patch by Dong-hee Na. diff --git a/Misc/NEWS.d/next/Library/2020-04-27-00-51-40.bpo-39791.wv8Dxn.rst b/Misc/NEWS.d/next/Library/2020-04-27-00-51-40.bpo-39791.wv8Dxn.rst deleted file mode 100644 index 237bcf7f99b0f0..00000000000000 --- a/Misc/NEWS.d/next/Library/2020-04-27-00-51-40.bpo-39791.wv8Dxn.rst +++ /dev/null @@ -1 +0,0 @@ -Added ``files()`` function to importlib.resources with support for subdirectories in package data, matching backport in importlib_resources 1.5. \ No newline at end of file diff --git a/Misc/NEWS.d/next/Library/2020-04-27-14-48-43.bpo-39966.N5yXUe.rst b/Misc/NEWS.d/next/Library/2020-04-27-14-48-43.bpo-39966.N5yXUe.rst deleted file mode 100644 index 614b452056e53f..00000000000000 --- a/Misc/NEWS.d/next/Library/2020-04-27-14-48-43.bpo-39966.N5yXUe.rst +++ /dev/null @@ -1,2 +0,0 @@ -Revert bpo-25597. :class:`unittest.mock.MagicMock` with wraps' set uses -default return values for magic methods. diff --git a/Misc/NEWS.d/next/Library/2020-04-27-17-19-09.bpo-30966._5lDx-.rst b/Misc/NEWS.d/next/Library/2020-04-27-17-19-09.bpo-30966._5lDx-.rst deleted file mode 100644 index 14e9e11538763e..00000000000000 --- a/Misc/NEWS.d/next/Library/2020-04-27-17-19-09.bpo-30966._5lDx-.rst +++ /dev/null @@ -1,2 +0,0 @@ -Add a new :meth:`~multiprocessing.SimpleQueue.close` method to the -:class:`~multiprocessing.SimpleQueue` class to explicitly close the queue. diff --git a/Misc/NEWS.d/next/Library/2020-04-27-20-27-39.bpo-30966.Xmtlqu.rst b/Misc/NEWS.d/next/Library/2020-04-27-20-27-39.bpo-30966.Xmtlqu.rst deleted file mode 100644 index 85b7934ba661e3..00000000000000 --- a/Misc/NEWS.d/next/Library/2020-04-27-20-27-39.bpo-30966.Xmtlqu.rst +++ /dev/null @@ -1,2 +0,0 @@ -``Process.shutdown(wait=True)`` of :mod:`concurrent.futures` now closes -explicitly the result queue. diff --git a/Misc/NEWS.d/next/Library/2020-04-28-18-25-27.bpo-39995.WmA3Gk.rst b/Misc/NEWS.d/next/Library/2020-04-28-18-25-27.bpo-39995.WmA3Gk.rst deleted file mode 100644 index 24aff657363372..00000000000000 --- a/Misc/NEWS.d/next/Library/2020-04-28-18-25-27.bpo-39995.WmA3Gk.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix a race condition in concurrent.futures._ThreadWakeup: access to -_ThreadWakeup is now protected with the shutdown lock. diff --git a/Misc/NEWS.d/next/Library/2020-04-28-18-59-48.bpo-40394.Yi5uuM.rst b/Misc/NEWS.d/next/Library/2020-04-28-18-59-48.bpo-40394.Yi5uuM.rst deleted file mode 100644 index ef2e239b1e6781..00000000000000 --- a/Misc/NEWS.d/next/Library/2020-04-28-18-59-48.bpo-40394.Yi5uuM.rst +++ /dev/null @@ -1 +0,0 @@ -Added default arguments to :meth:`difflib.SequenceMatcher.find_longest_match()`. \ No newline at end of file diff --git a/Misc/NEWS.d/next/Library/2020-04-29-18-02-16.bpo-40286.txbQNx.rst b/Misc/NEWS.d/next/Library/2020-04-29-18-02-16.bpo-40286.txbQNx.rst deleted file mode 100644 index ab9bfa65e07c2d..00000000000000 --- a/Misc/NEWS.d/next/Library/2020-04-29-18-02-16.bpo-40286.txbQNx.rst +++ /dev/null @@ -1,3 +0,0 @@ -Remove ``_random.Random.randbytes()``: the C implementation of -``randbytes()``. Implement the method in Python to ease subclassing: -``randbytes()`` now directly reuses ``getrandbits()``. diff --git a/Misc/NEWS.d/next/Library/2020-04-30-22-04-58.bpo-40453.ggz7sl.rst b/Misc/NEWS.d/next/Library/2020-04-30-22-04-58.bpo-40453.ggz7sl.rst deleted file mode 100644 index f20c666d3e27f9..00000000000000 --- a/Misc/NEWS.d/next/Library/2020-04-30-22-04-58.bpo-40453.ggz7sl.rst +++ /dev/null @@ -1,3 +0,0 @@ -Add ``isolated=True`` keyword-only parameter to -``_xxsubinterpreters.create()``. An isolated subinterpreter cannot spawn -threads, spawn a child process or call ``os.fork()``. diff --git a/Misc/NEWS.d/next/Library/2020-04-30-22-25-08.bpo-32494.1xaU5l.rst b/Misc/NEWS.d/next/Library/2020-04-30-22-25-08.bpo-32494.1xaU5l.rst deleted file mode 100644 index 3989700c5cd833..00000000000000 --- a/Misc/NEWS.d/next/Library/2020-04-30-22-25-08.bpo-32494.1xaU5l.rst +++ /dev/null @@ -1,2 +0,0 @@ -Update :mod:`dbm.gnu` to use gdbm_count if possible when calling -:func:`len`. Patch by Dong-hee Na. diff --git a/Misc/NEWS.d/next/Library/2020-05-01-00-22-58.bpo-39305.Cuwu_H.rst b/Misc/NEWS.d/next/Library/2020-05-01-00-22-58.bpo-39305.Cuwu_H.rst deleted file mode 100644 index 7c6fdb3ede1c63..00000000000000 --- a/Misc/NEWS.d/next/Library/2020-05-01-00-22-58.bpo-39305.Cuwu_H.rst +++ /dev/null @@ -1,2 +0,0 @@ -Update :mod:`nntplib` to merge :class:`nntplib.NNTP` and -:class:`nntplib._NNTPBase`. Patch by Dong-hee Na. diff --git a/Misc/NEWS.d/next/Library/2020-05-01-23-24-25.bpo-39435.mgb6ib.rst b/Misc/NEWS.d/next/Library/2020-05-01-23-24-25.bpo-39435.mgb6ib.rst deleted file mode 100644 index 2a516a53ed9e2b..00000000000000 --- a/Misc/NEWS.d/next/Library/2020-05-01-23-24-25.bpo-39435.mgb6ib.rst +++ /dev/null @@ -1 +0,0 @@ -The first argument of :func:`pickle.loads` is now positional-only. diff --git a/Misc/NEWS.d/next/Library/2020-05-02-04-29-31.bpo-40459.fSAYVD.rst b/Misc/NEWS.d/next/Library/2020-05-02-04-29-31.bpo-40459.fSAYVD.rst deleted file mode 100644 index d4bf6987fa2609..00000000000000 --- a/Misc/NEWS.d/next/Library/2020-05-02-04-29-31.bpo-40459.fSAYVD.rst +++ /dev/null @@ -1 +0,0 @@ -:func:`platform.win32_ver` now produces correct *ptype* strings instead of empty strings. diff --git a/Misc/NEWS.d/next/Library/2020-05-02-12-00-28.bpo-40465.qfCjOD.rst b/Misc/NEWS.d/next/Library/2020-05-02-12-00-28.bpo-40465.qfCjOD.rst deleted file mode 100644 index 7ce9a44c712e77..00000000000000 --- a/Misc/NEWS.d/next/Library/2020-05-02-12-00-28.bpo-40465.qfCjOD.rst +++ /dev/null @@ -1 +0,0 @@ -Deprecated the optional *random* argument to *random.shuffle()*. diff --git a/Misc/NEWS.d/next/Library/2020-05-02-14-24-48.bpo-40355.xTujaB.rst b/Misc/NEWS.d/next/Library/2020-05-02-14-24-48.bpo-40355.xTujaB.rst deleted file mode 100644 index 81f9e937a2bff4..00000000000000 --- a/Misc/NEWS.d/next/Library/2020-05-02-14-24-48.bpo-40355.xTujaB.rst +++ /dev/null @@ -1,2 +0,0 @@ -Improve error reporting in :func:`ast.literal_eval` in the presence of malformed :class:`ast.Dict` -nodes instead of silently ignoring any non-conforming elements. Patch by Curtis Bucher. diff --git a/Misc/NEWS.d/next/Library/2020-05-02-17-17-37.bpo-40457.EXReI1.rst b/Misc/NEWS.d/next/Library/2020-05-02-17-17-37.bpo-40457.EXReI1.rst deleted file mode 100644 index 19b6dd685cd8cb..00000000000000 --- a/Misc/NEWS.d/next/Library/2020-05-02-17-17-37.bpo-40457.EXReI1.rst +++ /dev/null @@ -1 +0,0 @@ -The ssl module now support OpenSSL builds without TLS 1.0 and 1.1 methods. diff --git a/Misc/NEWS.d/next/Library/2020-05-04-11-20-49.bpo-40495.TyTc2O.rst b/Misc/NEWS.d/next/Library/2020-05-04-11-20-49.bpo-40495.TyTc2O.rst deleted file mode 100644 index d3049b05a78b6c..00000000000000 --- a/Misc/NEWS.d/next/Library/2020-05-04-11-20-49.bpo-40495.TyTc2O.rst +++ /dev/null @@ -1,2 +0,0 @@ -:mod:`compileall` is now able to use hardlinks to prevent duplicates in a -case when ``.pyc`` files for different optimization levels have the same content. diff --git a/Misc/NEWS.d/next/Library/2020-05-04-21-21-43.bpo-40480.mjldWa.rst b/Misc/NEWS.d/next/Library/2020-05-04-21-21-43.bpo-40480.mjldWa.rst deleted file mode 100644 index d046b1422419d7..00000000000000 --- a/Misc/NEWS.d/next/Library/2020-05-04-21-21-43.bpo-40480.mjldWa.rst +++ /dev/null @@ -1 +0,0 @@ -``fnmatch.fnmatch()`` could take exponential time in the presence of multiple ``*`` pattern characters. This was repaired by generating more elaborate regular expressions to avoid futile backtracking. \ No newline at end of file diff --git a/Misc/NEWS.d/next/Library/2020-05-05-08-12-51.bpo-40559.112wwa.rst b/Misc/NEWS.d/next/Library/2020-05-05-08-12-51.bpo-40559.112wwa.rst deleted file mode 100644 index 15846351f25bbe..00000000000000 --- a/Misc/NEWS.d/next/Library/2020-05-05-08-12-51.bpo-40559.112wwa.rst +++ /dev/null @@ -1 +0,0 @@ -Fix possible memory leak in the C implementation of :class:`asyncio.Task`. \ No newline at end of file diff --git a/Misc/NEWS.d/next/Library/2020-05-05-17-12-47.bpo-40504.EX6wPn.rst b/Misc/NEWS.d/next/Library/2020-05-05-17-12-47.bpo-40504.EX6wPn.rst deleted file mode 100644 index 261a49e4329280..00000000000000 --- a/Misc/NEWS.d/next/Library/2020-05-05-17-12-47.bpo-40504.EX6wPn.rst +++ /dev/null @@ -1 +0,0 @@ -:func:`functools.lru_cache` objects can now be the targets of weakrefs. \ No newline at end of file diff --git a/Misc/NEWS.d/next/Library/2020-05-06-02-33-00.bpo-31033.aX12pw.rst b/Misc/NEWS.d/next/Library/2020-05-06-02-33-00.bpo-31033.aX12pw.rst deleted file mode 100644 index b1831e5ff8f895..00000000000000 --- a/Misc/NEWS.d/next/Library/2020-05-06-02-33-00.bpo-31033.aX12pw.rst +++ /dev/null @@ -1,2 +0,0 @@ -When a :class:`asyncio.Task` is cancelled, the exception traceback -now chains all the way back to where the task was first interrupted. diff --git a/Misc/NEWS.d/next/Library/2020-05-06-13-51-19.bpo-40515.TUCvYB.rst b/Misc/NEWS.d/next/Library/2020-05-06-13-51-19.bpo-40515.TUCvYB.rst deleted file mode 100644 index af77a57fe7237b..00000000000000 --- a/Misc/NEWS.d/next/Library/2020-05-06-13-51-19.bpo-40515.TUCvYB.rst +++ /dev/null @@ -1,3 +0,0 @@ -The :mod:`ssl` and :mod:`hashlib` modules now actively check that OpenSSL is -build with thread support. Python 3.7.0 made thread support mandatory and no -longer works safely with a no-thread builds. diff --git a/Misc/NEWS.d/next/Library/2020-05-06-15-36-47.bpo-40541.LlYghL.rst b/Misc/NEWS.d/next/Library/2020-05-06-15-36-47.bpo-40541.LlYghL.rst deleted file mode 100644 index a2e694ac1ad080..00000000000000 --- a/Misc/NEWS.d/next/Library/2020-05-06-15-36-47.bpo-40541.LlYghL.rst +++ /dev/null @@ -1 +0,0 @@ -Added an optional *counts* parameter to random.sample(). diff --git a/Misc/NEWS.d/next/Library/2020-05-07-06-41-20.bpo-31033.waCj3n.rst b/Misc/NEWS.d/next/Library/2020-05-07-06-41-20.bpo-31033.waCj3n.rst deleted file mode 100644 index e3d35a04aab513..00000000000000 --- a/Misc/NEWS.d/next/Library/2020-05-07-06-41-20.bpo-31033.waCj3n.rst +++ /dev/null @@ -1 +0,0 @@ -Add a ``msg`` argument to :meth:`Future.cancel` and :meth:`Task.cancel`. diff --git a/Misc/NEWS.d/next/Library/2020-05-07-20-11-51.bpo-40549.6FiRSV.rst b/Misc/NEWS.d/next/Library/2020-05-07-20-11-51.bpo-40549.6FiRSV.rst deleted file mode 100644 index 873ff49c1eb00b..00000000000000 --- a/Misc/NEWS.d/next/Library/2020-05-07-20-11-51.bpo-40549.6FiRSV.rst +++ /dev/null @@ -1,2 +0,0 @@ -Convert posixmodule.c ("posix" or "nt" module) to the multiphase -initialization (PEP 489). diff --git a/Misc/NEWS.d/next/Library/2020-05-07-21-22-04.bpo-40397.PVWFAn.rst b/Misc/NEWS.d/next/Library/2020-05-07-21-22-04.bpo-40397.PVWFAn.rst deleted file mode 100644 index 46e806a2dc2222..00000000000000 --- a/Misc/NEWS.d/next/Library/2020-05-07-21-22-04.bpo-40397.PVWFAn.rst +++ /dev/null @@ -1,2 +0,0 @@ -Removed attributes ``__args__`` and ``__parameters__`` from special generic -aliases like ``typing.List`` (not subscripted). diff --git a/Misc/NEWS.d/next/Library/2020-05-08-15-48-39.bpo-40503.elZyxc.rst b/Misc/NEWS.d/next/Library/2020-05-08-15-48-39.bpo-40503.elZyxc.rst deleted file mode 100644 index d68797a738c2c1..00000000000000 --- a/Misc/NEWS.d/next/Library/2020-05-08-15-48-39.bpo-40503.elZyxc.rst +++ /dev/null @@ -1 +0,0 @@ -:pep:`615`, the :mod:`zoneinfo` module. Adds support for the IANA time zone database. diff --git a/Misc/NEWS.d/next/Library/2020-05-09-15-38-25.bpo-40571.kOXZGC.rst b/Misc/NEWS.d/next/Library/2020-05-09-15-38-25.bpo-40571.kOXZGC.rst deleted file mode 100644 index 476770f6974d2f..00000000000000 --- a/Misc/NEWS.d/next/Library/2020-05-09-15-38-25.bpo-40571.kOXZGC.rst +++ /dev/null @@ -1,2 +0,0 @@ -Added functools.cache() as a simpler, more discoverable way to access the -unbounded cache variant of lru_cache(maxsize=None). diff --git a/Misc/NEWS.d/next/Library/2020-05-11-19-17-23.bpo-40597.4SGfgm.rst b/Misc/NEWS.d/next/Library/2020-05-11-19-17-23.bpo-40597.4SGfgm.rst deleted file mode 100644 index 1b9fe609c25b71..00000000000000 --- a/Misc/NEWS.d/next/Library/2020-05-11-19-17-23.bpo-40597.4SGfgm.rst +++ /dev/null @@ -1 +0,0 @@ -If text content lines are longer than policy.max_line_length, always use a content-encoding to make sure they are wrapped. diff --git a/Misc/NEWS.d/next/Library/2020-05-13-10-23-29.bpo-40612.gOIreM.rst b/Misc/NEWS.d/next/Library/2020-05-13-10-23-29.bpo-40612.gOIreM.rst deleted file mode 100644 index 32cc8073d3f79c..00000000000000 --- a/Misc/NEWS.d/next/Library/2020-05-13-10-23-29.bpo-40612.gOIreM.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix edge cases in SyntaxError formatting. If the offset is <= 0, no caret is printed. -If the offset is > line length, the caret is printed pointing just after the last character. diff --git a/Misc/NEWS.d/next/Library/2020-05-13-15-32-13.bpo-40607.uSPFCi.rst b/Misc/NEWS.d/next/Library/2020-05-13-15-32-13.bpo-40607.uSPFCi.rst deleted file mode 100644 index 8060628b595480..00000000000000 --- a/Misc/NEWS.d/next/Library/2020-05-13-15-32-13.bpo-40607.uSPFCi.rst +++ /dev/null @@ -1,3 +0,0 @@ -When cancelling a task due to timeout, :meth:`asyncio.wait_for` will now -propagate the exception if an error happens during cancellation. -Patch by Roman Skurikhin. diff --git a/Misc/NEWS.d/next/Library/2020-05-13-23-10-25.bpo-40257.aR4TGp.rst b/Misc/NEWS.d/next/Library/2020-05-13-23-10-25.bpo-40257.aR4TGp.rst deleted file mode 100644 index 9d4037bc9aa797..00000000000000 --- a/Misc/NEWS.d/next/Library/2020-05-13-23-10-25.bpo-40257.aR4TGp.rst +++ /dev/null @@ -1 +0,0 @@ -Revert changes to :func:`inspect.getdoc`. diff --git a/Misc/NEWS.d/next/Library/2020-05-15-17-38-21.bpo-40479.yamSCh.rst b/Misc/NEWS.d/next/Library/2020-05-15-17-38-21.bpo-40479.yamSCh.rst deleted file mode 100644 index 87ede982f29677..00000000000000 --- a/Misc/NEWS.d/next/Library/2020-05-15-17-38-21.bpo-40479.yamSCh.rst +++ /dev/null @@ -1 +0,0 @@ -The :mod:`hashlib` now compiles with OpenSSL 3.0.0-alpha2. diff --git a/Misc/NEWS.d/next/Library/2020-05-15-19-53-18.bpo-37630.O5kgAw.rst b/Misc/NEWS.d/next/Library/2020-05-15-19-53-18.bpo-37630.O5kgAw.rst deleted file mode 100644 index 78458e6d1a46b6..00000000000000 --- a/Misc/NEWS.d/next/Library/2020-05-15-19-53-18.bpo-37630.O5kgAw.rst +++ /dev/null @@ -1,2 +0,0 @@ -The :mod:`hashlib` module can now use SHA3 hashes and SHAKE XOF from OpenSSL -when available. diff --git a/Misc/NEWS.d/next/Library/2020-05-15-21-57-10.bpo-40637.lb3Bnp.rst b/Misc/NEWS.d/next/Library/2020-05-15-21-57-10.bpo-40637.lb3Bnp.rst deleted file mode 100644 index d05e57d86b6ecc..00000000000000 --- a/Misc/NEWS.d/next/Library/2020-05-15-21-57-10.bpo-40637.lb3Bnp.rst +++ /dev/null @@ -1,2 +0,0 @@ -Builtin hash modules can now be disabled or selectively enabled with -``configure --with-builtin-hashlib-hashes=sha3,blake1`` or ``--without-builtin-hashlib-hashes``. diff --git a/Misc/NEWS.d/next/Library/2020-05-16-17-05-02.bpo-40645.wYSkjT.rst b/Misc/NEWS.d/next/Library/2020-05-16-17-05-02.bpo-40645.wYSkjT.rst deleted file mode 100644 index bb7eacdc5aa78f..00000000000000 --- a/Misc/NEWS.d/next/Library/2020-05-16-17-05-02.bpo-40645.wYSkjT.rst +++ /dev/null @@ -1 +0,0 @@ -The internal module ``_hashlib`` wraps and exposes OpenSSL's HMAC API. The new code will be used in Python 3.10 after the internal implementation details of the pure Python HMAC module are no longer part of the public API. diff --git a/Misc/NEWS.d/next/Library/2020-05-16-19-34-38.bpo-40645.7ibMt-.rst b/Misc/NEWS.d/next/Library/2020-05-16-19-34-38.bpo-40645.7ibMt-.rst deleted file mode 100644 index 19d5a651eb49aa..00000000000000 --- a/Misc/NEWS.d/next/Library/2020-05-16-19-34-38.bpo-40645.7ibMt-.rst +++ /dev/null @@ -1,3 +0,0 @@ -The :class:`hmac.HMAC` exposes internal implementation details. The -attributes ``digest_cons``, ``inner``, and ``outer`` are deprecated and will -be removed in the future. diff --git a/Misc/NEWS.d/next/Library/2020-05-17-14-00-12.bpo-40536.FCpoRA.rst b/Misc/NEWS.d/next/Library/2020-05-17-14-00-12.bpo-40536.FCpoRA.rst deleted file mode 100644 index ba7773bf61fa6b..00000000000000 --- a/Misc/NEWS.d/next/Library/2020-05-17-14-00-12.bpo-40536.FCpoRA.rst +++ /dev/null @@ -1,2 +0,0 @@ -Added the :func:`~zoneinfo.available_timezones` function to the -:mod:`zoneinfo` module. Patch by Paul Ganssle. diff --git a/Misc/NEWS.d/next/Library/2020-05-17-21-56-38.bpo-40665.msB7u5.rst b/Misc/NEWS.d/next/Library/2020-05-17-21-56-38.bpo-40665.msB7u5.rst deleted file mode 100644 index 160b2ca75d31cf..00000000000000 --- a/Misc/NEWS.d/next/Library/2020-05-17-21-56-38.bpo-40665.msB7u5.rst +++ /dev/null @@ -1 +0,0 @@ -Convert :mod:`bisect` to use Argument Clinic. \ No newline at end of file diff --git a/Misc/NEWS.d/next/Library/2020-05-18-12-56-45.bpo-40662.dfornR.rst b/Misc/NEWS.d/next/Library/2020-05-18-12-56-45.bpo-40662.dfornR.rst deleted file mode 100644 index a960c3f61b6bbe..00000000000000 --- a/Misc/NEWS.d/next/Library/2020-05-18-12-56-45.bpo-40662.dfornR.rst +++ /dev/null @@ -1 +0,0 @@ -Fixed :func:`ast.get_source_segment` for ast nodes that have incomplete location information. Patch by Irit Katriel. diff --git a/Misc/NEWS.d/next/Security/2020-05-06-00-41-11.bpo-40501._61wv_.rst b/Misc/NEWS.d/next/Security/2020-05-06-00-41-11.bpo-40501._61wv_.rst deleted file mode 100644 index 5ce22eb8a92eef..00000000000000 --- a/Misc/NEWS.d/next/Security/2020-05-06-00-41-11.bpo-40501._61wv_.rst +++ /dev/null @@ -1,2 +0,0 @@ -:mod:`uuid` no longer uses :mod:`ctypes` to load :file:`libuuid` or -:file:`rpcrt4.dll` at runtime. diff --git a/Misc/NEWS.d/next/Tests/2020-04-29-16-08-24.bpo-40436.gDMnYl.rst b/Misc/NEWS.d/next/Tests/2020-04-29-16-08-24.bpo-40436.gDMnYl.rst deleted file mode 100644 index 0aee2c3aa2b4dd..00000000000000 --- a/Misc/NEWS.d/next/Tests/2020-04-29-16-08-24.bpo-40436.gDMnYl.rst +++ /dev/null @@ -1 +0,0 @@ -test_gdb and test.pythoninfo now check gdb command exit code. diff --git a/Misc/NEWS.d/next/Tests/2020-05-15-01-21-44.bpo-40055.Xp4aP9.rst b/Misc/NEWS.d/next/Tests/2020-05-15-01-21-44.bpo-40055.Xp4aP9.rst deleted file mode 100644 index edb01182c3a5ce..00000000000000 --- a/Misc/NEWS.d/next/Tests/2020-05-15-01-21-44.bpo-40055.Xp4aP9.rst +++ /dev/null @@ -1,3 +0,0 @@ -distutils.tests now saves/restores warnings filters to leave them unchanged. -Importing tests imports docutils which imports pkg_resources which adds a -warnings filter. diff --git a/Misc/NEWS.d/next/Tools-Demos/2020-04-03-08-32-31.bpo-40163.lX8K4B.rst b/Misc/NEWS.d/next/Tools-Demos/2020-04-03-08-32-31.bpo-40163.lX8K4B.rst deleted file mode 100644 index fc0a22a0a953e1..00000000000000 --- a/Misc/NEWS.d/next/Tools-Demos/2020-04-03-08-32-31.bpo-40163.lX8K4B.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix multissltest tool. OpenSSL has changed download URL for old releases. -The multissltest tool now tries to download from current and old download -URLs. diff --git a/Misc/NEWS.d/next/Tools-Demos/2020-04-29-01-32-17.bpo-40431.B_aEZ0.rst b/Misc/NEWS.d/next/Tools-Demos/2020-04-29-01-32-17.bpo-40431.B_aEZ0.rst deleted file mode 100644 index abef046326fcb0..00000000000000 --- a/Misc/NEWS.d/next/Tools-Demos/2020-04-29-01-32-17.bpo-40431.B_aEZ0.rst +++ /dev/null @@ -1 +0,0 @@ -Fix a syntax typo in ``turtledemo`` that now raises a ``SyntaxError``. diff --git a/Misc/NEWS.d/next/Tools-Demos/2020-05-15-17-48-25.bpo-40479.B1gBl-.rst b/Misc/NEWS.d/next/Tools-Demos/2020-05-15-17-48-25.bpo-40479.B1gBl-.rst deleted file mode 100644 index b59035971d7b08..00000000000000 --- a/Misc/NEWS.d/next/Tools-Demos/2020-05-15-17-48-25.bpo-40479.B1gBl-.rst +++ /dev/null @@ -1,2 +0,0 @@ -Update multissltest helper to test with latest OpenSSL 1.0.2, 1.1.0, 1.1.1, -and 3.0.0-alpha. diff --git a/Misc/NEWS.d/next/Windows/2020-03-23-19-07-55.bpo-39148.W1YJEb.rst b/Misc/NEWS.d/next/Windows/2020-03-23-19-07-55.bpo-39148.W1YJEb.rst deleted file mode 100644 index 7c70dce1e73339..00000000000000 --- a/Misc/NEWS.d/next/Windows/2020-03-23-19-07-55.bpo-39148.W1YJEb.rst +++ /dev/null @@ -1,3 +0,0 @@ -Add IPv6 support to :mod:`asyncio` datagram endpoints in ProactorEventLoop. -Change the raised exception for unknown address families to ValueError -as it's not coming from Windows API. diff --git a/Misc/NEWS.d/next/Windows/2020-05-01-20-57-57.bpo-40458.Eb0ueI.rst b/Misc/NEWS.d/next/Windows/2020-05-01-20-57-57.bpo-40458.Eb0ueI.rst deleted file mode 100644 index 4dc1ff480df87a..00000000000000 --- a/Misc/NEWS.d/next/Windows/2020-05-01-20-57-57.bpo-40458.Eb0ueI.rst +++ /dev/null @@ -1 +0,0 @@ -Increase reserved stack space to prevent overflow crash on Windows. diff --git a/Misc/NEWS.d/next/Windows/2020-05-17-00-08-13.bpo-40650.4euMtU.rst b/Misc/NEWS.d/next/Windows/2020-05-17-00-08-13.bpo-40650.4euMtU.rst deleted file mode 100644 index db13e58b14a790..00000000000000 --- a/Misc/NEWS.d/next/Windows/2020-05-17-00-08-13.bpo-40650.4euMtU.rst +++ /dev/null @@ -1 +0,0 @@ -Include winsock2.h in pytime.c for timeval. \ No newline at end of file diff --git a/Misc/NEWS.d/next/macOS/2020-04-15-00-02-47.bpo-35569.02_1MV.rst b/Misc/NEWS.d/next/macOS/2020-04-15-00-02-47.bpo-35569.02_1MV.rst deleted file mode 100644 index ed48efd7f5c492..00000000000000 --- a/Misc/NEWS.d/next/macOS/2020-04-15-00-02-47.bpo-35569.02_1MV.rst +++ /dev/null @@ -1 +0,0 @@ -Expose RFC 3542 IPv6 socket options. diff --git a/Misc/NEWS.d/next/macOS/2020-05-18-02-43-11.bpo-34956.35IcGF.rst b/Misc/NEWS.d/next/macOS/2020-05-18-02-43-11.bpo-34956.35IcGF.rst deleted file mode 100644 index 6ad9c1ac93355a..00000000000000 --- a/Misc/NEWS.d/next/macOS/2020-05-18-02-43-11.bpo-34956.35IcGF.rst +++ /dev/null @@ -1,6 +0,0 @@ -_tkinter now builds and links with non-system Tcl and Tk frameworks if they -are installed in /Library/Frameworks as had been the case on older releases -of macOS. If a macOS SDK is explicitly configured, by using ./configure ---enable-universalsdk= or -isysroot, only a Library/Frameworks directory in -the SDK itself is searched. The default behavior can still be overridden with -configure --with-tcltk-includes and --with-tcltk-libs. diff --git a/README.rst b/README.rst index 82303953ecda58..d3c6ab439f3ce0 100644 --- a/README.rst +++ b/README.rst @@ -1,5 +1,5 @@ -This is Python version 3.9.0 alpha 6 -==================================== +This is Python version 3.9.0 beta 1 +=================================== .. image:: https://travis-ci.org/python/cpython.svg?branch=master :alt: CPython build status on Travis CI From 5e6f198bdb737d95a928dc5475e88fdcfefea98f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Langa?= Date: Tue, 19 May 2020 02:12:30 +0200 Subject: [PATCH 0002/1314] Post 3.9.0b1 --- Include/patchlevel.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Include/patchlevel.h b/Include/patchlevel.h index c028eea7b56d6a..16b53ba7a2508b 100644 --- a/Include/patchlevel.h +++ b/Include/patchlevel.h @@ -23,7 +23,7 @@ #define PY_RELEASE_SERIAL 1 /* Version as a string */ -#define PY_VERSION "3.9.0b1" +#define PY_VERSION "3.9.0b1+" /*--end constants--*/ /* Version as a single 4-byte hex number, e.g. 0x010502B2 == 1.5.2b2. From 1bf757884a431e025ef5f1e84c34b3fbbbe5b792 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Langa?= Date: Tue, 19 May 2020 02:31:31 +0200 Subject: [PATCH 0003/1314] Update README links to point to 3.9 and not master --- README.rst | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/README.rst b/README.rst index d3c6ab439f3ce0..147344b278973a 100644 --- a/README.rst +++ b/README.rst @@ -1,7 +1,7 @@ This is Python version 3.9.0 beta 1 =================================== -.. image:: https://travis-ci.org/python/cpython.svg?branch=master +.. image:: https://travis-ci.org/python/cpython.svg?branch=3.9 :alt: CPython build status on Travis CI :target: https://travis-ci.org/python/cpython @@ -9,11 +9,11 @@ This is Python version 3.9.0 beta 1 :alt: CPython build status on GitHub Actions :target: https://github.com/python/cpython/actions -.. image:: https://dev.azure.com/python/cpython/_apis/build/status/Azure%20Pipelines%20CI?branchName=master +.. image:: https://dev.azure.com/python/cpython/_apis/build/status/Azure%20Pipelines%20CI?branchName=3.9 :alt: CPython build status on Azure DevOps - :target: https://dev.azure.com/python/cpython/_build/latest?definitionId=4&branchName=master + :target: https://dev.azure.com/python/cpython/_build/latest?definitionId=4&branchName=3.9 -.. image:: https://codecov.io/gh/python/cpython/branch/master/graph/badge.svg +.. image:: https://codecov.io/gh/python/cpython/branch/3.9/graph/badge.svg :alt: CPython code coverage on Codecov :target: https://codecov.io/gh/python/cpython @@ -79,10 +79,10 @@ dependencies for various Linux distributions and macOS. On macOS, there are additional configure and build options related to macOS framework and universal builds. Refer to `Mac/README.rst -`_. +`_. On Windows, see `PCbuild/readme.txt -`_. +`_. If you wish, you can create a subdirectory and invoke configure from there. For example:: @@ -143,9 +143,9 @@ What's New We have a comprehensive overview of the changes in the `What's New in Python 3.9 `_ document. For a more detailed change log, read `Misc/NEWS -`_, but a full +`_, but a full accounting of changes can only be gleaned from the `commit history -`_. +`_. If you want to install multiple versions of Python, see the section below entitled "Installing multiple versions". @@ -163,7 +163,7 @@ is primarily for documentation authors, translators, and people with special formatting requirements. For information about building Python's documentation, refer to `Doc/README.rst -`_. +`_. Converting From Python 2.x to 3.x From f02c3048dc2f22053a2ba56ef5987967b89c4be3 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 18 May 2020 19:14:13 -0700 Subject: [PATCH 0004/1314] Use _PyErr_ChainStackItem() inside gen_send_ex(). (GH-20173) (#20202) _PyErr_ChainStackItem was just added in GH-19951 (for bpo-31033). (cherry picked from commit ff7a8b03c49153021d6de5d0b2fa8b5163059ed6) Co-authored-by: Chris Jerdonek Co-authored-by: Chris Jerdonek --- Objects/genobject.c | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/Objects/genobject.c b/Objects/genobject.c index 40179cdbf7dbd2..271720bdf8b4ce 100644 --- a/Objects/genobject.c +++ b/Objects/genobject.c @@ -203,16 +203,8 @@ gen_send_ex(PyGenObject *gen, PyObject *arg, int exc, int closing) assert(f->f_back == NULL); f->f_back = tstate->frame; - _PyErr_StackItem *gi_exc_state = &gen->gi_exc_state; - if (exc && gi_exc_state->exc_type != NULL && - gi_exc_state->exc_type != Py_None) - { - Py_INCREF(gi_exc_state->exc_type); - Py_XINCREF(gi_exc_state->exc_value); - Py_XINCREF(gi_exc_state->exc_traceback); - _PyErr_ChainExceptions(gi_exc_state->exc_type, - gi_exc_state->exc_value, - gi_exc_state->exc_traceback); + if (exc) { + _PyErr_ChainStackItem(&gen->gi_exc_state); } gen->gi_running = 1; From 3d062829deadcb8355e97090aba47138eb9bc649 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 18 May 2020 19:31:28 -0700 Subject: [PATCH 0005/1314] bpo-40669: Use requirements.pip when installing PEG dependencies (GH-20194) (cherry picked from commit 3764069f3ba2a7e932837ae19265059339dc86e3) Co-authored-by: Pablo Galindo --- Tools/peg_generator/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tools/peg_generator/Makefile b/Tools/peg_generator/Makefile index 7b33a86b24a8b2..34763b543c23b8 100644 --- a/Tools/peg_generator/Makefile +++ b/Tools/peg_generator/Makefile @@ -46,7 +46,7 @@ regen-metaparser: pegen/metagrammar.gram pegen/*.py venv: $(PYTHON) -m venv $(VENVDIR) $(VENVPYTHON) -m pip install -U pip setuptools - $(VENVPYTHON) -m pip install -U memory_profiler + $(VENVPYTHON) -m pip install -r requirements.pip @echo "The venv has been created in the $(VENVDIR) directory" test: run From e2991308c9b49547d9762157ac913dda94b5eb32 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 19 May 2020 03:03:25 -0700 Subject: [PATCH 0006/1314] bpo-32309: Implement asyncio.to_thread() (GH-20143) Implements `asyncio.to_thread`, a coroutine for asynchronously running IO-bound functions in a separate thread without blocking the event loop. See the discussion starting from [here](https://github.com/python/cpython/pull/18410GH-issuecomment-628930973) in GH-18410 for context. Automerge-Triggered-By: @aeros (cherry picked from commit cc2bbc2227c3f5ed9d8f6b3bd052e6f9e68279d2) Co-authored-by: Kyle Stanley --- Doc/library/asyncio-api-index.rst | 3 + Doc/library/asyncio-task.rst | 56 +++++++++++++ Doc/whatsnew/3.9.rst | 6 ++ Lib/asyncio/__init__.py | 2 + Lib/asyncio/threads.py | 21 +++++ Lib/test/test_asyncio/test_threads.py | 79 +++++++++++++++++++ .../2020-05-17-02-03-09.bpo-32309.KM9psl.rst | 4 + 7 files changed, 171 insertions(+) create mode 100644 Lib/asyncio/threads.py create mode 100644 Lib/test/test_asyncio/test_threads.py create mode 100644 Misc/NEWS.d/next/Library/2020-05-17-02-03-09.bpo-32309.KM9psl.rst diff --git a/Doc/library/asyncio-api-index.rst b/Doc/library/asyncio-api-index.rst index d5b5659abc65e2..047e5bbc58ccad 100644 --- a/Doc/library/asyncio-api-index.rst +++ b/Doc/library/asyncio-api-index.rst @@ -48,6 +48,9 @@ await on multiple things with timeouts. * - :class:`Task` - Task object. + * - :func:`to_thread` + - Asychronously run a function in a separate OS thread. + * - :func:`run_coroutine_threadsafe` - Schedule a coroutine from another OS thread. diff --git a/Doc/library/asyncio-task.rst b/Doc/library/asyncio-task.rst index 2e963398d93001..7c2704090551b6 100644 --- a/Doc/library/asyncio-task.rst +++ b/Doc/library/asyncio-task.rst @@ -602,6 +602,62 @@ Waiting Primitives # ... +Running in Threads +================== + +.. coroutinefunction:: to_thread(func, /, \*args, \*\*kwargs) + + Asynchronously run function *func* in a separate thread. + + Any \*args and \*\*kwargs supplied for this function are directly passed + to *func*. + + Return an :class:`asyncio.Future` which represents the eventual result of + *func*. + + This coroutine function is primarily intended to be used for executing + IO-bound functions/methods that would otherwise block the event loop if + they were ran in the main thread. For example:: + + def blocking_io(): + print(f"start blocking_io at {time.strftime('%X')}") + # Note that time.sleep() can be replaced with any blocking + # IO-bound operation, such as file operations. + time.sleep(1) + print(f"blocking_io complete at {time.strftime('%X')}") + + async def main(): + print(f"started main at {time.strftime('%X')}") + + await asyncio.gather( + asyncio.to_thread(blocking_io), + asyncio.sleep(1)) + + print(f"finished main at {time.strftime('%X')}") + + + asyncio.run(main()) + + # Expected output: + # + # started main at 19:50:53 + # start blocking_io at 19:50:53 + # blocking_io complete at 19:50:54 + # finished main at 19:50:54 + + Directly calling `blocking_io()` in any coroutine would block the event loop + for its duration, resulting in an additional 1 second of run time. Instead, + by using `asyncio.to_thread()`, we can run it in a separate thread without + blocking the event loop. + + .. note:: + + Due to the :term:`GIL`, `asyncio.to_thread()` can typically only be used + to make IO-bound functions non-blocking. However, for extension modules + that release the GIL or alternative Python implementations that don't + have one, `asyncio.to_thread()` can also be used for CPU-bound functions. + + Scheduling From Other Threads ============================= diff --git a/Doc/whatsnew/3.9.rst b/Doc/whatsnew/3.9.rst index 593f523828703e..037e1055c79e52 100644 --- a/Doc/whatsnew/3.9.rst +++ b/Doc/whatsnew/3.9.rst @@ -282,6 +282,12 @@ that schedules a shutdown for the default executor that waits on the Added :class:`asyncio.PidfdChildWatcher`, a Linux-specific child watcher implementation that polls process file descriptors. (:issue:`38692`) +Added a new :term:`coroutine` :func:`asyncio.to_thread`. It is mainly used for +running IO-bound functions in a separate thread to avoid blocking the event +loop, and essentially works as a high-level version of +:meth:`~asyncio.loop.run_in_executor` that can directly take keyword arguments. +(Contributed by Kyle Stanley and Yury Selivanov in :issue:`32309`.) + compileall ---------- diff --git a/Lib/asyncio/__init__.py b/Lib/asyncio/__init__.py index 28c2e2c429f34a..eb84bfb189ccf3 100644 --- a/Lib/asyncio/__init__.py +++ b/Lib/asyncio/__init__.py @@ -17,6 +17,7 @@ from .streams import * from .subprocess import * from .tasks import * +from .threads import * from .transports import * # Exposed for _asynciomodule.c to implement now deprecated @@ -35,6 +36,7 @@ streams.__all__ + subprocess.__all__ + tasks.__all__ + + threads.__all__ + transports.__all__) if sys.platform == 'win32': # pragma: no cover diff --git a/Lib/asyncio/threads.py b/Lib/asyncio/threads.py new file mode 100644 index 00000000000000..2f40467fe5bc7b --- /dev/null +++ b/Lib/asyncio/threads.py @@ -0,0 +1,21 @@ +"""High-level support for working with threads in asyncio""" + +import functools + +from . import events + + +__all__ = "to_thread", + + +async def to_thread(func, /, *args, **kwargs): + """Asynchronously run function *func* in a separate thread. + + Any *args and **kwargs supplied for this function are directly passed + to *func*. + + Return an asyncio.Future which represents the eventual result of *func*. + """ + loop = events.get_running_loop() + func_call = functools.partial(func, *args, **kwargs) + return await loop.run_in_executor(None, func_call) diff --git a/Lib/test/test_asyncio/test_threads.py b/Lib/test/test_asyncio/test_threads.py new file mode 100644 index 00000000000000..99a00f21832f3e --- /dev/null +++ b/Lib/test/test_asyncio/test_threads.py @@ -0,0 +1,79 @@ +"""Tests for asyncio/threads.py""" + +import asyncio +import unittest + +from unittest import mock +from test.test_asyncio import utils as test_utils + + +def tearDownModule(): + asyncio.set_event_loop_policy(None) + + +class ToThreadTests(test_utils.TestCase): + def setUp(self): + super().setUp() + self.loop = asyncio.new_event_loop() + asyncio.set_event_loop(self.loop) + + def tearDown(self): + self.loop.run_until_complete( + self.loop.shutdown_default_executor()) + self.loop.close() + asyncio.set_event_loop(None) + self.loop = None + super().tearDown() + + def test_to_thread(self): + async def main(): + return await asyncio.to_thread(sum, [40, 2]) + + result = self.loop.run_until_complete(main()) + self.assertEqual(result, 42) + + def test_to_thread_exception(self): + def raise_runtime(): + raise RuntimeError("test") + + async def main(): + await asyncio.to_thread(raise_runtime) + + with self.assertRaisesRegex(RuntimeError, "test"): + self.loop.run_until_complete(main()) + + def test_to_thread_once(self): + func = mock.Mock() + + async def main(): + await asyncio.to_thread(func) + + self.loop.run_until_complete(main()) + func.assert_called_once() + + def test_to_thread_concurrent(self): + func = mock.Mock() + + async def main(): + futs = [] + for _ in range(10): + fut = asyncio.to_thread(func) + futs.append(fut) + await asyncio.gather(*futs) + + self.loop.run_until_complete(main()) + self.assertEqual(func.call_count, 10) + + def test_to_thread_args_kwargs(self): + # Unlike run_in_executor(), to_thread() should directly accept kwargs. + func = mock.Mock() + + async def main(): + await asyncio.to_thread(func, 'test', something=True) + + self.loop.run_until_complete(main()) + func.assert_called_once_with('test', something=True) + + +if __name__ == "__main__": + unittest.main() diff --git a/Misc/NEWS.d/next/Library/2020-05-17-02-03-09.bpo-32309.KM9psl.rst b/Misc/NEWS.d/next/Library/2020-05-17-02-03-09.bpo-32309.KM9psl.rst new file mode 100644 index 00000000000000..6272c35edf4d57 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2020-05-17-02-03-09.bpo-32309.KM9psl.rst @@ -0,0 +1,4 @@ +Added a new :term:`coroutine` :func:`asyncio.to_thread`. It is mainly used for +running IO-bound functions in a separate thread to avoid blocking the event +loop, and essentially works as a high-level version of +:meth:`~asyncio.loop.run_in_executor` that can directly take keyword arguments. \ No newline at end of file From 73812a49941f7a1d01ae48ed533f7d57af680e1a Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 19 May 2020 05:31:57 -0700 Subject: [PATCH 0007/1314] [3.9] Doc: Python 3.10 in sidebar and version switcher. (GH-20209) (GH-20221) (cherry picked from commit 19e3e0026417caa92ffe21a67157363b45da9aa2) Co-authored-by: Julien Palard --- Doc/tools/static/switchers.js | 3 ++- Doc/tools/templates/indexsidebar.html | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Doc/tools/static/switchers.js b/Doc/tools/static/switchers.js index e1ef91a8dfc686..c51f178ce645c0 100644 --- a/Doc/tools/static/switchers.js +++ b/Doc/tools/static/switchers.js @@ -10,7 +10,8 @@ '(?:release/\\d.\\d[\\x\\d\\.]*)']; var all_versions = { - '3.9': 'dev (3.9)', + '3.10': 'dev (3.10)', + '3.9': 'pre (3.9)', '3.8': '3.8', '3.7': '3.7', '3.6': '3.6', diff --git a/Doc/tools/templates/indexsidebar.html b/Doc/tools/templates/indexsidebar.html index 4730a5fe5db7bc..7a40be77aa1295 100644 --- a/Doc/tools/templates/indexsidebar.html +++ b/Doc/tools/templates/indexsidebar.html @@ -2,7 +2,8 @@

{% trans %}Download{% endtrans %}

{% trans %}Download these documents{% endtrans %}

{% trans %}Docs by version{% endtrans %}

From f22f874a66d6ddb32fa74ad4325199db7e4c25fd Mon Sep 17 00:00:00 2001 From: "Miss Skeleton (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 22 Oct 2020 09:02:13 -0700 Subject: [PATCH 0626/1314] bpo-25655: Improve Win DLL loading failures doc (GH-22372) Add documentation to help diagnose CDLL dependent DLL loading errors on windows for OSError with message: "[WinError 126] The specified module could not be found" This error is otherwise difficult to diagnose. (cherry picked from commit b6f2fc90409e291822166d74ce7402e0ef4dba91) Co-authored-by: Philippe Ombredanne --- Doc/library/ctypes.rst | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/Doc/library/ctypes.rst b/Doc/library/ctypes.rst index c172d5377636a7..bf32d3e549b480 100644 --- a/Doc/library/ctypes.rst +++ b/Doc/library/ctypes.rst @@ -1326,6 +1326,21 @@ way is to instantiate one of the following classes: libraries use the standard C calling convention, and are assumed to return :c:type:`int`. + On Windows creating a :class:`CDLL` instance may fail even if the DLL name + exists. When a dependent DLL of the loaded DLL is not found, a + :exc:`OSError` error is raised with the message *"[WinError 126] The + specified module could not be found".* This error message does not contain + the name of the missing DLL because the Windows API does not return this + information making this error hard to diagnose. To resolve this error and + determine which DLL is not found, you need to find the list of dependent + DLLs and determine which one is not found using Windows debugging and + tracing tools. + +.. seealso:: + + `Microsoft DUMPBIN tool `_ + -- A tool to find DLL dependents. + .. class:: OleDLL(name, mode=DEFAULT_MODE, handle=None, use_errno=False, use_last_error=False, winmode=0) From 25687bbe0da160ebdd3cd422a01d677ce467e72e Mon Sep 17 00:00:00 2001 From: "Miss Skeleton (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 22 Oct 2020 12:58:04 -0700 Subject: [PATCH 0627/1314] bpo-33987: IDLE: Use ttk Frame on doc window and statusbar (GH-11433) (GH-22899) (cherry picked from commit facb522d44fceaf15de6bc95de1cd680c4621c2a) Co-authored-by: Cheryl Sabella --- Lib/idlelib/help.py | 8 +++++--- Lib/idlelib/statusbar.py | 6 ++++-- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/Lib/idlelib/help.py b/Lib/idlelib/help.py index 9f63ea0d3990e6..f420d40fb9ea40 100644 --- a/Lib/idlelib/help.py +++ b/Lib/idlelib/help.py @@ -28,8 +28,8 @@ from os.path import abspath, dirname, isfile, join from platform import python_version -from tkinter import Toplevel, Frame, Text, Menu -from tkinter.ttk import Menubutton, Scrollbar +from tkinter import Toplevel, Text, Menu +from tkinter.ttk import Frame, Menubutton, Scrollbar, Style from tkinter import font as tkfont from idlelib.config import idleConf @@ -212,7 +212,9 @@ class HelpFrame(Frame): def __init__(self, parent, filename): Frame.__init__(self, parent) self.text = text = HelpText(self, filename) - self['background'] = text['background'] + self.style = Style(parent) + self['style'] = 'helpframe.TFrame' + self.style.configure('helpframe.TFrame', background=text['background']) self.toc = toc = self.toc_menu(text) self.scroll = scroll = Scrollbar(self, command=text.yview) text['yscrollcommand'] = scroll.set diff --git a/Lib/idlelib/statusbar.py b/Lib/idlelib/statusbar.py index c071f898b0f744..ae52a56368c82a 100644 --- a/Lib/idlelib/statusbar.py +++ b/Lib/idlelib/statusbar.py @@ -1,4 +1,5 @@ -from tkinter import Frame, Label +from tkinter import Label +from tkinter.ttk import Frame class MultiStatusBar(Frame): @@ -20,7 +21,8 @@ def set_label(self, name, text='', side='left', width=0): def _multistatus_bar(parent): # htest # - from tkinter import Toplevel, Frame, Text, Button + from tkinter import Toplevel, Text + from tkinter.ttk import Frame, Button top = Toplevel(parent) x, y = map(int, parent.geometry().split('+')[1:]) top.geometry("+%d+%d" %(x, y + 175)) From 69479ecfa86cc2f0e70d5627d52907e82c3f5b9b Mon Sep 17 00:00:00 2001 From: "Miss Skeleton (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 22 Oct 2020 16:55:05 -0700 Subject: [PATCH 0628/1314] [3.9] bpo-38486: Fix dead qmail links in the mailbox docs (GH-22239) (GH-22901) (cherry picked from commit ec388cfb4ede56dace2bb78851ff6f38fa2a6abe) Co-authored-by: Zackery Spytz Automerge-Triggered-By: GH:warsaw --- Doc/library/mailbox.rst | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/Doc/library/mailbox.rst b/Doc/library/mailbox.rst index f82a3b200deb7c..94d95d10290b00 100644 --- a/Doc/library/mailbox.rst +++ b/Doc/library/mailbox.rst @@ -426,17 +426,14 @@ Supported mailbox formats are Maildir, mbox, MH, Babyl, and MMDF. .. seealso:: - `maildir man page from qmail `_ - The original specification of the format. + `maildir man page from Courier `_ + A specification of the format. Describes a common extension for + supporting folders. `Using maildir format `_ Notes on Maildir by its inventor. Includes an updated name-creation scheme and details on "info" semantics. - `maildir man page from Courier `_ - Another specification of the format. Describes a common extension for supporting - folders. - .. _mailbox-mbox: @@ -485,11 +482,8 @@ Supported mailbox formats are Maildir, mbox, MH, Babyl, and MMDF. .. seealso:: - `mbox man page from qmail `_ - A specification of the format and its variations. - `mbox man page from tin `_ - Another specification of the format, with details on locking. + A specification of the format, with details on locking. `Configuring Netscape Mail on Unix: Why The Content-Length Format is Bad `_ An argument for using the original mbox format rather than a variation. From f8d96b98a48c97d0da8714e5e18675412774a6ef Mon Sep 17 00:00:00 2001 From: "Miss Skeleton (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 23 Oct 2020 13:49:32 -0700 Subject: [PATCH 0629/1314] Create a primer section for the descriptor howto guide (GH-22906) (GH0-22918) --- Doc/glossary.rst | 3 +- Doc/howto/descriptor.rst | 552 +++++++++++++++++++++++++++++++++---- Doc/tools/susp-ignored.csv | 3 + 3 files changed, 499 insertions(+), 59 deletions(-) diff --git a/Doc/glossary.rst b/Doc/glossary.rst index 9fdbdb1a83f280..189d49ee0d6279 100644 --- a/Doc/glossary.rst +++ b/Doc/glossary.rst @@ -301,7 +301,8 @@ Glossary including functions, methods, properties, class methods, static methods, and reference to super classes. - For more information about descriptors' methods, see :ref:`descriptors`. + For more information about descriptors' methods, see :ref:`descriptors` + or the :ref:`Descriptor How To Guide `. dictionary An associative array, where arbitrary keys are mapped to values. The diff --git a/Doc/howto/descriptor.rst b/Doc/howto/descriptor.rst index b792b6c6ab77f2..4a53b9e6156922 100644 --- a/Doc/howto/descriptor.rst +++ b/Doc/howto/descriptor.rst @@ -1,3 +1,5 @@ +.. _descriptorhowto: + ====================== Descriptor HowTo Guide ====================== @@ -7,6 +9,415 @@ Descriptor HowTo Guide .. Contents:: + +:term:`Descriptors ` let objects customize attribute lookup, +storage, and deletion. + +This HowTo guide has three major sections: + +1) The "primer" gives a basic overview, moving gently from simple examples, + adding one feature at a time. It is a great place to start. + +2) The second section shows a complete, practical descriptor example. If you + already know the basics, start there. + +3) The third section provides a more technical tutorial that goes into the + detailed mechanics of how descriptors work. Most people don't need this + level of detail. + + +Primer +^^^^^^ + +In this primer, we start with most basic possible example and then we'll add +new capabilities one by one. + + +Simple example: A descriptor that returns a constant +---------------------------------------------------- + +The :class:`Ten` class is a descriptor that always returns the constant ``10``:: + + + class Ten: + def __get__(self, obj, objtype=None): + return 10 + +To use the descriptor, it must be stored as a class variable in another class:: + + class A: + x = 5 # Regular class attribute + y = Ten() # Descriptor + +An interactive session shows the difference between normal attribute lookup +and descriptor lookup:: + + >>> a = A() # Make an instance of class A + >>> a.x # Normal attribute lookup + 5 + >>> a.y # Descriptor lookup + 10 + +In the ``a.x`` attribute lookup, the dot operator finds the value ``5`` stored +in the class dictionary. In the ``a.y`` descriptor lookup, the dot operator +calls the descriptor's :meth:`__get__()` method. That method returns ``10``. +Note that the value ``10`` is not stored in either the class dictionary or the +instance dictionary. Instead, the value ``10`` is computed on demand. + +This example shows how a simple descriptor works, but it isn't very useful. +For retrieving constants, normal attribute lookup would be better. + +In the next section, we'll create something more useful, a dynamic lookup. + + +Dynamic lookups +--------------- + +Interesting descriptors typically run computations instead of doing lookups:: + + + import os + + class DirectorySize: + + def __get__(self, obj, objtype=None): + return len(os.listdir(obj.dirname)) + + class Directory: + + size = DirectorySize() # Descriptor + + def __init__(self, dirname): + self.dirname = dirname # Regular instance attribute + +An interactive session shows that the lookup is dynamic — it computes +different, updated answers each time:: + + >>> g = Directory('games') + >>> s = Directory('songs') + >>> g.size # The games directory has three files + 3 + >>> os.system('touch games/newfile') # Add a fourth file to the directory + 0 + >>> g.size + 4 + >>> s.size # The songs directory has twenty files + 20 + +Besides showing how descriptors can run computations, this example also +reveals the purpose of the parameters to :meth:`__get__`. The *self* +parameter is *size*, an instance of *DirectorySize*. The *obj* parameter is +either *g* or *s*, an instance of *Directory*. It is *obj* parameter that +lets the :meth:`__get__` method learn the target directory. The *objtype* +parameter is the class *Directory*. + + +Managed attributes +------------------ + +A popular use for descriptors is managing access to instance data. The +descriptor is assigned to a public attribute in the class dictionary while the +actual data is stored as a private attribute in the instance dictionary. The +descriptor's :meth:`__get__` and :meth:`__set__` methods are triggered when +the public attribute is accessed. + +In the following example, *age* is the public attribute and *_age* is the +private attribute. When the public attribute is accessed, the descriptor logs +the lookup or update:: + + import logging + + logging.basicConfig(level=logging.INFO) + + class LoggedAgeAccess: + + def __get__(self, obj, objtype=None): + value = obj._age + logging.info('Accessing %r giving %r', 'age', value) + return value + + def __set__(self, obj, value): + logging.info('Updating %r to %r', 'age', value) + obj._age = value + + class Person: + + age = LoggedAgeAccess() # Descriptor + + def __init__(self, name, age): + self.name = name # Regular instance attribute + self.age = age # Calls the descriptor + + def birthday(self): + self.age += 1 # Calls both __get__() and __set__() + + +An interactive session shows that all access to the managed attribute *age* is +logged, but that the regular attribute *name* is not logged:: + + >>> mary = Person('Mary M', 30) # The initial age update is logged + INFO:root:Updating 'age' to 30 + >>> dave = Person('David D', 40) + INFO:root:Updating 'age' to 40 + + >>> vars(mary) # The actual data is in a private attribute + {'name': 'Mary M', '_age': 30} + >>> vars(dave) + {'name': 'David D', '_age': 40} + + >>> mary.age # Access the data and log the lookup + INFO:root:Accessing 'age' giving 30 + 30 + >>> mary.birthday() # Updates are logged as well + INFO:root:Accessing 'age' giving 30 + INFO:root:Updating 'age' to 31 + + >>> dave.name # Regular attribute lookup isn't logged + 'David D' + >>> dave.age # Only the managed attribute is logged + INFO:root:Accessing 'age' giving 40 + 40 + +One major issue with this example is the private name *_age* is hardwired in +the *LoggedAgeAccess* class. That means that each instance can only have one +logged attribute and that its name is unchangeable. In the next example, +we'll fix that problem. + + +Customized Names +---------------- + +When a class uses descriptors, it can inform each descriptor about what +variable name was used. + +In this example, the :class:`Person` class has two descriptor instances, +*name* and *age*. When the :class:`Person` class is defined, it makes a +callback to :meth:`__set_name__` in *LoggedAccess* so that the field names can +be recorded, giving each descriptor its own *public_name* and *private_name*:: + + import logging + + logging.basicConfig(level=logging.INFO) + + class LoggedAccess: + + def __set_name__(self, owner, name): + self.public_name = name + self.private_name = f'_{name}' + + def __get__(self, obj, objtype=None): + value = getattr(obj, self.private_name) + logging.info('Accessing %r giving %r', self.public_name, value) + return value + + def __set__(self, obj, value): + logging.info('Updating %r to %r', self.public_name, value) + setattr(obj, self.private_name, value) + + class Person: + + name = LoggedAccess() # First descriptor + age = LoggedAccess() # Second descriptor + + def __init__(self, name, age): + self.name = name # Calls the first descriptor + self.age = age # Calls the second descriptor + + def birthday(self): + self.age += 1 + +An interactive session shows that the :class:`Person` class has called +:meth:`__set_name__` so that the field names would be recorded. Here +we call :func:`vars` to lookup the descriptor without triggering it:: + + >>> vars(vars(Person)['name']) + {'public_name': 'name', 'private_name': '_name'} + >>> vars(vars(Person)['age']) + {'public_name': 'age', 'private_name': '_age'} + +The new class now logs access to both *name* and *age*:: + + >>> pete = Person('Peter P', 10) + INFO:root:Updating 'name' to 'Peter P' + INFO:root:Updating 'age' to 10 + >>> kate = Person('Catherine C', 20) + INFO:root:Updating 'name' to 'Catherine C' + INFO:root:Updating 'age' to 20 + +The two *Person* instances contain only the private names:: + + >>> vars(pete) + {'_name': 'Peter P', '_age': 10} + >>> vars(kate) + {'_name': 'Catherine C', '_age': 20} + + +Closing thoughts +---------------- + +A :term:`descriptor` is what we call any object that defines :meth:`__get__`, +:meth:`__set__`, or :meth:`__delete__`. + +Descriptors get invoked by the dot operator during attribute lookup. If a +descriptor is accessed indirectly with ``vars(some_class)[descriptor_name]``, +the descriptor instance is returned without invoking it. + +Descriptors only work when used as class variables. When put in instances, +they have no effect. + +The main motivation for descriptors is to provide a hook allowing objects +stored in class variables to control what happens during dotted lookup. + +Traditionally, the calling class controls what happens during lookup. +Descriptors invert that relationship and allow the data being looked-up to +have a say in the matter. + +Descriptors are used throughout the language. It is how functions turn into +bound methods. Common tools like :func:`classmethod`, :func:`staticmethod`, +:func:`property`, and :func:`functools.cached_property` are all implemented as +descriptors. + + +Complete Practical Example +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +In this example, we create a practical and powerful tool for locating +notoriously hard to find data corruption bugs. + + +Validator class +--------------- + +A validator is a descriptor for managed attribute access. Prior to storing +any data, it verifies that the new value meets various type and range +restrictions. If those restrictions aren't met, it raises an exception to +prevents data corruption at its source. + +This :class:`Validator` class is both an :term:`abstract base class` and a +managed attribute descriptor:: + + from abc import ABC, abstractmethod + + class Validator(ABC): + + def __set_name__(self, owner, name): + self.private_name = f'_{name}' + + def __get__(self, obj, objtype=None): + return getattr(obj, self.private_name) + + def __set__(self, obj, value): + self.validate(value) + setattr(obj, self.private_name, value) + + @abstractmethod + def validate(self, value): + pass + +Custom validators need to subclass from :class:`Validator` and supply a +:meth:`validate` method to test various restrictions as needed. + + +Custom validators +----------------- + +Here are three practical data validation utilities: + +1) :class:`OneOf` verifies that a value is one of a restricted set of options. + +2) :class:`Number` verifies that a value is either an :class:`int` or + :class:`float`. Optionally, it verifies that a value is between a given + minimum or maximum. + +3) :class:`String` verifies that a value is a :class:`str`. Optionally, it + validates a given minimum or maximum length. Optionally, it can test for + another predicate as well. + +:: + + class OneOf(Validator): + + def __init__(self, *options): + self.options = set(options) + + def validate(self, value): + if value not in self.options: + raise ValueError(f'Expected {value!r} to be one of {self.options!r}') + + class Number(Validator): + + def __init__(self, minvalue=None, maxvalue=None): + self.minvalue = minvalue + self.maxvalue = maxvalue + + def validate(self, value): + if not isinstance(value, (int, float)): + raise TypeError(f'Expected {value!r} to be an int or float') + if self.minvalue is not None and value < self.minvalue: + raise ValueError( + f'Expected {value!r} to be at least {self.minvalue!r}' + ) + if self.maxvalue is not None and value > self.maxvalue: + raise ValueError( + f'Expected {value!r} to be no more than {self.maxvalue!r}' + ) + + class String(Validator): + + def __init__(self, minsize=None, maxsize=None, predicate=None): + self.minsize = minsize + self.maxsize = maxsize + self.predicate = predicate + + def validate(self, value): + if not isinstance(value, str): + raise TypeError(f'Expected {value!r} to be an str') + if self.minsize is not None and len(value) < self.minsize: + raise ValueError( + f'Expected {value!r} to be no smaller than {self.minsize!r}' + ) + if self.maxsize is not None and len(value) > self.maxsize: + raise ValueError( + f'Expected {value!r} to be no bigger than {self.maxsize!r}' + ) + if self.predicate is not None and not self.predicate(value): + raise ValueError( + f'Expected {self.predicate} to be true for {value!r}' + ) + + +Practical use +------------- + +Here's how the data validators can be used in a real class:: + + class Component: + + name = String(minsize=3, maxsize=10, predicate=str.isupper) + kind = OneOf('plastic', 'metal') + quantity = Number(minvalue=0) + + def __init__(self, name, kind, quantity): + self.name = name + self.kind = kind + self.quantity = quantity + +The descriptors prevent invalid instances from being created:: + + Component('WIDGET', 'metal', 5) # Allowed. + Component('Widget', 'metal', 5) # Blocked: 'Widget' is not all uppercase + Component('WIDGET', 'metle', 5) # Blocked: 'metle' is misspelled + Component('WIDGET', 'metal', -5) # Blocked: -5 is negative + Component('WIDGET', 'metal', 'V') # Blocked: 'V' isn't a number + + +Technical Tutorial +^^^^^^^^^^^^^^^^^^ + +What follows is a more technical tutorial for the mechanics and details of how +descriptors work. + + Abstract -------- @@ -39,10 +450,10 @@ Where this occurs in the precedence chain depends on which descriptor methods were defined. Descriptors are a powerful, general purpose protocol. They are the mechanism -behind properties, methods, static methods, class methods, and :func:`super()`. -They are used throughout Python itself to implement the new style classes -introduced in version 2.2. Descriptors simplify the underlying C-code and offer -a flexible set of new tools for everyday Python programs. +behind properties, methods, static methods, class methods, and +:func:`super()`. They are used throughout Python itself. Descriptors +simplify the underlying C code and offer a flexible set of new tools for +everyday Python programs. Descriptor Protocol @@ -132,11 +543,29 @@ The implementation details are in :c:func:`super_getattro()` in The details above show that the mechanism for descriptors is embedded in the :meth:`__getattribute__()` methods for :class:`object`, :class:`type`, and :func:`super`. Classes inherit this machinery when they derive from -:class:`object` or if they have a meta-class providing similar functionality. +:class:`object` or if they have a metaclass providing similar functionality. Likewise, classes can turn-off descriptor invocation by overriding :meth:`__getattribute__()`. +Automatic Name Notification +--------------------------- + +Sometimes it is desirable for a descriptor to know what class variable name it +was assigned to. When a new class is created, the :class:`type` metaclass +scans the dictionary of the new class. If any of the entries are descriptors +and if they define :meth:`__set_name__`, that method is called with two +arguments. The *owner* is the class where the descriptor is used, the *name* +is class variable the descriptor was assigned to. + +The implementation details are in :c:func:`type_new()` and +:c:func:`set_names()` in :source:`Objects/typeobject.c`. + +Since the update logic is in :meth:`type.__new__`, notifications only take +place at the time of class creation. If descriptors are added to the class +afterwards, :meth:`__set_name__` will need to be called manually. + + Descriptor Example ------------------ @@ -154,7 +583,7 @@ descriptor is useful for monitoring just a few chosen attributes:: self.val = initval self.name = name - def __get__(self, obj, objtype): + def __get__(self, obj, objtype=None): print('Retrieving', self.name) return self.val @@ -162,11 +591,11 @@ descriptor is useful for monitoring just a few chosen attributes:: print('Updating', self.name) self.val = val - >>> class MyClass: - ... x = RevealAccess(10, 'var "x"') - ... y = 5 - ... - >>> m = MyClass() + class B: + x = RevealAccess(10, 'var "x"') + y = 5 + + >>> m = B() >>> m.x Retrieving var "x" 10 @@ -251,12 +680,13 @@ affect existing client code accessing the attribute directly. The solution is to wrap access to the value attribute in a property data descriptor:: class Cell: - . . . - def getvalue(self): + ... + + @property + def value(self): "Recalculate the cell before returning value" self.recalc() return self._value - value = property(getvalue) Functions and Methods @@ -278,42 +708,48 @@ non-data descriptors which return bound methods when they are invoked from an object. In pure Python, it works like this:: class Function: - . . . + ... + def __get__(self, obj, objtype=None): "Simulate func_descr_get() in Objects/funcobject.c" if obj is None: return self return types.MethodType(self, obj) -Running the interpreter shows how the function descriptor works in practice:: +Running the following in class in the interpreter shows how the function +descriptor works in practice:: - >>> class D: - ... def f(self, x): - ... return x - ... - >>> d = D() + class D: + def f(self, x): + return x + +Access through the class dictionary does not invoke :meth:`__get__`. Instead, +it just returns the underlying function object:: - # Access through the class dictionary does not invoke __get__. - # It just returns the underlying function object. >>> D.__dict__['f'] - # Dotted access from a class calls __get__() which just returns - # the underlying function unchanged. +Dotted access from a class calls :meth:`__get__` which just returns the +underlying function unchanged:: + >>> D.f - # The function has a __qualname__ attribute to support introspection +The function has a :term:`qualified name` attribute to support introspection:: + >>> D.f.__qualname__ 'D.f' - # Dotted access from an instance calls __get__() which returns the - # function wrapped in a bound method object +Dotted access from an instance calls :meth:`__get__` which returns a bound +method object:: + + >>> d = D() >>> d.f > - # Internally, the bound method stores the underlying function and - # the bound instance. +Internally, the bound method stores the underlying function and the bound +instance:: + >>> d.f.__func__ >>> d.f.__self__ @@ -328,20 +764,20 @@ patterns of binding functions into methods. To recap, functions have a :meth:`__get__` method so that they can be converted to a method when accessed as attributes. The non-data descriptor transforms an -``obj.f(*args)`` call into ``f(obj, *args)``. Calling ``klass.f(*args)`` +``obj.f(*args)`` call into ``f(obj, *args)``. Calling ``cls.f(*args)`` becomes ``f(*args)``. This chart summarizes the binding and its two most useful variants: +-----------------+----------------------+------------------+ | Transformation | Called from an | Called from a | - | | Object | Class | + | | object | class | +=================+======================+==================+ | function | f(obj, \*args) | f(\*args) | +-----------------+----------------------+------------------+ | staticmethod | f(\*args) | f(\*args) | +-----------------+----------------------+------------------+ - | classmethod | f(type(obj), \*args) | f(klass, \*args) | + | classmethod | f(type(obj), \*args) | f(cls, \*args) | +-----------------+----------------------+------------------+ Static methods return the underlying function without changes. Calling either @@ -365,11 +801,11 @@ It can be called either from an object or the class: ``s.erf(1.5) --> .9332`` o Since staticmethods return the underlying function with no changes, the example calls are unexciting:: - >>> class E: - ... def f(x): - ... print(x) - ... f = staticmethod(f) - ... + class E: + @staticmethod + def f(x): + print(x) + >>> E.f(3) 3 >>> E().f(3) @@ -391,32 +827,33 @@ Unlike static methods, class methods prepend the class reference to the argument list before calling the function. This format is the same for whether the caller is an object or a class:: - >>> class E: - ... def f(klass, x): - ... return klass.__name__, x - ... f = classmethod(f) - ... - >>> print(E.f(3)) - ('E', 3) - >>> print(E().f(3)) - ('E', 3) + class F: + @classmethod + def f(cls, x): + return cls.__name__, x + + >>> print(F.f(3)) + ('F', 3) + >>> print(F().f(3)) + ('F', 3) This behavior is useful whenever the function only needs to have a class -reference and does not care about any underlying data. One use for classmethods -is to create alternate class constructors. In Python 2.3, the classmethod +reference and does not care about any underlying data. One use for +classmethods is to create alternate class constructors. The classmethod :func:`dict.fromkeys` creates a new dictionary from a list of keys. The pure Python equivalent is:: class Dict: - . . . - def fromkeys(klass, iterable, value=None): + ... + + @classmethod + def fromkeys(cls, iterable, value=None): "Emulate dict_fromkeys() in Objects/dictobject.c" - d = klass() + d = cls() for key in iterable: d[key] = value return d - fromkeys = classmethod(fromkeys) Now a new dictionary of unique keys can be constructed like this:: @@ -432,10 +869,9 @@ Using the non-data descriptor protocol, a pure Python version of def __init__(self, f): self.f = f - def __get__(self, obj, klass=None): - if klass is None: - klass = type(obj) + def __get__(self, obj, cls=None): + if cls is None: + cls = type(obj) def newfunc(*args): - return self.f(klass, *args) + return self.f(cls, *args) return newfunc - diff --git a/Doc/tools/susp-ignored.csv b/Doc/tools/susp-ignored.csv index e03c68fa98a0be..80e77be45f95b1 100644 --- a/Doc/tools/susp-ignored.csv +++ b/Doc/tools/susp-ignored.csv @@ -23,6 +23,9 @@ howto/curses,,:blue,"2:green, 3:yellow, 4:blue, 5:magenta, 6:cyan, and 7:white. howto/curses,,:magenta,"2:green, 3:yellow, 4:blue, 5:magenta, 6:cyan, and 7:white. The" howto/curses,,:cyan,"2:green, 3:yellow, 4:blue, 5:magenta, 6:cyan, and 7:white. The" howto/curses,,:white,"2:green, 3:yellow, 4:blue, 5:magenta, 6:cyan, and 7:white. The" +howto/descriptor,,:root,"INFO:root" +howto/descriptor,,:Updating,"root:Updating" +howto/descriptor,,:Accessing,"root:Accessing" howto/instrumentation,,::,python$target:::function-entry howto/instrumentation,,:function,python$target:::function-entry howto/instrumentation,,::,python$target:::function-return From c437fe39cf5318f27f3381a983fbf320f65064bc Mon Sep 17 00:00:00 2001 From: "Miss Skeleton (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 23 Oct 2020 14:38:05 -0700 Subject: [PATCH 0630/1314] [3.9] bpo-40592: shutil.which will not return None anymore if ; is the last char in PATHEXT (GH-20088) (GH-22912) shutil.which will not return None anymore for empty str in PATHEXT Empty PATHEXT will now be defaulted to _WIN_DEFAULT_PATHEXT (cherry picked from commit da6f098188c9825f10ae60db8987056b3a54c2e8) Co-authored-by: Christopher Marchfelder --- Lib/shutil.py | 7 ++++++- Lib/test/test_shutil.py | 17 +++++++++++++++++ .../2020-05-14-16-01-34.bpo-40592.Cmk855.rst | 1 + 3 files changed, 24 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Library/2020-05-14-16-01-34.bpo-40592.Cmk855.rst diff --git a/Lib/shutil.py b/Lib/shutil.py index a4ce2c0290bc93..223e9a8a705064 100644 --- a/Lib/shutil.py +++ b/Lib/shutil.py @@ -53,6 +53,9 @@ _USE_CP_SENDFILE = hasattr(os, "sendfile") and sys.platform.startswith("linux") _HAS_FCOPYFILE = posix and hasattr(posix, "_fcopyfile") # macOS +# CMD defaults in Windows 10 +_WIN_DEFAULT_PATHEXT = ".COM;.EXE;.BAT;.CMD;.VBS;.JS;.WS;.MSC" + __all__ = ["copyfileobj", "copyfile", "copymode", "copystat", "copy", "copy2", "copytree", "move", "rmtree", "Error", "SpecialFileError", "ExecError", "make_archive", "get_archive_formats", @@ -1415,7 +1418,9 @@ def which(cmd, mode=os.F_OK | os.X_OK, path=None): path.insert(0, curdir) # PATHEXT is necessary to check on Windows. - pathext = os.environ.get("PATHEXT", "").split(os.pathsep) + pathext_source = os.getenv("PATHEXT") or _WIN_DEFAULT_PATHEXT + pathext = [ext for ext in pathext_source.split(os.pathsep) if ext] + if use_bytes: pathext = [os.fsencode(ext) for ext in pathext] # See if the given file matches any of the expected path extensions. diff --git a/Lib/test/test_shutil.py b/Lib/test/test_shutil.py index e56b337083c8f2..e19af64be0e1a2 100644 --- a/Lib/test/test_shutil.py +++ b/Lib/test/test_shutil.py @@ -1848,6 +1848,23 @@ def test_pathext(self): rv = shutil.which(program, path=self.temp_dir) self.assertEqual(rv, temp_filexyz.name) + # Issue 40592: See https://bugs.python.org/issue40592 + @unittest.skipUnless(sys.platform == "win32", 'test specific to Windows') + def test_pathext_with_empty_str(self): + ext = ".xyz" + temp_filexyz = tempfile.NamedTemporaryFile(dir=self.temp_dir, + prefix="Tmp2", suffix=ext) + self.addCleanup(temp_filexyz.close) + + # strip path and extension + program = os.path.basename(temp_filexyz.name) + program = os.path.splitext(program)[0] + + with support.EnvironmentVarGuard() as env: + env['PATHEXT'] = f"{ext};" # note the ; + rv = shutil.which(program, path=self.temp_dir) + self.assertEqual(rv, temp_filexyz.name) + class TestWhichBytes(TestWhich): def setUp(self): diff --git a/Misc/NEWS.d/next/Library/2020-05-14-16-01-34.bpo-40592.Cmk855.rst b/Misc/NEWS.d/next/Library/2020-05-14-16-01-34.bpo-40592.Cmk855.rst new file mode 100644 index 00000000000000..3211a1bc345fa5 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2020-05-14-16-01-34.bpo-40592.Cmk855.rst @@ -0,0 +1 @@ +:func:`shutil.which` now ignores empty entries in :envvar:`PATHEXT` instead of treating them as a match. From 11ab4fcbcefcd9dd3af509d25f3f408d2fc01eec Mon Sep 17 00:00:00 2001 From: "Miss Skeleton (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 23 Oct 2020 14:48:15 -0700 Subject: [PATCH 0631/1314] build(deps): bump actions/cache from v1 to v2.1.2 (GH-22919) Bumps [actions/cache](https://github.com/actions/cache) from v1 to v2.1.2.
Release notes

Sourced from actions/cache's releases.

v2.1.2

  • Adds input to limit the chunk upload size, useful for self-hosted runners with slower upload speeds
  • No-op when executing on GHES
Commits

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: GH- (dependabot-automerge-start) [//]: GH- (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
Automerge-Triggered-By: GH:Mariatta (cherry picked from commit cd0edbc716d64ccd437d97af1eaa3b7a6f0f6de5) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/build.yml | 2 +- .github/workflows/coverage.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 2cd2fbb6863364..9e63b68576303b 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -104,7 +104,7 @@ jobs: run: sudo ./.github/workflows/posix-deps-apt.sh - name: 'Restore OpenSSL build' id: cache-openssl - uses: actions/cache@v1 + uses: actions/cache@v2.1.2 with: path: ./multissl/openssl/${{ env.OPENSSL_VER }} key: ${{ runner.os }}-multissl-openssl-${{ env.OPENSSL_VER }} diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index 4f46cbf1100e91..d66c02b51b15e5 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -32,7 +32,7 @@ jobs: run: sudo ./.github/workflows/posix-deps-apt.sh - name: 'Restore OpenSSL build' id: cache-openssl - uses: actions/cache@v1 + uses: actions/cache@v2.1.2 with: path: ./multissl/openssl/${{ env.OPENSSL_VER }} key: ${{ runner.os }}-multissl-openssl-${{ env.OPENSSL_VER }} From 750a8a9568742917b1f62f30ed3c54e26088a5c2 Mon Sep 17 00:00:00 2001 From: "Miss Skeleton (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 23 Oct 2020 14:51:04 -0700 Subject: [PATCH 0632/1314] build(deps): bump actions/upload-artifact from v1 to v2.2.0 (GH-22920) Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from v1 to v2.2.0.
Release notes

Sourced from actions/upload-artifact's releases.

v2.2.0

  • Support for artifact retention
Commits

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: GH- (dependabot-automerge-start) [//]: GH- (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
Automerge-Triggered-By: GH:Mariatta (cherry picked from commit a3c4ceffe61df89cc9ce5c437cae0276521dc83b) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/doc.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/doc.yml b/.github/workflows/doc.yml index d481ea279d796f..455ad02f7ed3ed 100644 --- a/.github/workflows/doc.yml +++ b/.github/workflows/doc.yml @@ -36,7 +36,7 @@ jobs: - name: 'Build documentation' run: xvfb-run make -C Doc/ PYTHON=../python SPHINXOPTS="-q -W -j4" doctest suspicious html - name: 'Upload' - uses: actions/upload-artifact@v1 + uses: actions/upload-artifact@v2.2.0 with: name: doc-html path: Doc/build/html From dc33f798139016961fba33b37c792c690399b2b6 Mon Sep 17 00:00:00 2001 From: Weiliang Li Date: Sat, 24 Oct 2020 09:11:10 +0900 Subject: [PATCH 0633/1314] bpo-41950: Typo in Python 3.9 what's new page (GH-22573) --- Doc/whatsnew/3.9.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/whatsnew/3.9.rst b/Doc/whatsnew/3.9.rst index da0718561537b1..1a37f16ea2b09a 100644 --- a/Doc/whatsnew/3.9.rst +++ b/Doc/whatsnew/3.9.rst @@ -1177,7 +1177,7 @@ CPython bytecode changes * ``COMPARE_OP`` for rich comparisons * ``IS_OP`` for 'is' and 'is not' tests - * ``CONTAINS_OP`` for 'in' and 'is not' tests + * ``CONTAINS_OP`` for 'in' and 'not in' tests * ``JUMP_IF_NOT_EXC_MATCH`` for checking exceptions in 'try-except' statements. From c17f63fae57dc02e78bd6931b8fb6c6c2f9d4d81 Mon Sep 17 00:00:00 2001 From: "Miss Skeleton (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 23 Oct 2020 19:01:35 -0700 Subject: [PATCH 0634/1314] bpo-19072: Update descriptor howto for decorator chaining (GH-22934) (GH-22935) --- Doc/howto/descriptor.rst | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/Doc/howto/descriptor.rst b/Doc/howto/descriptor.rst index 4a53b9e6156922..4e9fad30d31c4f 100644 --- a/Doc/howto/descriptor.rst +++ b/Doc/howto/descriptor.rst @@ -872,6 +872,16 @@ Using the non-data descriptor protocol, a pure Python version of def __get__(self, obj, cls=None): if cls is None: cls = type(obj) - def newfunc(*args): - return self.f(cls, *args) - return newfunc + if hasattr(obj, '__get__'): + return self.f.__get__(cls) + return types.MethodType(self.f, cls) + +The code path for ``hasattr(obj, '__get__')`` was added in Python 3.9 and +makes it possible for :func:`classmethod` to support chained decorators. +For example, a classmethod and property could be chained together:: + + class G: + @classmethod + @property + def __doc__(cls): + return f'A doc for {cls.__name__!r}' From 4efd2defb899c5c45334814234c842f8f513879e Mon Sep 17 00:00:00 2001 From: "Miss Skeleton (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 24 Oct 2020 16:53:34 -0700 Subject: [PATCH 0635/1314] bpo-33987: Use ttk Label on IDLE statusbar (GH-22941) (cherry picked from commit e53e54425d9b7b9b7b082817da104d60bb25e3a2) Co-authored-by: Mark Roseman --- Lib/idlelib/statusbar.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Lib/idlelib/statusbar.py b/Lib/idlelib/statusbar.py index ae52a56368c82a..755fafb0ac6438 100644 --- a/Lib/idlelib/statusbar.py +++ b/Lib/idlelib/statusbar.py @@ -1,5 +1,4 @@ -from tkinter import Label -from tkinter.ttk import Frame +from tkinter.ttk import Label, Frame class MultiStatusBar(Frame): From c2c44774893770da6ef4709828d398d73beffc56 Mon Sep 17 00:00:00 2001 From: "Miss Skeleton (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 24 Oct 2020 17:33:01 -0700 Subject: [PATCH 0636/1314] [doc] Fix link to abc.ABCMeta.register in Glossary (GH-22932) (cherry picked from commit e01e442125bbc98e6dab66f38ecc6c45f69e6587) Co-authored-by: Andre Delfino --- Doc/glossary.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/glossary.rst b/Doc/glossary.rst index 189d49ee0d6279..778fd404381575 100644 --- a/Doc/glossary.rst +++ b/Doc/glossary.rst @@ -1025,7 +1025,7 @@ Glossary :meth:`index`, :meth:`__contains__`, and :meth:`__reversed__`. Types that implement this expanded interface can be registered explicitly using - :func:`~abc.register`. + :func:`~abc.ABCMeta.register`. single dispatch A form of :term:`generic function` dispatch where the implementation is From 2d493893c7aa9af633c4ebeb56ecce42e3a82e9f Mon Sep 17 00:00:00 2001 From: "Miss Skeleton (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 24 Oct 2020 18:08:17 -0700 Subject: [PATCH 0637/1314] bpo-33987: Use master ttk Frame for IDLE config dialog (GH-22943) (cherry picked from commit c579ad14d3b5bb9a45d7b9cc708eaf0bf4884c50) Co-authored-by: Mark Roseman --- Lib/idlelib/configdialog.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/Lib/idlelib/configdialog.py b/Lib/idlelib/configdialog.py index 82596498d34611..a84e1c5668f99f 100644 --- a/Lib/idlelib/configdialog.py +++ b/Lib/idlelib/configdialog.py @@ -67,7 +67,6 @@ def __init__(self, parent, title='', *, _htest=False, _utest=False): if not _utest: self.withdraw() - self.configure(borderwidth=5) self.title(title or 'IDLE Preferences') x = parent.winfo_rootx() + 20 y = parent.winfo_rooty() + (30 if not _htest else 150) @@ -97,6 +96,7 @@ def create_widgets(self): """Create and place widgets for tabbed dialog. Widgets Bound to self: + frame: encloses all other widgets note: Notebook highpage: HighPage fontpage: FontPage @@ -109,7 +109,9 @@ def create_widgets(self): load_configs: Load pages except for extensions. activate_config_changes: Tell editors to reload. """ - self.note = note = Notebook(self) + self.frame = frame = Frame(self, padding="5px") + self.frame.grid(sticky="nwes") + self.note = note = Notebook(frame) self.highpage = HighPage(note) self.fontpage = FontPage(note, self.highpage) self.keyspage = KeysPage(note) @@ -148,7 +150,7 @@ def create_action_buttons(self): padding_args = {} else: padding_args = {'padding': (6, 3)} - outer = Frame(self, padding=2) + outer = Frame(self.frame, padding=2) buttons_frame = Frame(outer, padding=2) self.buttons = {} for txt, cmd in ( @@ -687,7 +689,7 @@ class HighPage(Frame): def __init__(self, master): super().__init__(master) - self.cd = master.master + self.cd = master.winfo_toplevel() self.style = Style(master) self.create_page_highlight() self.load_theme_cfg() @@ -1346,7 +1348,7 @@ class KeysPage(Frame): def __init__(self, master): super().__init__(master) - self.cd = master.master + self.cd = master.winfo_toplevel() self.create_page_keys() self.load_key_cfg() From 427cb0aa78813b89a3f100073bf7d70a53510f57 Mon Sep 17 00:00:00 2001 From: "Miss Skeleton (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 24 Oct 2020 19:00:14 -0700 Subject: [PATCH 0638/1314] bpo-42127: Document effect of cached_property on key-sharing dictionaries (GH-22930) (GH-22955) --- Doc/library/functools.rst | 33 ++++++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/Doc/library/functools.rst b/Doc/library/functools.rst index 14aa184e2cd14c..4869b67cb94164 100644 --- a/Doc/library/functools.rst +++ b/Doc/library/functools.rst @@ -73,16 +73,31 @@ The :mod:`functools` module defines the following functions: def variance(self): return statistics.variance(self._data) - .. versionadded:: 3.8 + Note, this decorator interferes with the operation of :pep:`412` + key-sharing dictionaries. This means that instance dictionaries + can take more space than usual. - .. note:: + Also, this decorator requires that the ``__dict__`` attribute on each instance + be a mutable mapping. This means it will not work with some types, such as + metaclasses (since the ``__dict__`` attributes on type instances are + read-only proxies for the class namespace), and those that specify + ``__slots__`` without including ``__dict__`` as one of the defined slots + (as such classes don't provide a ``__dict__`` attribute at all). + + If a mutable mapping is not available or if space-efficient key sharing + is desired, an effect similar to :func:`cached_property` can be achieved + by a stacking :func:`property` on top of :func:`cache`:: - This decorator requires that the ``__dict__`` attribute on each instance - be a mutable mapping. This means it will not work with some types, such as - metaclasses (since the ``__dict__`` attributes on type instances are - read-only proxies for the class namespace), and those that specify - ``__slots__`` without including ``__dict__`` as one of the defined slots - (as such classes don't provide a ``__dict__`` attribute at all). + class DataSet: + def __init__(self, sequence_of_numbers): + self._data = sequence_of_numbers + + @property + @cache + def stdev(self): + return statistics.stdev(self._data) + + .. versionadded:: 3.8 .. function:: cmp_to_key(func) @@ -651,4 +666,4 @@ callable, weak referencable, and can have attributes. There are some important differences. For instance, the :attr:`~definition.__name__` and :attr:`__doc__` attributes are not created automatically. Also, :class:`partial` objects defined in classes behave like static methods and do not transform into bound methods -during instance attribute look-up. \ No newline at end of file +during instance attribute look-up. From 2cccc29eaf20694006c03af0f4740abdf8ae5579 Mon Sep 17 00:00:00 2001 From: "Miss Skeleton (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 24 Oct 2020 19:53:41 -0700 Subject: [PATCH 0639/1314] bpo-29981: Add examples and update index for set, dict, and generator comprehensions'(GH-20272) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Rémi Lapeyre (cherry picked from commit 2d55aa9e37c9c84f4f6a8135d0326da0bcd8f38b) Co-authored-by: Florian Dahlitz --- Doc/glossary.rst | 12 ++++++++++++ Doc/library/stdtypes.rst | 14 ++++++++++++++ Doc/reference/expressions.rst | 4 ++++ Misc/ACKS | 1 + 4 files changed, 31 insertions(+) diff --git a/Doc/glossary.rst b/Doc/glossary.rst index 778fd404381575..847500e556056e 100644 --- a/Doc/glossary.rst +++ b/Doc/glossary.rst @@ -309,6 +309,12 @@ Glossary keys can be any object with :meth:`__hash__` and :meth:`__eq__` methods. Called a hash in Perl. + dictionary comprehension + A compact way to process all or part of the elements in an iterable and + return a dictionary with the results. ``results = {n: n ** 2 for n in + range(10)}`` generates a dictionary containing key ``n`` mapped to + value ``n ** 2``. See :ref:`comprehensions`. + dictionary view The objects returned from :meth:`dict.keys`, :meth:`dict.values`, and :meth:`dict.items` are called dictionary views. They provide a dynamic @@ -1027,6 +1033,12 @@ Glossary interface can be registered explicitly using :func:`~abc.ABCMeta.register`. + set comprehension + A compact way to process all or part of the elements in an iterable and + return a set with the results. ``results = {c for c in 'abracadabra' if + c not in 'abc'}`` generates the set of strings ``{'r', 'd'}``. See + :ref:`comprehensions`. + single dispatch A form of :term:`generic function` dispatch where the implementation is chosen based on the type of a single argument. diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst index c3f5c04aac7d98..1de48e13e271f2 100644 --- a/Doc/library/stdtypes.rst +++ b/Doc/library/stdtypes.rst @@ -4119,6 +4119,12 @@ The constructors for both classes work the same: objects. If *iterable* is not specified, a new empty set is returned. + Sets can be created by several means: + + * Use a comma-separated list of elements within braces: ``{'jack', 'sjoerd'}`` + * Use a set comprehension: ``{c for c in 'abracadabra' if c not in 'abc'}`` + * Use the type constructor: ``set()``, ``set('foobar')``, ``set(['a', 'b', 'foo'])`` + Instances of :class:`set` and :class:`frozenset` provide the following operations: @@ -4311,6 +4317,14 @@ pairs within braces, for example: ``{'jack': 4098, 'sjoerd': 4127}`` or ``{4098: Return a new dictionary initialized from an optional positional argument and a possibly empty set of keyword arguments. + Dictionaries can be created by several means: + + * Use a comma-separated list of ``key: value`` pairs within braces: + ``{'jack': 4098, 'sjoerd': 4127}`` or ``{4098: 'jack', 4127: 'sjoerd'}`` + * Use a dict comprehension: ``{}``, ``{x: x ** 2 for x in range(10)}`` + * Use the type constructor: ``dict()``, + ``dict([('foo', 100), ('bar', 200)])``, ``dict(foo=100, bar=200)`` + If no positional argument is given, an empty dictionary is created. If a positional argument is given and it is a mapping object, a dictionary is created with the same key-value pairs as the mapping object. Otherwise, diff --git a/Doc/reference/expressions.rst b/Doc/reference/expressions.rst index f1f19c3f02d390..938a9732f5a250 100644 --- a/Doc/reference/expressions.rst +++ b/Doc/reference/expressions.rst @@ -162,6 +162,8 @@ ambiguities and allow common typos to pass uncaught. Displays for lists, sets and dictionaries ----------------------------------------- +.. index:: single: comprehensions + For constructing a list, a set or a dictionary Python provides special syntax called "displays", each of them in two flavors: @@ -260,6 +262,7 @@ Set displays .. index:: pair: set; display + pair: set; comprehensions object: set single: {} (curly brackets); set expression single: , (comma); expression list @@ -287,6 +290,7 @@ Dictionary displays .. index:: pair: dictionary; display + pair: dictionary; comprehensions key, datum, key/datum pair object: dictionary single: {} (curly brackets); dictionary expression diff --git a/Misc/ACKS b/Misc/ACKS index f06fad7926d461..9ad9dffe22aea4 100644 --- a/Misc/ACKS +++ b/Misc/ACKS @@ -379,6 +379,7 @@ Brian Curtin Jason Curtis Hakan Celik Paul Dagnelie +Florian Dahlitz Lisandro Dalcin Darren Dale Andrew Dalke From 9cf26b00e42787bc668c62f1b5dde814f8307259 Mon Sep 17 00:00:00 2001 From: "Miss Skeleton (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 24 Oct 2020 20:36:55 -0700 Subject: [PATCH 0640/1314] bpo-33987: Add master ttk Frame to IDLE search dialogs (GH-22942) (cherry picked from commit 5df6c99cb450fe2f30be681dbf68cd1d34d3bbe4) Co-authored-by: Mark Roseman --- Lib/idlelib/NEWS.txt | 3 +++ Lib/idlelib/idle_test/test_searchbase.py | 14 +++++++------- Lib/idlelib/searchbase.py | 19 ++++++++++++------- .../2020-10-24-21-27-37.bpo-33987.fIh9JL.rst | 3 +++ 4 files changed, 25 insertions(+), 14 deletions(-) create mode 100644 Misc/NEWS.d/next/IDLE/2020-10-24-21-27-37.bpo-33987.fIh9JL.rst diff --git a/Lib/idlelib/NEWS.txt b/Lib/idlelib/NEWS.txt index 5ea33226cc0c3a..a7f74814d72516 100644 --- a/Lib/idlelib/NEWS.txt +++ b/Lib/idlelib/NEWS.txt @@ -3,6 +3,9 @@ Released on 2020-12-07? ====================================== +bpo-33987: Mostly finish using ttk widgets, mainly for editor, +settings, and searches. Some patches by Mark Roseman. + bpo-41775: Make 'IDLE Shell' the shell title. bpo-35764: Rewrite the Calltips doc section. diff --git a/Lib/idlelib/idle_test/test_searchbase.py b/Lib/idlelib/idle_test/test_searchbase.py index aee0c4c69929a6..8c9c410ebaf47c 100644 --- a/Lib/idlelib/idle_test/test_searchbase.py +++ b/Lib/idlelib/idle_test/test_searchbase.py @@ -76,7 +76,7 @@ def test_create_widgets(self): def test_make_entry(self): equal = self.assertEqual self.dialog.row = 0 - self.dialog.top = self.root + self.dialog.frame = Frame(self.root) entry, label = self.dialog.make_entry("Test:", 'hello') equal(label['text'], 'Test:') @@ -89,7 +89,7 @@ def test_make_entry(self): equal(self.dialog.row, 1) def test_create_entries(self): - self.dialog.top = self.root + self.dialog.frame = Frame(self.root) self.dialog.row = 0 self.engine.setpat('hello') self.dialog.create_entries() @@ -97,7 +97,7 @@ def test_create_entries(self): def test_make_frame(self): self.dialog.row = 0 - self.dialog.top = self.root + self.dialog.frame = Frame(self.root) frame, label = self.dialog.make_frame() self.assertEqual(label, '') self.assertEqual(str(type(frame)), "") @@ -108,7 +108,7 @@ def test_make_frame(self): self.assertEqual(label['text'], 'testlabel') def btn_test_setup(self, meth): - self.dialog.top = self.root + self.dialog.frame = Frame(self.root) self.dialog.row = 0 return meth() @@ -140,13 +140,13 @@ def test_create_other_buttons(self): self.assertEqual(var.get(), state) def test_make_button(self): - self.dialog.top = self.root - self.dialog.buttonframe = Frame(self.dialog.top) + self.dialog.frame = Frame(self.root) + self.dialog.buttonframe = Frame(self.dialog.frame) btn = self.dialog.make_button('Test', self.dialog.close) self.assertEqual(btn['text'], 'Test') def test_create_command_buttons(self): - self.dialog.top = self.root + self.dialog.frame = Frame(self.root) self.dialog.create_command_buttons() # Look for close button command in buttonframe closebuttoncommand = '' diff --git a/Lib/idlelib/searchbase.py b/Lib/idlelib/searchbase.py index 6fba0b8e583f2b..fbef87aa2d3d04 100644 --- a/Lib/idlelib/searchbase.py +++ b/Lib/idlelib/searchbase.py @@ -33,6 +33,7 @@ def __init__(self, root, engine): '''Initialize root, engine, and top attributes. top (level widget): set in create_widgets() called from open(). + frame: container for all widgets in dialog. text (Text searched): set in open(), only used in subclasses(). ent (ry): created in make_entry() called from create_entry(). row (of grid): 0 in create_widgets(), +1 in make_entry/frame(). @@ -83,10 +84,14 @@ def create_widgets(self): top.wm_title(self.title) top.wm_iconname(self.icon) self.top = top + self.frame = Frame(top, padding="5px") + self.frame.grid(sticky="nwes") + top.grid_columnconfigure(0, weight=100) + top.grid_rowconfigure(0, weight=100) self.row = 0 - self.top.grid_columnconfigure(0, pad=2, weight=0) - self.top.grid_columnconfigure(1, pad=2, minsize=100, weight=100) + self.frame.grid_columnconfigure(0, pad=2, weight=0) + self.frame.grid_columnconfigure(1, pad=2, minsize=100, weight=100) self.create_entries() # row 0 (and maybe 1), cols 0, 1 self.create_option_buttons() # next row, cols 0, 1 @@ -99,9 +104,9 @@ def make_entry(self, label_text, var): entry - gridded labeled Entry for text entry. label - Label widget, returned for testing. ''' - label = Label(self.top, text=label_text) + label = Label(self.frame, text=label_text) label.grid(row=self.row, column=0, sticky="nw") - entry = Entry(self.top, textvariable=var, exportselection=0) + entry = Entry(self.frame, textvariable=var, exportselection=0) entry.grid(row=self.row, column=1, sticky="nwe") self.row = self.row + 1 return entry, label @@ -117,11 +122,11 @@ def make_frame(self,labeltext=None): label - Label widget, returned for testing. ''' if labeltext: - label = Label(self.top, text=labeltext) + label = Label(self.frame, text=labeltext) label.grid(row=self.row, column=0, sticky="nw") else: label = '' - frame = Frame(self.top) + frame = Frame(self.frame) frame.grid(row=self.row, column=1, columnspan=1, sticky="nwe") self.row = self.row + 1 return frame, label @@ -171,7 +176,7 @@ def make_button(self, label, command, isdef=0): def create_command_buttons(self): "Place buttons in vertical command frame gridded on right." - f = self.buttonframe = Frame(self.top) + f = self.buttonframe = Frame(self.frame) f.grid(row=0,column=2,padx=2,pady=2,ipadx=2,ipady=2) b = self.make_button("Close", self.close) diff --git a/Misc/NEWS.d/next/IDLE/2020-10-24-21-27-37.bpo-33987.fIh9JL.rst b/Misc/NEWS.d/next/IDLE/2020-10-24-21-27-37.bpo-33987.fIh9JL.rst new file mode 100644 index 00000000000000..1e67edc03c658d --- /dev/null +++ b/Misc/NEWS.d/next/IDLE/2020-10-24-21-27-37.bpo-33987.fIh9JL.rst @@ -0,0 +1,3 @@ +Mostly finish using ttk widgets, mainly for editor, settings, +and searches. Some patches by Mark Roseman. + From 3d43f1dce3e9aaded38f9a2c73e3c66acf85505c Mon Sep 17 00:00:00 2001 From: "Miss Skeleton (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 24 Oct 2020 20:39:15 -0700 Subject: [PATCH 0641/1314] Second round of updates to the descriptor howto guide (GH-22946) (GH-22958) --- Doc/howto/descriptor.rst | 252 ++++++++++++++++++++++++--------------- 1 file changed, 156 insertions(+), 96 deletions(-) diff --git a/Doc/howto/descriptor.rst b/Doc/howto/descriptor.rst index 4e9fad30d31c4f..bed4078e3a3a9d 100644 --- a/Doc/howto/descriptor.rst +++ b/Doc/howto/descriptor.rst @@ -29,8 +29,8 @@ This HowTo guide has three major sections: Primer ^^^^^^ -In this primer, we start with most basic possible example and then we'll add -new capabilities one by one. +In this primer, we start with the most basic possible example and then we'll +add new capabilities one by one. Simple example: A descriptor that returns a constant @@ -197,7 +197,7 @@ be recorded, giving each descriptor its own *public_name* and *private_name*:: import logging - logging.basicConfig(level=logging.INFO) + logging.basicConfig(level=logging.INFO, force=True) class LoggedAccess: @@ -258,6 +258,10 @@ Closing thoughts A :term:`descriptor` is what we call any object that defines :meth:`__get__`, :meth:`__set__`, or :meth:`__delete__`. +Optionally, descriptors can have a :meth:`__set_name__` method. This is only +used in cases where a descriptor needs to know either the class where it is +created or the name of class variable it was assigned to. + Descriptors get invoked by the dot operator during attribute lookup. If a descriptor is accessed indirectly with ``vars(some_class)[descriptor_name]``, the descriptor instance is returned without invoking it. @@ -291,7 +295,7 @@ Validator class A validator is a descriptor for managed attribute access. Prior to storing any data, it verifies that the new value meets various type and range restrictions. If those restrictions aren't met, it raises an exception to -prevents data corruption at its source. +prevent data corruption at its source. This :class:`Validator` class is both an :term:`abstract base class` and a managed attribute descriptor:: @@ -438,12 +442,12 @@ In general, a descriptor is an object attribute with "binding behavior", one whose attribute access has been overridden by methods in the descriptor protocol. Those methods are :meth:`__get__`, :meth:`__set__`, and :meth:`__delete__`. If any of those methods are defined for an object, it is -said to be a descriptor. +said to be a :term:`descriptor`. The default behavior for attribute access is to get, set, or delete the attribute from an object's dictionary. For instance, ``a.x`` has a lookup chain starting with ``a.__dict__['x']``, then ``type(a).__dict__['x']``, and -continuing through the base classes of ``type(a)`` excluding metaclasses. If the +continuing through the base classes of ``type(a)``. If the looked-up value is an object defining one of the descriptor methods, then Python may override the default behavior and invoke the descriptor method instead. Where this occurs in the precedence chain depends on which descriptor methods @@ -492,60 +496,76 @@ Invoking Descriptors A descriptor can be called directly by its method name. For example, ``d.__get__(obj)``. -Alternatively, it is more common for a descriptor to be invoked automatically -upon attribute access. For example, ``obj.d`` looks up ``d`` in the dictionary -of ``obj``. If ``d`` defines the method :meth:`__get__`, then ``d.__get__(obj)`` +But it is more common for a descriptor to be invoked automatically from +attribute access. The expression ``obj.d`` looks up ``d`` in the dictionary of +``obj``. If ``d`` defines the method :meth:`__get__`, then ``d.__get__(obj)`` is invoked according to the precedence rules listed below. -The details of invocation depend on whether ``obj`` is an object or a class. +The details of invocation depend on whether ``obj`` is an object, class, or +instance of super. + +**Objects**: The machinery is in :meth:`object.__getattribute__`. + +It transforms ``b.x`` into ``type(b).__dict__['x'].__get__(b, type(b))``. -For objects, the machinery is in :meth:`object.__getattribute__` which -transforms ``b.x`` into ``type(b).__dict__['x'].__get__(b, type(b))``. The -implementation works through a precedence chain that gives data descriptors +The implementation works through a precedence chain that gives data descriptors priority over instance variables, instance variables priority over non-data descriptors, and assigns lowest priority to :meth:`__getattr__` if provided. + The full C implementation can be found in :c:func:`PyObject_GenericGetAttr()` in :source:`Objects/object.c`. -For classes, the machinery is in :meth:`type.__getattribute__` which transforms -``B.x`` into ``B.__dict__['x'].__get__(None, B)``. In pure Python, it looks -like:: +**Classes**: The machinery is in :meth:`type.__getattribute__`. + +It transforms ``A.x`` into ``A.__dict__['x'].__get__(None, A)``. + +In pure Python, it looks like this:: - def __getattribute__(self, key): + def __getattribute__(cls, key): "Emulate type_getattro() in Objects/typeobject.c" - v = object.__getattribute__(self, key) + v = object.__getattribute__(cls, key) if hasattr(v, '__get__'): - return v.__get__(None, self) + return v.__get__(None, cls) return v -The important points to remember are: +**Super**: The machinery is in the custom :meth:`__getattribute__` method for +object returned by :class:`super()`. -* descriptors are invoked by the :meth:`__getattribute__` method -* overriding :meth:`__getattribute__` prevents automatic descriptor calls -* :meth:`object.__getattribute__` and :meth:`type.__getattribute__` make - different calls to :meth:`__get__`. -* data descriptors always override instance dictionaries. -* non-data descriptors may be overridden by instance dictionaries. +The attribute lookup ``super(A, obj).m`` searches ``obj.__class__.__mro__`` for +the base class ``B`` immediately following ``A`` and then returns +``B.__dict__['m'].__get__(obj, A)``. -The object returned by ``super()`` also has a custom :meth:`__getattribute__` -method for invoking descriptors. The attribute lookup ``super(B, obj).m`` searches -``obj.__class__.__mro__`` for the base class ``A`` immediately following ``B`` -and then returns ``A.__dict__['m'].__get__(obj, B)``. If not a descriptor, -``m`` is returned unchanged. If not in the dictionary, ``m`` reverts to a -search using :meth:`object.__getattribute__`. +If not a descriptor, ``m`` is returned unchanged. If not in the dictionary, +``m`` reverts to a search using :meth:`object.__getattribute__`. The implementation details are in :c:func:`super_getattro()` in -:source:`Objects/typeobject.c`. and a pure Python equivalent can be found in +:source:`Objects/typeobject.c`. A pure Python equivalent can be found in `Guido's Tutorial`_. .. _`Guido's Tutorial`: https://www.python.org/download/releases/2.2.3/descrintro/#cooperation -The details above show that the mechanism for descriptors is embedded in the -:meth:`__getattribute__()` methods for :class:`object`, :class:`type`, and -:func:`super`. Classes inherit this machinery when they derive from -:class:`object` or if they have a metaclass providing similar functionality. -Likewise, classes can turn-off descriptor invocation by overriding -:meth:`__getattribute__()`. +**Summary**: The details listed above show that the mechanism for descriptors is +embedded in the :meth:`__getattribute__()` methods for :class:`object`, +:class:`type`, and :func:`super`. + +The important points to remember are: + +* Descriptors are invoked by the :meth:`__getattribute__` method. + +* Classes inherit this machinery from :class:`object`, :class:`type`, or + :func:`super`. + +* Overriding :meth:`__getattribute__` prevents automatic descriptor calls + because all the descriptor logic is in that method. + +* :meth:`object.__getattribute__` and :meth:`type.__getattribute__` make + different calls to :meth:`__get__`. The first includes the instance and may + include the class. The second puts in ``None`` for the instance and always + includes the class. + +* Data descriptors always override instance dictionaries. + +* Non-data descriptors may be overridden by instance dictionaries. Automatic Name Notification @@ -569,47 +589,70 @@ afterwards, :meth:`__set_name__` will need to be called manually. Descriptor Example ------------------ -The following code creates a class whose objects are data descriptors which -print a message for each get or set. Overriding :meth:`__getattribute__` is -alternate approach that could do this for every attribute. However, this -descriptor is useful for monitoring just a few chosen attributes:: +The following code is simplified skeleton showing how data descriptors could +be used to implement an `object relational mapping +`_. - class RevealAccess: - """A data descriptor that sets and returns values - normally and prints a message logging their access. - """ +The essential idea is that instances only hold keys to a database table. The +actual data is stored in an external table that is being dynamically updated:: - def __init__(self, initval=None, name='var'): - self.val = initval - self.name = name + class Field: + + def __set_name__(self, owner, name): + self.fetch = f'SELECT {name} FROM {owner.table} WHERE {owner.key}=?;' + self.store = f'UPDATE {owner.table} SET {name}=? WHERE {owner.key}=?;' def __get__(self, obj, objtype=None): - print('Retrieving', self.name) - return self.val + return conn.execute(self.fetch, [obj.key]).fetchone()[0] - def __set__(self, obj, val): - print('Updating', self.name) - self.val = val + def __set__(self, obj, value): + conn.execute(self.store, [value, obj.key]) + conn.commit() - class B: - x = RevealAccess(10, 'var "x"') - y = 5 +We can use the :class:`Field` to define "models" that describe the schema for +each table in a database:: - >>> m = B() - >>> m.x - Retrieving var "x" - 10 - >>> m.x = 20 - Updating var "x" - >>> m.x - Retrieving var "x" - 20 - >>> m.y - 5 + class Movie: + table = 'Movies' # Table name + key = 'title' # Primary key + director = Field() + year = Field() -The protocol is simple and offers exciting possibilities. Several use cases are -so common that they have been packaged into individual function calls. -Properties, bound methods, static methods, and class methods are all + def __init__(self, key): + self.key = key + + class Song: + table = 'Music' + key = 'title' + artist = Field() + year = Field() + genre = Field() + + def __init__(self, key): + self.key = key + +An interactive session shows how data is retrieved from the database and how +it can be updated:: + + >>> import sqlite3 + >>> conn = sqlite3.connect('entertainment.db') + + >>> Movie('Star Wars').director + 'George Lucas' + >>> jaws = Movie('Jaws') + >>> f'Released in {jaws.year} by {jaws.director}' + 'Released in 1975 by Steven Spielberg' + + >>> Song('Country Roads').artist + 'John Denver' + + >>> Movie('Star Wars').director = 'J.J. Abrams' + >>> Movie('Star Wars').director + 'J.J. Abrams' + +The descriptor protocol is simple and offers exciting possibilities. Several +use cases are so common that they have been packaged into individual function +calls. Properties, bound methods, static methods, and class methods are all based on the descriptor protocol. @@ -619,7 +662,7 @@ Properties Calling :func:`property` is a succinct way of building a data descriptor that triggers function calls upon access to an attribute. Its signature is:: - property(fget=None, fset=None, fdel=None, doc=None) -> property attribute + property(fget=None, fset=None, fdel=None, doc=None) -> property The documentation shows a typical use to define a managed attribute ``x``:: @@ -695,17 +738,30 @@ Functions and Methods Python's object oriented features are built upon a function based environment. Using non-data descriptors, the two are merged seamlessly. -Class dictionaries store methods as functions. In a class definition, methods -are written using :keyword:`def` or :keyword:`lambda`, the usual tools for -creating functions. Methods only differ from regular functions in that the -first argument is reserved for the object instance. By Python convention, the -instance reference is called *self* but may be called *this* or any other -variable name. +Functions stored in class dictionaries get turned into methods when invoked. +Methods only differ from regular functions in that the object instance is +prepended to the other arguments. By convention, the instance is called +*self* but could be called *this* or any other variable name. + +Methods can be created manually with :class:`types.MethodType` which is +roughly equivalent to:: + + class Method: + "Emulate Py_MethodType in Objects/classobject.c" + + def __init__(self, func, obj): + self.__func__ = func + self.__self__ = obj + + def __call__(self, *args, **kwargs): + func = self.__func__ + obj = self.__self__ + return func(obj, *args, **kwargs) -To support method calls, functions include the :meth:`__get__` method for -binding methods during attribute access. This means that all functions are -non-data descriptors which return bound methods when they are invoked from an -object. In pure Python, it works like this:: +To support automatic creation of methods, functions include the +:meth:`__get__` method for binding methods during attribute access. This +means that functions are non-data descriptors which return bound methods +during dotted lookup from an instance. Here's how it works:: class Function: ... @@ -716,15 +772,20 @@ object. In pure Python, it works like this:: return self return types.MethodType(self, obj) -Running the following in class in the interpreter shows how the function +Running the following class in the interpreter shows how the function descriptor works in practice:: class D: def f(self, x): return x -Access through the class dictionary does not invoke :meth:`__get__`. Instead, -it just returns the underlying function object:: +The function has a :term:`qualified name` attribute to support introspection:: + + >>> D.f.__qualname__ + 'D.f' + +Accessing the function through the class dictionary does not invoke +:meth:`__get__`. Instead, it just returns the underlying function object:: >>> D.__dict__['f'] @@ -735,13 +796,8 @@ underlying function unchanged:: >>> D.f -The function has a :term:`qualified name` attribute to support introspection:: - - >>> D.f.__qualname__ - 'D.f' - -Dotted access from an instance calls :meth:`__get__` which returns a bound -method object:: +The interesting behavior occurs during dotted access from an instance. The +dotted lookup calls :meth:`__get__` which returns a bound method object:: >>> d = D() >>> d.f @@ -752,9 +808,13 @@ instance:: >>> d.f.__func__ + >>> d.f.__self__ <__main__.D object at 0x1012e1f98> +If you have ever wondered where *self* comes from in regular methods or where +*cls* comes from in class methods, this is it! + Static Methods and Class Methods -------------------------------- @@ -798,8 +858,8 @@ in statistical work but does not directly depend on a particular dataset. It can be called either from an object or the class: ``s.erf(1.5) --> .9332`` or ``Sample.erf(1.5) --> .9332``. -Since staticmethods return the underlying function with no changes, the example -calls are unexciting:: +Since static methods return the underlying function with no changes, the +example calls are unexciting:: class E: @staticmethod @@ -840,7 +900,7 @@ for whether the caller is an object or a class:: This behavior is useful whenever the function only needs to have a class reference and does not care about any underlying data. One use for -classmethods is to create alternate class constructors. The classmethod +class methods is to create alternate class constructors. The classmethod :func:`dict.fromkeys` creates a new dictionary from a list of keys. The pure Python equivalent is:: From 2990aef0c804b5d8956c221540bb639983fc0ae4 Mon Sep 17 00:00:00 2001 From: "Miss Skeleton (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 25 Oct 2020 07:35:56 -0700 Subject: [PATCH 0642/1314] Split-out a fourth section in the descriptor HowTo guide (GH-22965) (GH-22969) --- Doc/howto/descriptor.rst | 96 +++++++++++++++++++++------------------- 1 file changed, 50 insertions(+), 46 deletions(-) diff --git a/Doc/howto/descriptor.rst b/Doc/howto/descriptor.rst index bed4078e3a3a9d..f1d1ab1d1d6101 100644 --- a/Doc/howto/descriptor.rst +++ b/Doc/howto/descriptor.rst @@ -13,7 +13,7 @@ Descriptor HowTo Guide :term:`Descriptors ` let objects customize attribute lookup, storage, and deletion. -This HowTo guide has three major sections: +This guide has four major sections: 1) The "primer" gives a basic overview, moving gently from simple examples, adding one feature at a time. It is a great place to start. @@ -25,6 +25,11 @@ This HowTo guide has three major sections: detailed mechanics of how descriptors work. Most people don't need this level of detail. +4) The last section has pure Python equivalents for built-in descriptors that + are written in C. Read this if you're curious about how functions turn + into bound methods or about how to implement common tools like + :func:`classmethod`, :func:`staticmethod`, and :func:`property`. + Primer ^^^^^^ @@ -99,7 +104,7 @@ different, updated answers each time:: 3 >>> os.system('touch games/newfile') # Add a fourth file to the directory 0 - >>> g.size + >>> g.size # Automatically updated 4 >>> s.size # The songs directory has twenty files 20 @@ -197,7 +202,7 @@ be recorded, giving each descriptor its own *public_name* and *private_name*:: import logging - logging.basicConfig(level=logging.INFO, force=True) + logging.basicConfig(level=logging.INFO) class LoggedAccess: @@ -259,7 +264,7 @@ A :term:`descriptor` is what we call any object that defines :meth:`__get__`, :meth:`__set__`, or :meth:`__delete__`. Optionally, descriptors can have a :meth:`__set_name__` method. This is only -used in cases where a descriptor needs to know either the class where it is +used in cases where a descriptor needs to know either the class where it was created or the name of class variable it was assigned to. Descriptors get invoked by the dot operator during attribute lookup. If a @@ -318,7 +323,7 @@ managed attribute descriptor:: def validate(self, value): pass -Custom validators need to subclass from :class:`Validator` and supply a +Custom validators need to inherit from :class:`Validator` and must supply a :meth:`validate` method to test various restrictions as needed. @@ -334,8 +339,9 @@ Here are three practical data validation utilities: minimum or maximum. 3) :class:`String` verifies that a value is a :class:`str`. Optionally, it - validates a given minimum or maximum length. Optionally, it can test for - another predicate as well. + validates a given minimum or maximum length. It can validate a + user-defined `predicate + `_ as well. :: @@ -398,7 +404,7 @@ Here's how the data validators can be used in a real class:: class Component: name = String(minsize=3, maxsize=10, predicate=str.isupper) - kind = OneOf('plastic', 'metal') + kind = OneOf('wood', 'metal', 'plastic') quantity = Number(minvalue=0) def __init__(self, name, kind, quantity): @@ -426,9 +432,7 @@ Abstract -------- Defines descriptors, summarizes the protocol, and shows how descriptors are -called. Examines a custom descriptor and several built-in Python descriptors -including functions, properties, static methods, and class methods. Shows how -each works by giving a pure Python equivalent and a sample application. +called. Provides an example showing how object relational mappings work. Learning about descriptors not only provides access to a larger toolset, it creates a deeper understanding of how Python works and an appreciation for the @@ -519,24 +523,17 @@ The full C implementation can be found in :c:func:`PyObject_GenericGetAttr()` in It transforms ``A.x`` into ``A.__dict__['x'].__get__(None, A)``. -In pure Python, it looks like this:: - - def __getattribute__(cls, key): - "Emulate type_getattro() in Objects/typeobject.c" - v = object.__getattribute__(cls, key) - if hasattr(v, '__get__'): - return v.__get__(None, cls) - return v +The full C implementation can be found in :c:func:`type_getattro()` in +:source:`Objects/typeobject.c`. **Super**: The machinery is in the custom :meth:`__getattribute__` method for object returned by :class:`super()`. The attribute lookup ``super(A, obj).m`` searches ``obj.__class__.__mro__`` for the base class ``B`` immediately following ``A`` and then returns -``B.__dict__['m'].__get__(obj, A)``. - -If not a descriptor, ``m`` is returned unchanged. If not in the dictionary, -``m`` reverts to a search using :meth:`object.__getattribute__`. +``B.__dict__['m'].__get__(obj, A)``. If not a descriptor, ``m`` is returned +unchanged. If not in the dictionary, ``m`` reverts to a search using +:meth:`object.__getattribute__`. The implementation details are in :c:func:`super_getattro()` in :source:`Objects/typeobject.c`. A pure Python equivalent can be found in @@ -544,9 +541,9 @@ The implementation details are in :c:func:`super_getattro()` in .. _`Guido's Tutorial`: https://www.python.org/download/releases/2.2.3/descrintro/#cooperation -**Summary**: The details listed above show that the mechanism for descriptors is -embedded in the :meth:`__getattribute__()` methods for :class:`object`, -:class:`type`, and :func:`super`. +**Summary**: The mechanism for descriptors is embedded in the +:meth:`__getattribute__()` methods for :class:`object`, :class:`type`, and +:func:`super`. The important points to remember are: @@ -586,15 +583,16 @@ place at the time of class creation. If descriptors are added to the class afterwards, :meth:`__set_name__` will need to be called manually. -Descriptor Example ------------------- +ORM Example +----------- The following code is simplified skeleton showing how data descriptors could be used to implement an `object relational mapping `_. -The essential idea is that instances only hold keys to a database table. The -actual data is stored in an external table that is being dynamically updated:: +The essential idea is that the data is stored in an external database. The +Python instances only hold keys to the database's tables. Descriptors take +care of lookups or updates:: class Field: @@ -609,8 +607,8 @@ actual data is stored in an external table that is being dynamically updated:: conn.execute(self.store, [value, obj.key]) conn.commit() -We can use the :class:`Field` to define "models" that describe the schema for -each table in a database:: +We can use the :class:`Field` class to define "models" that describe the schema +for each table in a database:: class Movie: table = 'Movies' # Table name @@ -650,10 +648,13 @@ it can be updated:: >>> Movie('Star Wars').director 'J.J. Abrams' +Pure Python Equivalents +^^^^^^^^^^^^^^^^^^^^^^^ + The descriptor protocol is simple and offers exciting possibilities. Several -use cases are so common that they have been packaged into individual function -calls. Properties, bound methods, static methods, and class methods are all -based on the descriptor protocol. +use cases are so common that they have been prepackaged into builtin tools. +Properties, bound methods, static methods, and class methods are all based on +the descriptor protocol. Properties @@ -746,7 +747,7 @@ prepended to the other arguments. By convention, the instance is called Methods can be created manually with :class:`types.MethodType` which is roughly equivalent to:: - class Method: + class MethodType: "Emulate Py_MethodType in Objects/classobject.c" def __init__(self, func, obj): @@ -770,7 +771,7 @@ during dotted lookup from an instance. Here's how it works:: "Simulate func_descr_get() in Objects/funcobject.c" if obj is None: return self - return types.MethodType(self, obj) + return MethodType(self, obj) Running the following class in the interpreter shows how the function descriptor works in practice:: @@ -816,8 +817,8 @@ If you have ever wondered where *self* comes from in regular methods or where *cls* comes from in class methods, this is it! -Static Methods and Class Methods --------------------------------- +Static Methods +-------------- Non-data descriptors provide a simple mechanism for variations on the usual patterns of binding functions into methods. @@ -883,6 +884,10 @@ Using the non-data descriptor protocol, a pure Python version of def __get__(self, obj, objtype=None): return self.f + +Class Methods +------------- + Unlike static methods, class methods prepend the class reference to the argument list before calling the function. This format is the same for whether the caller is an object or a class:: @@ -897,12 +902,11 @@ for whether the caller is an object or a class:: >>> print(F().f(3)) ('F', 3) - -This behavior is useful whenever the function only needs to have a class -reference and does not care about any underlying data. One use for -class methods is to create alternate class constructors. The classmethod -:func:`dict.fromkeys` creates a new dictionary from a list of keys. The pure -Python equivalent is:: +This behavior is useful whenever the method only needs to have a class +reference and does rely on data stored in a specific instance. One use for +class methods is to create alternate class constructors. For example, the +classmethod :func:`dict.fromkeys` creates a new dictionary from a list of +keys. The pure Python equivalent is:: class Dict: ... @@ -934,7 +938,7 @@ Using the non-data descriptor protocol, a pure Python version of cls = type(obj) if hasattr(obj, '__get__'): return self.f.__get__(cls) - return types.MethodType(self.f, cls) + return MethodType(self.f, cls) The code path for ``hasattr(obj, '__get__')`` was added in Python 3.9 and makes it possible for :func:`classmethod` to support chained decorators. From af891a962b62268d76ace0d4768ab0e1934a2cd1 Mon Sep 17 00:00:00 2001 From: "Miss Skeleton (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 25 Oct 2020 08:48:38 -0700 Subject: [PATCH 0643/1314] bpo-39108: Document threading issues for random.gauss() (GH-22928) (GH-22972) --- Doc/library/random.rst | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Doc/library/random.rst b/Doc/library/random.rst index f9535d7d1b9a22..8154dfc18ccc6d 100644 --- a/Doc/library/random.rst +++ b/Doc/library/random.rst @@ -319,6 +319,13 @@ be found in any statistics text. deviation. This is slightly faster than the :func:`normalvariate` function defined below. + Multithreading note: When two threads call this function + simultaneously, it is possible that they will receive the + same return value. This can be avoided in three ways. + 1) Have each thread use a different instance of the random + number generator. 2) Put locks around all calls. 3) Use the + slower, but thread-safe :func:`normalvariate` function instead. + .. function:: lognormvariate(mu, sigma) From 0aaecb30483e98fc29c1f4253967d05da092f0c5 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sun, 25 Oct 2020 17:56:17 +0200 Subject: [PATCH 0644/1314] [3.9] bpo-41052: Fix pickling heap types implemented in C with protocols 0 and 1 (GH-22870). (GH-22963) (cherry picked from commit 8cd1dbae32d9303caac3a473d3332f17bc98c921) --- Lib/copyreg.py | 4 ++++ Lib/test/pickletester.py | 18 ++++++++++++++++++ .../2020-10-21-23-45-02.bpo-41052.3N7J2J.rst | 2 ++ Modules/_randommodule.c | 17 ----------------- Modules/clinic/_randommodule.c.h | 19 +------------------ 5 files changed, 25 insertions(+), 35 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2020-10-21-23-45-02.bpo-41052.3N7J2J.rst diff --git a/Lib/copyreg.py b/Lib/copyreg.py index dfc463c49a389d..7ab8c128eb0445 100644 --- a/Lib/copyreg.py +++ b/Lib/copyreg.py @@ -48,6 +48,7 @@ def _reconstructor(cls, base, state): return obj _HEAPTYPE = 1<<9 +_new_type = type(int.__new__) # Python code for object.__reduce_ex__ for protocols 0 and 1 @@ -57,6 +58,9 @@ def _reduce_ex(self, proto): for base in cls.__mro__: if hasattr(base, '__flags__') and not base.__flags__ & _HEAPTYPE: break + new = base.__new__ + if isinstance(new, _new_type) and new.__self__ is base: + break else: base = object # not really reachable if base is object: diff --git a/Lib/test/pickletester.py b/Lib/test/pickletester.py index 94d42c4f97115b..3d54617f68ba4a 100644 --- a/Lib/test/pickletester.py +++ b/Lib/test/pickletester.py @@ -1965,6 +1965,17 @@ def test_newobj_proxies(self): self.assertEqual(B(x), B(y), detail) self.assertEqual(x.__dict__, y.__dict__, detail) + def test_newobj_overridden_new(self): + # Test that Python class with C implemented __new__ is pickleable + for proto in protocols: + x = MyIntWithNew2(1) + x.foo = 42 + s = self.dumps(x, proto) + y = self.loads(s) + self.assertIs(type(y), MyIntWithNew2) + self.assertEqual(int(y), 1) + self.assertEqual(y.foo, 42) + def test_newobj_not_class(self): # Issue 24552 global SimpleNewObj @@ -3085,6 +3096,13 @@ class MyFrozenSet(frozenset): MyStr, MyUnicode, MyTuple, MyList, MyDict, MySet, MyFrozenSet] +class MyIntWithNew(int): + def __new__(cls, value): + raise AssertionError + +class MyIntWithNew2(MyIntWithNew): + __new__ = int.__new__ + class SlotList(MyList): __slots__ = ["foo"] diff --git a/Misc/NEWS.d/next/Library/2020-10-21-23-45-02.bpo-41052.3N7J2J.rst b/Misc/NEWS.d/next/Library/2020-10-21-23-45-02.bpo-41052.3N7J2J.rst new file mode 100644 index 00000000000000..528e90ed13493c --- /dev/null +++ b/Misc/NEWS.d/next/Library/2020-10-21-23-45-02.bpo-41052.3N7J2J.rst @@ -0,0 +1,2 @@ +Pickling heap types implemented in C with protocols 0 and 1 raises now an +error instead of producing incorrect data. diff --git a/Modules/_randommodule.c b/Modules/_randommodule.c index 1b01491b068ff7..a402b937f70af8 100644 --- a/Modules/_randommodule.c +++ b/Modules/_randommodule.c @@ -537,29 +537,12 @@ random_new(PyTypeObject *type, PyObject *args, PyObject *kwds) } -/*[clinic input] - -_random.Random.__reduce__ - -[clinic start generated code]*/ - -static PyObject * -_random_Random___reduce___impl(RandomObject *self) -/*[clinic end generated code: output=ddea0dcdb60ffd6d input=bd38ec35fd157e0f]*/ -{ - PyErr_Format(PyExc_TypeError, - "cannot pickle %s object", - Py_TYPE(self)->tp_name); - return NULL; -} - static PyMethodDef random_methods[] = { _RANDOM_RANDOM_RANDOM_METHODDEF _RANDOM_RANDOM_SEED_METHODDEF _RANDOM_RANDOM_GETSTATE_METHODDEF _RANDOM_RANDOM_SETSTATE_METHODDEF _RANDOM_RANDOM_GETRANDBITS_METHODDEF - _RANDOM_RANDOM___REDUCE___METHODDEF {NULL, NULL} /* sentinel */ }; diff --git a/Modules/clinic/_randommodule.c.h b/Modules/clinic/_randommodule.c.h index 0a642dffc408e4..a467811d93b272 100644 --- a/Modules/clinic/_randommodule.c.h +++ b/Modules/clinic/_randommodule.c.h @@ -114,21 +114,4 @@ _random_Random_getrandbits(RandomObject *self, PyObject *arg) exit: return return_value; } - -PyDoc_STRVAR(_random_Random___reduce____doc__, -"__reduce__($self, /)\n" -"--\n" -"\n"); - -#define _RANDOM_RANDOM___REDUCE___METHODDEF \ - {"__reduce__", (PyCFunction)_random_Random___reduce__, METH_NOARGS, _random_Random___reduce____doc__}, - -static PyObject * -_random_Random___reduce___impl(RandomObject *self); - -static PyObject * -_random_Random___reduce__(RandomObject *self, PyObject *Py_UNUSED(ignored)) -{ - return _random_Random___reduce___impl(self); -} -/*[clinic end generated code: output=d8a99be3f1192219 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=a7feb0c9c8d1b627 input=a9049054013a1b77]*/ From 83c86cf54b36a7325f615f5adf22b28e48f0e72d Mon Sep 17 00:00:00 2001 From: "Miss Skeleton (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 25 Oct 2020 11:23:09 -0700 Subject: [PATCH 0645/1314] bpo-42144: Add a missing "goto error;" in the _ssl module (GH-22959) (cherry picked from commit c32f2976b8f4034724c3270397aa16f38daf470f) Co-authored-by: Zackery Spytz --- Modules/_ssl.c | 1 + 1 file changed, 1 insertion(+) diff --git a/Modules/_ssl.c b/Modules/_ssl.c index 28796b376e8623..7bdde452513fdc 100644 --- a/Modules/_ssl.c +++ b/Modules/_ssl.c @@ -899,6 +899,7 @@ _ssl_configure_hostname(PySSLSocket *self, const char* server_hostname) if (ip == NULL) { if (!SSL_set_tlsext_host_name(self->ssl, server_hostname)) { _setSSLError(NULL, 0, __FILE__, __LINE__); + goto error; } } if (self->ctx->check_hostname) { From 0b290dd2171e745d94f48298cafb2327eb2de17c Mon Sep 17 00:00:00 2001 From: "Miss Skeleton (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 25 Oct 2020 16:24:56 -0700 Subject: [PATCH 0646/1314] bpo-42150: Avoid buffer overflow in the new parser (GH-22978) (cherry picked from commit e68c67805e6a4c4ec80bea64be0e8373cc02d322) Co-authored-by: Pablo Galindo --- .../Core and Builtins/2020-10-25-21-14-18.bpo-42150.b70u_T.rst | 2 ++ Parser/pegen/pegen.c | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2020-10-25-21-14-18.bpo-42150.b70u_T.rst diff --git a/Misc/NEWS.d/next/Core and Builtins/2020-10-25-21-14-18.bpo-42150.b70u_T.rst b/Misc/NEWS.d/next/Core and Builtins/2020-10-25-21-14-18.bpo-42150.b70u_T.rst new file mode 100644 index 00000000000000..62fabb857aa380 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2020-10-25-21-14-18.bpo-42150.b70u_T.rst @@ -0,0 +1,2 @@ +Fix possible buffer overflow in the new parser when checking for +continuation lines. Patch by Pablo Galindo. diff --git a/Parser/pegen/pegen.c b/Parser/pegen/pegen.c index 2c435fb367836e..a7643fc3a6ad98 100644 --- a/Parser/pegen/pegen.c +++ b/Parser/pegen/pegen.c @@ -989,7 +989,8 @@ bad_single_statement(Parser *p) /* Newlines are allowed if preceded by a line continuation character or if they appear inside a string. */ - if (!cur || *(cur - 1) == '\\' || newline_in_string(p, cur)) { + if (!cur || (cur != p->tok->buf && *(cur - 1) == '\\') + || newline_in_string(p, cur)) { return 0; } char c = *cur; From c12afa92b0db6f017e479b41f95d75bac7b59850 Mon Sep 17 00:00:00 2001 From: "Miss Skeleton (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 25 Oct 2020 17:34:29 -0700 Subject: [PATCH 0647/1314] [3.9] bpo-42146: Fix memory leak in subprocess.Popen() in case of uid/gid overflow (GH-22966) (GH-22980) Fix memory leak in subprocess.Popen() in case of uid/gid overflow Also add a test that would catch this leak with `--huntrleaks`. Alas, the test for `extra_groups` also exposes an inconsistency in our error reporting: we use a custom ValueError for `extra_groups`, but propagate OverflowError for `user` and `group`. (cherry picked from commit c0590c0033e86f98cdf5f2ca6898656f98ab4053) Co-authored-by: Alexey Izbyshev Automerge-Triggered-By: GH:gpshead --- Lib/test/test_subprocess.py | 13 +++++++++++++ .../2020-10-25-19-25-02.bpo-42146.6A8uvS.rst | 2 ++ Modules/_posixsubprocess.c | 4 ++-- 3 files changed, 17 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2020-10-25-19-25-02.bpo-42146.6A8uvS.rst diff --git a/Lib/test/test_subprocess.py b/Lib/test/test_subprocess.py index ba2844da9add97..373542463f2e35 100644 --- a/Lib/test/test_subprocess.py +++ b/Lib/test/test_subprocess.py @@ -1826,6 +1826,10 @@ def test_user(self): with self.assertRaises(ValueError): subprocess.check_call(ZERO_RETURN_CMD, user=-1) + with self.assertRaises(OverflowError): + subprocess.check_call(ZERO_RETURN_CMD, + cwd=os.curdir, env=os.environ, user=2**64) + if pwd is None and name_uid is not None: with self.assertRaises(ValueError): subprocess.check_call(ZERO_RETURN_CMD, user=name_uid) @@ -1869,6 +1873,10 @@ def test_group(self): with self.assertRaises(ValueError): subprocess.check_call(ZERO_RETURN_CMD, group=-1) + with self.assertRaises(OverflowError): + subprocess.check_call(ZERO_RETURN_CMD, + cwd=os.curdir, env=os.environ, group=2**64) + if grp is None: with self.assertRaises(ValueError): subprocess.check_call(ZERO_RETURN_CMD, group=name_group) @@ -1917,6 +1925,11 @@ def test_extra_groups(self): with self.assertRaises(ValueError): subprocess.check_call(ZERO_RETURN_CMD, extra_groups=[-1]) + with self.assertRaises(ValueError): + subprocess.check_call(ZERO_RETURN_CMD, + cwd=os.curdir, env=os.environ, + extra_groups=[2**64]) + if grp is None: with self.assertRaises(ValueError): subprocess.check_call(ZERO_RETURN_CMD, diff --git a/Misc/NEWS.d/next/Library/2020-10-25-19-25-02.bpo-42146.6A8uvS.rst b/Misc/NEWS.d/next/Library/2020-10-25-19-25-02.bpo-42146.6A8uvS.rst new file mode 100644 index 00000000000000..041809803db6a2 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2020-10-25-19-25-02.bpo-42146.6A8uvS.rst @@ -0,0 +1,2 @@ +Fix memory leak in :func:`subprocess.Popen` in case an uid (gid) specified in +`user` (`group`, `extra_groups`) overflows `uid_t` (`gid_t`). diff --git a/Modules/_posixsubprocess.c b/Modules/_posixsubprocess.c index 5d1691ace41920..5356417dd7037f 100644 --- a/Modules/_posixsubprocess.c +++ b/Modules/_posixsubprocess.c @@ -626,7 +626,7 @@ subprocess_fork_exec(PyObject* self, PyObject *args) uid_t uid; gid_t gid, *groups = NULL; int child_umask; - PyObject *cwd_obj, *cwd_obj2; + PyObject *cwd_obj, *cwd_obj2 = NULL; const char *cwd; pid_t pid; int need_to_reenable_gc = 0; @@ -748,7 +748,6 @@ subprocess_fork_exec(PyObject* self, PyObject *args) cwd = PyBytes_AsString(cwd_obj2); } else { cwd = NULL; - cwd_obj2 = NULL; } if (groups_list != Py_None) { @@ -908,6 +907,7 @@ subprocess_fork_exec(PyObject* self, PyObject *args) return PyLong_FromPid(pid); cleanup: + Py_XDECREF(cwd_obj2); if (envp) _Py_FreeCharPArray(envp); if (argv) From 36cb0c88cf69c5d88440e784db0f214adf6154fc Mon Sep 17 00:00:00 2001 From: "Miss Skeleton (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 25 Oct 2020 22:50:11 -0700 Subject: [PATCH 0648/1314] Added some makefile generated files to .gitignore (GH-22435) (cherry picked from commit 96a9eed2457c05af6953890d89463704c9d99c57) Co-authored-by: Marco Sulla --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 0962d3a1841fc4..80dcf34bf47a6f 100644 --- a/.gitignore +++ b/.gitignore @@ -103,6 +103,8 @@ Tools/unicode/data/ /config.status /config.status.lineno /platform +/profile-clean-stamp +/profile-run-stamp /pybuilddir.txt /pyconfig.h /python-config From df4790c071ea47ea3d5e0697dadc78105cf7f280 Mon Sep 17 00:00:00 2001 From: "Miss Skeleton (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 25 Oct 2020 22:59:46 -0700 Subject: [PATCH 0649/1314] Add a link to buffer protocol in bytearray() doc (GH-22675) (cherry picked from commit 0f25c231b3a024e358c3e55d9aba2f7bcc49630c) Co-authored-by: Antoine <43954001+awecx@users.noreply.github.com> --- Doc/library/functions.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/library/functions.rst b/Doc/library/functions.rst index ca6dabfcdddaf4..2a54ce5baf6384 100644 --- a/Doc/library/functions.rst +++ b/Doc/library/functions.rst @@ -150,8 +150,8 @@ are always available. They are listed here in alphabetical order. * If it is an *integer*, the array will have that size and will be initialized with null bytes. - * If it is an object conforming to the *buffer* interface, a read-only buffer - of the object will be used to initialize the bytes array. + * If it is an object conforming to the :ref:`buffer interface `, + a read-only buffer of the object will be used to initialize the bytes array. * If it is an *iterable*, it must be an iterable of integers in the range ``0 <= x < 256``, which are used as the initial contents of the array. From 562ad7624e5fe22fdded9b39723c562255a49abd Mon Sep 17 00:00:00 2001 From: "Miss Skeleton (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 26 Oct 2020 21:01:51 -0700 Subject: [PATCH 0650/1314] bpo-41474, Makefile: Add dependency on cpython/frameobject.h (GH-22999) Co-Authored-By: Skip Montanaro (cherry picked from commit a6879d9445f98833c4e300e187956e2a218a2315) Co-authored-by: Victor Stinner --- Makefile.pre.in | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile.pre.in b/Makefile.pre.in index 77f91e72b19190..f128444b98594e 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -1114,6 +1114,7 @@ PYTHON_HEADERS= \ $(srcdir)/Include/cpython/dictobject.h \ $(srcdir)/Include/cpython/fileobject.h \ $(srcdir)/Include/cpython/fileutils.h \ + $(srcdir)/Include/cpython/frameobject.h \ $(srcdir)/Include/cpython/import.h \ $(srcdir)/Include/cpython/initconfig.h \ $(srcdir)/Include/cpython/interpreteridobject.h \ From 2cb259fcf3cde56f359c2f393280689784dcc834 Mon Sep 17 00:00:00 2001 From: "Miss Skeleton (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 27 Oct 2020 09:42:36 -0700 Subject: [PATCH 0651/1314] bpo-6761: Enhance __call__ documentation (GH-7987) (cherry picked from commit 95f710c55714153f0c8cce48f8215bb3d866ac1d) Co-authored-by: Andre Delfino --- Doc/reference/datamodel.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/reference/datamodel.rst b/Doc/reference/datamodel.rst index c527719c40d063..89063876ccc9ed 100644 --- a/Doc/reference/datamodel.rst +++ b/Doc/reference/datamodel.rst @@ -2168,7 +2168,7 @@ Emulating callable objects .. index:: pair: call; instance Called when the instance is "called" as a function; if this method is defined, - ``x(arg1, arg2, ...)`` is a shorthand for ``x.__call__(arg1, arg2, ...)``. + ``x(arg1, arg2, ...)`` roughly translates to ``type(x).__call__(x, arg1, ...)``. .. _sequence-types: From 8aee019d71b9ed44107bdc8a0c9c132059c0e1ef Mon Sep 17 00:00:00 2001 From: Lysandros Nikolaou Date: Wed, 28 Oct 2020 00:37:36 +0200 Subject: [PATCH 0652/1314] [3.9] Remove git conflict lines from test_parse_directory in peg_generator (GH-23007) --- Tools/peg_generator/scripts/test_parse_directory.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/Tools/peg_generator/scripts/test_parse_directory.py b/Tools/peg_generator/scripts/test_parse_directory.py index 100db1d424c7c9..6dfdbb9170e6e7 100755 --- a/Tools/peg_generator/scripts/test_parse_directory.py +++ b/Tools/peg_generator/scripts/test_parse_directory.py @@ -5,14 +5,9 @@ import os import sys import time -import traceback import tokenize -<<<<<<< HEAD import _peg_parser -from glob import glob -======= from glob import glob, escape ->>>>>>> 9355868458... bpo-41043: Escape literal part of the path for glob(). (GH-20994) from pathlib import PurePath from typing import List, Optional, Any, Tuple From c4b58cea4771afc0ddfdb857b0fb5115b9f4bc9f Mon Sep 17 00:00:00 2001 From: Lysandros Nikolaou Date: Wed, 28 Oct 2020 00:38:42 +0200 Subject: [PATCH 0653/1314] [3.9] bpo-41659: Disallow curly brace directly after primary (GH-22996) (#23006) (cherry picked from commit 15acc4eaba8519d7d5f2acaffde65446b44dcf79) --- Grammar/python.gram | 3 + Lib/test/test_exceptions.py | 1 + Lib/test/test_syntax.py | 3 + .../2020-10-27-18-32-49.bpo-41659.d4a-8o.rst | 3 + Parser/pegen/parse.c | 401 ++++++++++-------- 5 files changed, 244 insertions(+), 167 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2020-10-27-18-32-49.bpo-41659.d4a-8o.rst diff --git a/Grammar/python.gram b/Grammar/python.gram index 8f4d250dc3ae4d..6c36b6acb53527 100644 --- a/Grammar/python.gram +++ b/Grammar/python.gram @@ -460,6 +460,7 @@ await_primary[expr_ty] (memo): | AWAIT a=primary { CHECK_VERSION(5, "Await expressions are", _Py_Await(a, EXTRA)) } | primary primary[expr_ty]: + | invalid_primary # must be before 'primay genexp' because of invalid_genexp | a=primary '.' b=NAME { _Py_Attribute(a, b->v.Name.id, Load, EXTRA) } | a=primary b=genexp { _Py_Call(a, CHECK(_PyPegen_singleton_seq(p, b)), NULL, EXTRA) } | a=primary '(' b=[arguments] ')' { @@ -664,6 +665,8 @@ invalid_del_stmt: RAISE_SYNTAX_ERROR_INVALID_TARGET(DEL_TARGETS, a) } invalid_block: | NEWLINE !INDENT { RAISE_INDENTATION_ERROR("expected an indented block") } +invalid_primary: + | primary a='{' { RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "invalid syntax") } invalid_comprehension: | ('[' | '(' | '{') a=starred_expression for_if_clauses { RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "iterable unpacking cannot be used in comprehension") } diff --git a/Lib/test/test_exceptions.py b/Lib/test/test_exceptions.py index 47f37114f0259a..8d125b57ad6d5a 100644 --- a/Lib/test/test_exceptions.py +++ b/Lib/test/test_exceptions.py @@ -205,6 +205,7 @@ def testSyntaxErrorOffset(self): check(b'Python = "\xcf\xb3\xf2\xee\xed" +', 1, 18) check('x = "a', 1, 7) check('lambda x: x = 2', 1, 1) + check('f{a + b + c}', 1, 2) # Errors thrown by compile.c check('class foo:return 1', 1, 11) diff --git a/Lib/test/test_syntax.py b/Lib/test/test_syntax.py index d6583b9d30c272..b0527e6cd85ba4 100644 --- a/Lib/test/test_syntax.py +++ b/Lib/test/test_syntax.py @@ -802,6 +802,9 @@ def _check_error(self, code, errtext, else: self.fail("compile() did not raise SyntaxError") + def test_curly_brace_after_primary_raises_immediately(self): + self._check_error("f{", "invalid syntax", mode="single") + def test_assign_call(self): self._check_error("f() = 1", "assign") diff --git a/Misc/NEWS.d/next/Core and Builtins/2020-10-27-18-32-49.bpo-41659.d4a-8o.rst b/Misc/NEWS.d/next/Core and Builtins/2020-10-27-18-32-49.bpo-41659.d4a-8o.rst new file mode 100644 index 00000000000000..038749a7b16c9d --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2020-10-27-18-32-49.bpo-41659.d4a-8o.rst @@ -0,0 +1,3 @@ +Fix a bug in the parser, where a curly brace following a `primary` didn't fail immediately. +This led to invalid expressions like `a {b}` to throw a :exc:`SyntaxError` with a wrong offset, +or invalid expressions ending with a curly brace like `a {` to not fail immediately in the REPL. \ No newline at end of file diff --git a/Parser/pegen/parse.c b/Parser/pegen/parse.c index 1a4df757eae338..2eb9e03d528199 100644 --- a/Parser/pegen/parse.c +++ b/Parser/pegen/parse.c @@ -225,173 +225,174 @@ static KeywordToken *reserved_keywords[] = { #define invalid_ann_assign_target_type 1147 #define invalid_del_stmt_type 1148 #define invalid_block_type 1149 -#define invalid_comprehension_type 1150 -#define invalid_dict_comprehension_type 1151 -#define invalid_parameters_type 1152 -#define invalid_lambda_parameters_type 1153 -#define invalid_star_etc_type 1154 -#define invalid_lambda_star_etc_type 1155 -#define invalid_double_type_comments_type 1156 -#define invalid_with_item_type 1157 -#define invalid_for_target_type 1158 -#define invalid_group_type 1159 -#define invalid_import_from_targets_type 1160 -#define _loop0_1_type 1161 -#define _loop0_2_type 1162 -#define _loop0_4_type 1163 -#define _gather_3_type 1164 -#define _loop0_6_type 1165 -#define _gather_5_type 1166 -#define _loop0_8_type 1167 -#define _gather_7_type 1168 -#define _loop0_10_type 1169 -#define _gather_9_type 1170 -#define _loop1_11_type 1171 -#define _loop0_13_type 1172 -#define _gather_12_type 1173 -#define _tmp_14_type 1174 -#define _tmp_15_type 1175 -#define _tmp_16_type 1176 -#define _tmp_17_type 1177 -#define _tmp_18_type 1178 -#define _tmp_19_type 1179 -#define _tmp_20_type 1180 -#define _tmp_21_type 1181 -#define _loop1_22_type 1182 -#define _tmp_23_type 1183 -#define _tmp_24_type 1184 -#define _loop0_26_type 1185 -#define _gather_25_type 1186 -#define _loop0_28_type 1187 -#define _gather_27_type 1188 -#define _tmp_29_type 1189 -#define _tmp_30_type 1190 -#define _loop0_31_type 1191 -#define _loop1_32_type 1192 -#define _loop0_34_type 1193 -#define _gather_33_type 1194 -#define _tmp_35_type 1195 -#define _loop0_37_type 1196 -#define _gather_36_type 1197 -#define _tmp_38_type 1198 -#define _loop0_40_type 1199 -#define _gather_39_type 1200 -#define _loop0_42_type 1201 -#define _gather_41_type 1202 -#define _loop0_44_type 1203 -#define _gather_43_type 1204 -#define _loop0_46_type 1205 -#define _gather_45_type 1206 -#define _tmp_47_type 1207 -#define _loop1_48_type 1208 -#define _tmp_49_type 1209 -#define _tmp_50_type 1210 -#define _tmp_51_type 1211 -#define _tmp_52_type 1212 -#define _tmp_53_type 1213 -#define _loop0_54_type 1214 -#define _loop0_55_type 1215 -#define _loop0_56_type 1216 -#define _loop1_57_type 1217 -#define _loop0_58_type 1218 -#define _loop1_59_type 1219 -#define _loop1_60_type 1220 -#define _loop1_61_type 1221 -#define _loop0_62_type 1222 -#define _loop1_63_type 1223 -#define _loop0_64_type 1224 -#define _loop1_65_type 1225 -#define _loop0_66_type 1226 -#define _loop1_67_type 1227 -#define _loop1_68_type 1228 -#define _tmp_69_type 1229 -#define _loop0_71_type 1230 -#define _gather_70_type 1231 -#define _loop1_72_type 1232 -#define _loop0_74_type 1233 -#define _gather_73_type 1234 -#define _loop1_75_type 1235 -#define _loop0_76_type 1236 -#define _loop0_77_type 1237 -#define _loop0_78_type 1238 -#define _loop1_79_type 1239 -#define _loop0_80_type 1240 -#define _loop1_81_type 1241 -#define _loop1_82_type 1242 -#define _loop1_83_type 1243 -#define _loop0_84_type 1244 -#define _loop1_85_type 1245 -#define _loop0_86_type 1246 -#define _loop1_87_type 1247 -#define _loop0_88_type 1248 -#define _loop1_89_type 1249 -#define _loop1_90_type 1250 -#define _loop1_91_type 1251 -#define _loop1_92_type 1252 -#define _tmp_93_type 1253 -#define _loop0_95_type 1254 -#define _gather_94_type 1255 -#define _tmp_96_type 1256 -#define _tmp_97_type 1257 -#define _tmp_98_type 1258 -#define _tmp_99_type 1259 -#define _loop1_100_type 1260 -#define _tmp_101_type 1261 -#define _tmp_102_type 1262 -#define _loop0_104_type 1263 -#define _gather_103_type 1264 -#define _loop1_105_type 1265 -#define _loop0_106_type 1266 -#define _loop0_107_type 1267 -#define _loop0_109_type 1268 -#define _gather_108_type 1269 -#define _tmp_110_type 1270 -#define _loop0_112_type 1271 -#define _gather_111_type 1272 -#define _loop0_114_type 1273 -#define _gather_113_type 1274 -#define _loop0_116_type 1275 -#define _gather_115_type 1276 -#define _loop0_118_type 1277 -#define _gather_117_type 1278 -#define _loop0_119_type 1279 -#define _loop0_121_type 1280 -#define _gather_120_type 1281 -#define _tmp_122_type 1282 -#define _loop0_124_type 1283 -#define _gather_123_type 1284 -#define _loop0_126_type 1285 -#define _gather_125_type 1286 -#define _tmp_127_type 1287 -#define _loop0_128_type 1288 -#define _loop0_129_type 1289 -#define _loop0_130_type 1290 -#define _tmp_131_type 1291 -#define _tmp_132_type 1292 -#define _loop0_133_type 1293 -#define _tmp_134_type 1294 -#define _loop0_135_type 1295 -#define _tmp_136_type 1296 -#define _tmp_137_type 1297 -#define _tmp_138_type 1298 -#define _tmp_139_type 1299 -#define _tmp_140_type 1300 -#define _tmp_141_type 1301 -#define _tmp_142_type 1302 -#define _tmp_143_type 1303 -#define _tmp_144_type 1304 -#define _tmp_145_type 1305 -#define _tmp_146_type 1306 -#define _tmp_147_type 1307 -#define _tmp_148_type 1308 -#define _tmp_149_type 1309 -#define _tmp_150_type 1310 -#define _tmp_151_type 1311 -#define _tmp_152_type 1312 -#define _loop1_153_type 1313 -#define _loop1_154_type 1314 -#define _tmp_155_type 1315 -#define _tmp_156_type 1316 +#define invalid_primary_type 1150 // Left-recursive +#define invalid_comprehension_type 1151 +#define invalid_dict_comprehension_type 1152 +#define invalid_parameters_type 1153 +#define invalid_lambda_parameters_type 1154 +#define invalid_star_etc_type 1155 +#define invalid_lambda_star_etc_type 1156 +#define invalid_double_type_comments_type 1157 +#define invalid_with_item_type 1158 +#define invalid_for_target_type 1159 +#define invalid_group_type 1160 +#define invalid_import_from_targets_type 1161 +#define _loop0_1_type 1162 +#define _loop0_2_type 1163 +#define _loop0_4_type 1164 +#define _gather_3_type 1165 +#define _loop0_6_type 1166 +#define _gather_5_type 1167 +#define _loop0_8_type 1168 +#define _gather_7_type 1169 +#define _loop0_10_type 1170 +#define _gather_9_type 1171 +#define _loop1_11_type 1172 +#define _loop0_13_type 1173 +#define _gather_12_type 1174 +#define _tmp_14_type 1175 +#define _tmp_15_type 1176 +#define _tmp_16_type 1177 +#define _tmp_17_type 1178 +#define _tmp_18_type 1179 +#define _tmp_19_type 1180 +#define _tmp_20_type 1181 +#define _tmp_21_type 1182 +#define _loop1_22_type 1183 +#define _tmp_23_type 1184 +#define _tmp_24_type 1185 +#define _loop0_26_type 1186 +#define _gather_25_type 1187 +#define _loop0_28_type 1188 +#define _gather_27_type 1189 +#define _tmp_29_type 1190 +#define _tmp_30_type 1191 +#define _loop0_31_type 1192 +#define _loop1_32_type 1193 +#define _loop0_34_type 1194 +#define _gather_33_type 1195 +#define _tmp_35_type 1196 +#define _loop0_37_type 1197 +#define _gather_36_type 1198 +#define _tmp_38_type 1199 +#define _loop0_40_type 1200 +#define _gather_39_type 1201 +#define _loop0_42_type 1202 +#define _gather_41_type 1203 +#define _loop0_44_type 1204 +#define _gather_43_type 1205 +#define _loop0_46_type 1206 +#define _gather_45_type 1207 +#define _tmp_47_type 1208 +#define _loop1_48_type 1209 +#define _tmp_49_type 1210 +#define _tmp_50_type 1211 +#define _tmp_51_type 1212 +#define _tmp_52_type 1213 +#define _tmp_53_type 1214 +#define _loop0_54_type 1215 +#define _loop0_55_type 1216 +#define _loop0_56_type 1217 +#define _loop1_57_type 1218 +#define _loop0_58_type 1219 +#define _loop1_59_type 1220 +#define _loop1_60_type 1221 +#define _loop1_61_type 1222 +#define _loop0_62_type 1223 +#define _loop1_63_type 1224 +#define _loop0_64_type 1225 +#define _loop1_65_type 1226 +#define _loop0_66_type 1227 +#define _loop1_67_type 1228 +#define _loop1_68_type 1229 +#define _tmp_69_type 1230 +#define _loop0_71_type 1231 +#define _gather_70_type 1232 +#define _loop1_72_type 1233 +#define _loop0_74_type 1234 +#define _gather_73_type 1235 +#define _loop1_75_type 1236 +#define _loop0_76_type 1237 +#define _loop0_77_type 1238 +#define _loop0_78_type 1239 +#define _loop1_79_type 1240 +#define _loop0_80_type 1241 +#define _loop1_81_type 1242 +#define _loop1_82_type 1243 +#define _loop1_83_type 1244 +#define _loop0_84_type 1245 +#define _loop1_85_type 1246 +#define _loop0_86_type 1247 +#define _loop1_87_type 1248 +#define _loop0_88_type 1249 +#define _loop1_89_type 1250 +#define _loop1_90_type 1251 +#define _loop1_91_type 1252 +#define _loop1_92_type 1253 +#define _tmp_93_type 1254 +#define _loop0_95_type 1255 +#define _gather_94_type 1256 +#define _tmp_96_type 1257 +#define _tmp_97_type 1258 +#define _tmp_98_type 1259 +#define _tmp_99_type 1260 +#define _loop1_100_type 1261 +#define _tmp_101_type 1262 +#define _tmp_102_type 1263 +#define _loop0_104_type 1264 +#define _gather_103_type 1265 +#define _loop1_105_type 1266 +#define _loop0_106_type 1267 +#define _loop0_107_type 1268 +#define _loop0_109_type 1269 +#define _gather_108_type 1270 +#define _tmp_110_type 1271 +#define _loop0_112_type 1272 +#define _gather_111_type 1273 +#define _loop0_114_type 1274 +#define _gather_113_type 1275 +#define _loop0_116_type 1276 +#define _gather_115_type 1277 +#define _loop0_118_type 1278 +#define _gather_117_type 1279 +#define _loop0_119_type 1280 +#define _loop0_121_type 1281 +#define _gather_120_type 1282 +#define _tmp_122_type 1283 +#define _loop0_124_type 1284 +#define _gather_123_type 1285 +#define _loop0_126_type 1286 +#define _gather_125_type 1287 +#define _tmp_127_type 1288 +#define _loop0_128_type 1289 +#define _loop0_129_type 1290 +#define _loop0_130_type 1291 +#define _tmp_131_type 1292 +#define _tmp_132_type 1293 +#define _loop0_133_type 1294 +#define _tmp_134_type 1295 +#define _loop0_135_type 1296 +#define _tmp_136_type 1297 +#define _tmp_137_type 1298 +#define _tmp_138_type 1299 +#define _tmp_139_type 1300 +#define _tmp_140_type 1301 +#define _tmp_141_type 1302 +#define _tmp_142_type 1303 +#define _tmp_143_type 1304 +#define _tmp_144_type 1305 +#define _tmp_145_type 1306 +#define _tmp_146_type 1307 +#define _tmp_147_type 1308 +#define _tmp_148_type 1309 +#define _tmp_149_type 1310 +#define _tmp_150_type 1311 +#define _tmp_151_type 1312 +#define _tmp_152_type 1313 +#define _loop1_153_type 1314 +#define _loop1_154_type 1315 +#define _tmp_155_type 1316 +#define _tmp_156_type 1317 static mod_ty file_rule(Parser *p); static mod_ty interactive_rule(Parser *p); @@ -543,6 +544,7 @@ static void *invalid_assignment_rule(Parser *p); static expr_ty invalid_ann_assign_target_rule(Parser *p); static void *invalid_del_stmt_rule(Parser *p); static void *invalid_block_rule(Parser *p); +static void *invalid_primary_rule(Parser *p); static void *invalid_comprehension_rule(Parser *p); static void *invalid_dict_comprehension_rule(Parser *p); static void *invalid_parameters_rule(Parser *p); @@ -10274,6 +10276,7 @@ await_primary_rule(Parser *p) // Left-recursive // primary: +// | invalid_primary // | primary '.' NAME // | primary genexp // | primary '(' arguments? ')' @@ -10327,6 +10330,25 @@ primary_raw(Parser *p) UNUSED(_start_lineno); // Only used by EXTRA macro int _start_col_offset = p->tokens[_mark]->col_offset; UNUSED(_start_col_offset); // Only used by EXTRA macro + { // invalid_primary + if (p->error_indicator) { + D(p->level--); + return NULL; + } + D(fprintf(stderr, "%*c> primary[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "invalid_primary")); + void *invalid_primary_var; + if ( + (invalid_primary_var = invalid_primary_rule(p)) // invalid_primary + ) + { + D(fprintf(stderr, "%*c+ primary[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "invalid_primary")); + _res = invalid_primary_var; + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s primary[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "invalid_primary")); + } { // primary '.' NAME if (p->error_indicator) { D(p->level--); @@ -15047,6 +15069,51 @@ invalid_block_rule(Parser *p) return _res; } +// Left-recursive +// invalid_primary: primary '{' +static void * +invalid_primary_rule(Parser *p) +{ + D(p->level++); + if (p->error_indicator) { + D(p->level--); + return NULL; + } + void * _res = NULL; + int _mark = p->mark; + { // primary '{' + if (p->error_indicator) { + D(p->level--); + return NULL; + } + D(fprintf(stderr, "%*c> invalid_primary[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "primary '{'")); + Token * a; + expr_ty primary_var; + if ( + (primary_var = primary_rule(p)) // primary + && + (a = _PyPegen_expect_token(p, 25)) // token='{' + ) + { + D(fprintf(stderr, "%*c+ invalid_primary[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "primary '{'")); + _res = RAISE_SYNTAX_ERROR_KNOWN_LOCATION ( a , "invalid syntax" ); + if (_res == NULL && PyErr_Occurred()) { + p->error_indicator = 1; + D(p->level--); + return NULL; + } + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s invalid_primary[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "primary '{'")); + } + _res = NULL; + done: + D(p->level--); + return _res; +} + // invalid_comprehension: ('[' | '(' | '{') starred_expression for_if_clauses static void * invalid_comprehension_rule(Parser *p) From 24a7c298d47658295673dc04d1b6d59f2b200a7c Mon Sep 17 00:00:00 2001 From: Lysandros Nikolaou Date: Wed, 28 Oct 2020 02:14:15 +0200 Subject: [PATCH 0654/1314] [3.9] bpo-42123: Run the parser two times and only enable invalid rules on the second run (GH-22111) (GH-23011) * Implement running the parser a second time for the errors messages The first parser run is only responsible for detecting whether there is a `SyntaxError` or not. If there isn't the AST gets returned. Otherwise, the parser is run a second time with all the `invalid_*` rules enabled so that all the customized error messages get produced. (cherry picked from commit bca701403253379409dece03053dbd739c0bd059) --- Grammar/python.gram | 4 +- .../2020-10-23-02-43-24.bpo-42123.64gJWC.rst | 3 + Parser/pegen/parse.c | 96 +++++++++---------- Parser/pegen/pegen.c | 13 +++ Parser/pegen/pegen.h | 1 + Tools/peg_generator/pegen/c_generator.py | 5 +- 6 files changed, 71 insertions(+), 51 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2020-10-23-02-43-24.bpo-42123.64gJWC.rst diff --git a/Grammar/python.gram b/Grammar/python.gram index 6c36b6acb53527..b709d3d5c3214f 100644 --- a/Grammar/python.gram +++ b/Grammar/python.gram @@ -535,7 +535,7 @@ yield_expr[expr_ty]: arguments[expr_ty] (memo): | a=args [','] &')' { a } - | incorrect_arguments + | invalid_arguments args[expr_ty]: | a=','.(starred_expression | named_expression !'=')+ b=[',' k=kwargs {k}] { _PyPegen_collect_call_seqs(p, a, b, EXTRA) } | a=kwargs { _Py_Call(_PyPegen_dummy_name(p), @@ -620,7 +620,7 @@ t_atom[expr_ty]: # From here on, there are rules for invalid syntax with specialised error messages -incorrect_arguments: +invalid_arguments: | args ',' '*' { RAISE_SYNTAX_ERROR("iterable argument unpacking follows keyword argument unpacking") } | a=expression for_if_clauses ',' [args | expression for_if_clauses] { RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "Generator expression must be parenthesized") } diff --git a/Misc/NEWS.d/next/Core and Builtins/2020-10-23-02-43-24.bpo-42123.64gJWC.rst b/Misc/NEWS.d/next/Core and Builtins/2020-10-23-02-43-24.bpo-42123.64gJWC.rst new file mode 100644 index 00000000000000..6461efd76f0f97 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2020-10-23-02-43-24.bpo-42123.64gJWC.rst @@ -0,0 +1,3 @@ +Run the parser two times. On the first run, disable all the rules that only +generate better error messages to gain performance. If there's a parse +failure, run the parser a second time with those enabled. diff --git a/Parser/pegen/parse.c b/Parser/pegen/parse.c index 2eb9e03d528199..48a24434746848 100644 --- a/Parser/pegen/parse.c +++ b/Parser/pegen/parse.c @@ -218,7 +218,7 @@ static KeywordToken *reserved_keywords[] = { #define t_primary_type 1140 // Left-recursive #define t_lookahead_type 1141 #define t_atom_type 1142 -#define incorrect_arguments_type 1143 +#define invalid_arguments_type 1143 #define invalid_kwarg_type 1144 #define invalid_named_expression_type 1145 #define invalid_assignment_type 1146 @@ -537,7 +537,7 @@ static expr_ty target_rule(Parser *p); static expr_ty t_primary_rule(Parser *p); static void *t_lookahead_rule(Parser *p); static expr_ty t_atom_rule(Parser *p); -static void *incorrect_arguments_rule(Parser *p); +static void *invalid_arguments_rule(Parser *p); static void *invalid_kwarg_rule(Parser *p); static void *invalid_named_expression_rule(Parser *p); static void *invalid_assignment_rule(Parser *p); @@ -2219,7 +2219,7 @@ assignment_rule(Parser *p) return NULL; } } - { // invalid_assignment + if (p->call_invalid_rules) { // invalid_assignment if (p->error_indicator) { D(p->level--); return NULL; @@ -2892,7 +2892,7 @@ del_stmt_rule(Parser *p) D(fprintf(stderr, "%*c%s del_stmt[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'del' del_targets &(';' | NEWLINE)")); } - { // invalid_del_stmt + if (p->call_invalid_rules) { // invalid_del_stmt if (p->error_indicator) { D(p->level--); return NULL; @@ -3243,7 +3243,7 @@ import_from_targets_rule(Parser *p) D(fprintf(stderr, "%*c%s import_from_targets[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'*'")); } - { // invalid_import_from_targets + if (p->call_invalid_rules) { // invalid_import_from_targets if (p->error_indicator) { D(p->level--); return NULL; @@ -4036,7 +4036,7 @@ for_stmt_rule(Parser *p) return NULL; } } - { // invalid_for_target + if (p->call_invalid_rules) { // invalid_for_target if (p->error_indicator) { D(p->level--); return NULL; @@ -4337,7 +4337,7 @@ with_item_rule(Parser *p) D(fprintf(stderr, "%*c%s with_item[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "expression 'as' star_target &(',' | ')' | ':')")); } - { // invalid_with_item + if (p->call_invalid_rules) { // invalid_with_item if (p->error_indicator) { D(p->level--); return NULL; @@ -5072,7 +5072,7 @@ func_type_comment_rule(Parser *p) D(fprintf(stderr, "%*c%s func_type_comment[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "NEWLINE TYPE_COMMENT &(NEWLINE INDENT)")); } - { // invalid_double_type_comments + if (p->call_invalid_rules) { // invalid_double_type_comments if (p->error_indicator) { D(p->level--); return NULL; @@ -5127,7 +5127,7 @@ params_rule(Parser *p) } arguments_ty _res = NULL; int _mark = p->mark; - { // invalid_parameters + if (p->call_invalid_rules) { // invalid_parameters if (p->error_indicator) { D(p->level--); return NULL; @@ -5602,7 +5602,7 @@ star_etc_rule(Parser *p) D(fprintf(stderr, "%*c%s star_etc[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "kwds")); } - { // invalid_star_etc + if (p->call_invalid_rules) { // invalid_star_etc if (p->error_indicator) { D(p->level--); return NULL; @@ -6305,7 +6305,7 @@ block_rule(Parser *p) D(fprintf(stderr, "%*c%s block[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "simple_stmt")); } - { // invalid_block + if (p->call_invalid_rules) { // invalid_block if (p->error_indicator) { D(p->level--); return NULL; @@ -6799,7 +6799,7 @@ named_expression_rule(Parser *p) D(fprintf(stderr, "%*c%s named_expression[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "expression !':='")); } - { // invalid_named_expression + if (p->call_invalid_rules) { // invalid_named_expression if (p->error_indicator) { D(p->level--); return NULL; @@ -7193,7 +7193,7 @@ lambda_params_rule(Parser *p) } arguments_ty _res = NULL; int _mark = p->mark; - { // invalid_lambda_parameters + if (p->call_invalid_rules) { // invalid_lambda_parameters if (p->error_indicator) { D(p->level--); return NULL; @@ -7670,7 +7670,7 @@ lambda_star_etc_rule(Parser *p) D(fprintf(stderr, "%*c%s lambda_star_etc[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_kwds")); } - { // invalid_lambda_star_etc + if (p->call_invalid_rules) { // invalid_lambda_star_etc if (p->error_indicator) { D(p->level--); return NULL; @@ -10330,7 +10330,7 @@ primary_raw(Parser *p) UNUSED(_start_lineno); // Only used by EXTRA macro int _start_col_offset = p->tokens[_mark]->col_offset; UNUSED(_start_col_offset); // Only used by EXTRA macro - { // invalid_primary + if (p->call_invalid_rules) { // invalid_primary if (p->error_indicator) { D(p->level--); return NULL; @@ -11209,7 +11209,7 @@ listcomp_rule(Parser *p) return NULL; } } - { // invalid_comprehension + if (p->call_invalid_rules) { // invalid_comprehension if (p->error_indicator) { D(p->level--); return NULL; @@ -11340,7 +11340,7 @@ group_rule(Parser *p) D(fprintf(stderr, "%*c%s group[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'(' (yield_expr | named_expression) ')'")); } - { // invalid_group + if (p->call_invalid_rules) { // invalid_group if (p->error_indicator) { D(p->level--); return NULL; @@ -11434,7 +11434,7 @@ genexp_rule(Parser *p) return NULL; } } - { // invalid_comprehension + if (p->call_invalid_rules) { // invalid_comprehension if (p->error_indicator) { D(p->level--); return NULL; @@ -11593,7 +11593,7 @@ setcomp_rule(Parser *p) return NULL; } } - { // invalid_comprehension + if (p->call_invalid_rules) { // invalid_comprehension if (p->error_indicator) { D(p->level--); return NULL; @@ -11745,7 +11745,7 @@ dictcomp_rule(Parser *p) D(fprintf(stderr, "%*c%s dictcomp[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'{' kvpair for_if_clauses '}'")); } - { // invalid_dict_comprehension + if (p->call_invalid_rules) { // invalid_dict_comprehension if (p->error_indicator) { D(p->level--); return NULL; @@ -12064,7 +12064,7 @@ for_if_clause_rule(Parser *p) return NULL; } } - { // invalid_for_target + if (p->call_invalid_rules) { // invalid_for_target if (p->error_indicator) { D(p->level--); return NULL; @@ -12190,7 +12190,7 @@ yield_expr_rule(Parser *p) return _res; } -// arguments: args ','? &')' | incorrect_arguments +// arguments: args ','? &')' | invalid_arguments static expr_ty arguments_rule(Parser *p) { @@ -12235,24 +12235,24 @@ arguments_rule(Parser *p) D(fprintf(stderr, "%*c%s arguments[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "args ','? &')'")); } - { // incorrect_arguments + if (p->call_invalid_rules) { // invalid_arguments if (p->error_indicator) { D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> arguments[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "incorrect_arguments")); - void *incorrect_arguments_var; + D(fprintf(stderr, "%*c> arguments[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "invalid_arguments")); + void *invalid_arguments_var; if ( - (incorrect_arguments_var = incorrect_arguments_rule(p)) // incorrect_arguments + (invalid_arguments_var = invalid_arguments_rule(p)) // invalid_arguments ) { - D(fprintf(stderr, "%*c+ arguments[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "incorrect_arguments")); - _res = incorrect_arguments_var; + D(fprintf(stderr, "%*c+ arguments[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "invalid_arguments")); + _res = invalid_arguments_var; goto done; } p->mark = _mark; D(fprintf(stderr, "%*c%s arguments[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "incorrect_arguments")); + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "invalid_arguments")); } _res = NULL; done: @@ -12589,7 +12589,7 @@ kwarg_or_starred_rule(Parser *p) D(fprintf(stderr, "%*c%s kwarg_or_starred[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "starred_expression")); } - { // invalid_kwarg + if (p->call_invalid_rules) { // invalid_kwarg if (p->error_indicator) { D(p->level--); return NULL; @@ -12709,7 +12709,7 @@ kwarg_or_double_starred_rule(Parser *p) D(fprintf(stderr, "%*c%s kwarg_or_double_starred[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'**' expression")); } - { // invalid_kwarg + if (p->call_invalid_rules) { // invalid_kwarg if (p->error_indicator) { D(p->level--); return NULL; @@ -14421,14 +14421,14 @@ t_atom_rule(Parser *p) return _res; } -// incorrect_arguments: +// invalid_arguments: // | args ',' '*' // | expression for_if_clauses ',' [args | expression for_if_clauses] // | args for_if_clauses // | args ',' expression for_if_clauses // | args ',' args static void * -incorrect_arguments_rule(Parser *p) +invalid_arguments_rule(Parser *p) { D(p->level++); if (p->error_indicator) { @@ -14442,7 +14442,7 @@ incorrect_arguments_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> incorrect_arguments[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "args ',' '*'")); + D(fprintf(stderr, "%*c> invalid_arguments[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "args ',' '*'")); Token * _literal; Token * _literal_1; expr_ty args_var; @@ -14454,7 +14454,7 @@ incorrect_arguments_rule(Parser *p) (_literal_1 = _PyPegen_expect_token(p, 16)) // token='*' ) { - D(fprintf(stderr, "%*c+ incorrect_arguments[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "args ',' '*'")); + D(fprintf(stderr, "%*c+ invalid_arguments[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "args ',' '*'")); _res = RAISE_SYNTAX_ERROR ( "iterable argument unpacking follows keyword argument unpacking" ); if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -14464,7 +14464,7 @@ incorrect_arguments_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s incorrect_arguments[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s invalid_arguments[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "args ',' '*'")); } { // expression for_if_clauses ',' [args | expression for_if_clauses] @@ -14472,7 +14472,7 @@ incorrect_arguments_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> incorrect_arguments[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression for_if_clauses ',' [args | expression for_if_clauses]")); + D(fprintf(stderr, "%*c> invalid_arguments[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression for_if_clauses ',' [args | expression for_if_clauses]")); Token * _literal; void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings @@ -14488,7 +14488,7 @@ incorrect_arguments_rule(Parser *p) (_opt_var = _tmp_127_rule(p), 1) // [args | expression for_if_clauses] ) { - D(fprintf(stderr, "%*c+ incorrect_arguments[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression for_if_clauses ',' [args | expression for_if_clauses]")); + D(fprintf(stderr, "%*c+ invalid_arguments[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression for_if_clauses ',' [args | expression for_if_clauses]")); _res = RAISE_SYNTAX_ERROR_KNOWN_LOCATION ( a , "Generator expression must be parenthesized" ); if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -14498,7 +14498,7 @@ incorrect_arguments_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s incorrect_arguments[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s invalid_arguments[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "expression for_if_clauses ',' [args | expression for_if_clauses]")); } { // args for_if_clauses @@ -14506,7 +14506,7 @@ incorrect_arguments_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> incorrect_arguments[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "args for_if_clauses")); + D(fprintf(stderr, "%*c> invalid_arguments[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "args for_if_clauses")); expr_ty a; asdl_seq* for_if_clauses_var; if ( @@ -14515,7 +14515,7 @@ incorrect_arguments_rule(Parser *p) (for_if_clauses_var = for_if_clauses_rule(p)) // for_if_clauses ) { - D(fprintf(stderr, "%*c+ incorrect_arguments[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "args for_if_clauses")); + D(fprintf(stderr, "%*c+ invalid_arguments[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "args for_if_clauses")); _res = _PyPegen_nonparen_genexp_in_call ( p , a ); if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -14525,7 +14525,7 @@ incorrect_arguments_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s incorrect_arguments[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s invalid_arguments[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "args for_if_clauses")); } { // args ',' expression for_if_clauses @@ -14533,7 +14533,7 @@ incorrect_arguments_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> incorrect_arguments[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "args ',' expression for_if_clauses")); + D(fprintf(stderr, "%*c> invalid_arguments[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "args ',' expression for_if_clauses")); Token * _literal; expr_ty a; expr_ty args_var; @@ -14548,7 +14548,7 @@ incorrect_arguments_rule(Parser *p) (for_if_clauses_var = for_if_clauses_rule(p)) // for_if_clauses ) { - D(fprintf(stderr, "%*c+ incorrect_arguments[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "args ',' expression for_if_clauses")); + D(fprintf(stderr, "%*c+ invalid_arguments[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "args ',' expression for_if_clauses")); _res = RAISE_SYNTAX_ERROR_KNOWN_LOCATION ( a , "Generator expression must be parenthesized" ); if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -14558,7 +14558,7 @@ incorrect_arguments_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s incorrect_arguments[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s invalid_arguments[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "args ',' expression for_if_clauses")); } { // args ',' args @@ -14566,7 +14566,7 @@ incorrect_arguments_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> incorrect_arguments[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "args ',' args")); + D(fprintf(stderr, "%*c> invalid_arguments[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "args ',' args")); Token * _literal; expr_ty a; expr_ty args_var; @@ -14578,7 +14578,7 @@ incorrect_arguments_rule(Parser *p) (args_var = args_rule(p)) // args ) { - D(fprintf(stderr, "%*c+ incorrect_arguments[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "args ',' args")); + D(fprintf(stderr, "%*c+ invalid_arguments[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "args ',' args")); _res = _PyPegen_arguments_parsing_error ( p , a ); if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -14588,7 +14588,7 @@ incorrect_arguments_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s incorrect_arguments[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s invalid_arguments[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "args ',' args")); } _res = NULL; diff --git a/Parser/pegen/pegen.c b/Parser/pegen/pegen.c index a7643fc3a6ad98..78891af8250073 100644 --- a/Parser/pegen/pegen.c +++ b/Parser/pegen/pegen.c @@ -1101,15 +1101,28 @@ _PyPegen_Parser_New(struct tok_state *tok, int start_rule, int flags, p->feature_version = feature_version; p->known_err_token = NULL; p->level = 0; + p->call_invalid_rules = 0; return p; } +static void +reset_parser_state(Parser *p) +{ + for (int i = 0; i < p->fill; i++) { + p->tokens[i]->memo = NULL; + } + p->mark = 0; + p->call_invalid_rules = 1; +} + void * _PyPegen_run_parser(Parser *p) { void *res = _PyPegen_parse(p); if (res == NULL) { + reset_parser_state(p); + _PyPegen_parse(p); if (PyErr_Occurred()) { return NULL; } diff --git a/Parser/pegen/pegen.h b/Parser/pegen/pegen.h index bd35d4ff71ae8d..2fea84fd22ab40 100644 --- a/Parser/pegen/pegen.h +++ b/Parser/pegen/pegen.h @@ -73,6 +73,7 @@ typedef struct { growable_comment_array type_ignore_comments; Token *known_err_token; int level; + int call_invalid_rules; } Parser; typedef struct { diff --git a/Tools/peg_generator/pegen/c_generator.py b/Tools/peg_generator/pegen/c_generator.py index aee668c3f329ab..d0abc12b4026ae 100644 --- a/Tools/peg_generator/pegen/c_generator.py +++ b/Tools/peg_generator/pegen/c_generator.py @@ -730,7 +730,10 @@ def handle_alt_loop(self, node: Alt, is_gather: bool, rulename: Optional[str]) - def visit_Alt( self, node: Alt, is_loop: bool, is_gather: bool, rulename: Optional[str] ) -> None: - self.print(f"{{ // {node}") + if len(node.items) == 1 and str(node.items[0]).startswith('invalid_'): + self.print(f"if (p->call_invalid_rules) {{ // {node}") + else: + self.print(f"{{ // {node}") with self.indent(): self._check_for_errors() node_str = str(node).replace('"', '\\"') From 577d7c4e628260eb7926d043ca9c355ece583eb7 Mon Sep 17 00:00:00 2001 From: kj <28750310+Fidget-Spinner@users.noreply.github.com> Date: Wed, 28 Oct 2020 23:33:36 +0800 Subject: [PATCH 0655/1314] [3.9] bpo-41805: Documentation for PEP 585 (GH-22615) (GH-23016) Backport of #22615 to 3.9 since that couldn't be auto-merged due to conflicts. --- Doc/glossary.rst | 7 + Doc/library/stdtypes.rst | 193 ++++++++++++++++++ Doc/library/types.rst | 8 + .../2020-10-10-01-36-37.bpo-41805.l-CGv5.rst | 3 + 4 files changed, 211 insertions(+) create mode 100644 Misc/NEWS.d/next/Documentation/2020-10-10-01-36-37.bpo-41805.l-CGv5.rst diff --git a/Doc/glossary.rst b/Doc/glossary.rst index 847500e556056e..4fd01e0160c26c 100644 --- a/Doc/glossary.rst +++ b/Doc/glossary.rst @@ -483,6 +483,13 @@ Glossary See also the :term:`single dispatch` glossary entry, the :func:`functools.singledispatch` decorator, and :pep:`443`. + generic type + A :term:`type` that can be parameterized; typically a container like + :class:`list`. Used for :term:`type hints ` and + :term:`annotations `. + + See :pep:`483` for more details, and :mod:`typing` or + :ref:`generic alias type ` for its uses. GIL See :term:`global interpreter lock`. diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst index 1de48e13e271f2..e19e76f8311c8e 100644 --- a/Doc/library/stdtypes.rst +++ b/Doc/library/stdtypes.rst @@ -4731,6 +4731,199 @@ Compared to the overhead of setting up the runtime context, the overhead of a single class dictionary lookup is negligible. +.. _types-genericalias: + +Generic Alias Type +================== + +.. index:: + object: GenericAlias + pair: Generic; Alias + +``GenericAlias`` objects are created by subscripting a class (usually a +container), such as ``list[int]``. They are intended primarily for +:term:`type annotations `. + +Usually, the :ref:`subscription ` of container objects calls the +method :meth:`__getitem__` of the object. However, the subscription of some +containers' classes may call the classmethod :meth:`__class_getitem__` of the +class instead. The classmethod :meth:`__class_getitem__` should return a +``GenericAlias`` object. + +.. note:: + If the :meth:`__getitem__` of the class' metaclass is present, it will take + precedence over the :meth:`__class_getitem__` defined in the class (see + :pep:`560` for more details). + +The ``GenericAlias`` object acts as a proxy for :term:`generic types +`, implementing *parameterized generics* - a specific instance +of a generic which provides the types for container elements. + +The user-exposed type for the ``GenericAlias`` object can be accessed from +:data:`types.GenericAlias` and used for :func:`isinstance` checks. + +.. describe:: T[X, Y, ...] + + Creates a ``GenericAlias`` representing a type ``T`` containing elements + of types *X*, *Y*, and more depending on the ``T`` used. + For example, a function expecting a :class:`list` containing + :class:`float` elements:: + + def average(values: list[float]) -> float: + return sum(values) / len(values) + + Another example for :term:`mapping` objects, using a :class:`dict`, which + is a generic type expecting two type parameters representing the key type + and the value type. In this example, the function expects a ``dict`` with + keys of type :class:`str` and values of type :class:`int`:: + + def send_post_request(url: str, body: dict[str, int]) -> None: + ... + +The builtin functions :func:`isinstance` and :func:`issubclass` do not accept +``GenericAlias`` types for their second argument:: + + >>> isinstance([1, 2], list[str]) + Traceback (most recent call last): + File "", line 1, in + TypeError: isinstance() argument 2 cannot be a parameterized generic + +The Python runtime does not enforce :term:`type annotations `. +This extends to generic types and their type parameters. When creating +an object from a ``GenericAlias``, container elements are not checked +against their type. For example, the following code is discouraged, but will +run without errors:: + + >>> t = list[str] + >>> t([1, 2, 3]) + [1, 2, 3] + +Furthermore, parameterized generics erase type parameters during object +creation:: + + >>> t = list[str] + >>> type(t) + + + >>> l = t() + >>> type(l) + + +Calling :func:`repr` or :func:`str` on a generic shows the parameterized type:: + + >>> repr(list[int]) + 'list[int]' + + >>> str(list[int]) + 'list[int]' + +The :meth:`__getitem__` method of generics will raise an exception to disallow +mistakes like ``dict[str][str]``:: + + >>> dict[str][str] + Traceback (most recent call last): + File "", line 1, in + TypeError: There are no type variables left in dict[str] + +However, such expressions are valid when :ref:`type variables ` are +used. The index must have as many elements as there are type variable items +in the ``GenericAlias`` object's :attr:`__args__ `. :: + + >>> from typing import TypeVar + >>> Y = TypeVar('Y') + >>> dict[str, Y][int] + dict[str, int] + + +Standard Generic Collections +---------------------------- + +These standard library collections support parameterized generics. + +* :class:`tuple` +* :class:`list` +* :class:`dict` +* :class:`set` +* :class:`frozenset` +* :class:`type` +* :class:`collections.deque` +* :class:`collections.defaultdict` +* :class:`collections.OrderedDict` +* :class:`collections.Counter` +* :class:`collections.ChainMap` +* :class:`collections.abc.Awaitable` +* :class:`collections.abc.Coroutine` +* :class:`collections.abc.AsyncIterable` +* :class:`collections.abc.AsyncIterator` +* :class:`collections.abc.AsyncGenerator` +* :class:`collections.abc.Iterable` +* :class:`collections.abc.Iterator` +* :class:`collections.abc.Generator` +* :class:`collections.abc.Reversible` +* :class:`collections.abc.Container` +* :class:`collections.abc.Collection` +* :class:`collections.abc.Callable` +* :class:`collections.abc.Set` +* :class:`collections.abc.MutableSet` +* :class:`collections.abc.Mapping` +* :class:`collections.abc.MutableMapping` +* :class:`collections.abc.Sequence` +* :class:`collections.abc.MutableSequence` +* :class:`collections.abc.ByteString` +* :class:`collections.abc.MappingView` +* :class:`collections.abc.KeysView` +* :class:`collections.abc.ItemsView` +* :class:`collections.abc.ValuesView` +* :class:`contextlib.AbstractContextManager` +* :class:`contextlib.AbstractAsyncContextManager` +* :ref:`re.Pattern ` +* :ref:`re.Match ` + + +Special Attributes of Generic Alias +----------------------------------- + +All parameterized generics implement special read-only attributes. + +.. attribute:: genericalias.__origin__ + + This attribute points at the non-parameterized generic class:: + + >>> list[int].__origin__ + + + +.. attribute:: genericalias.__args__ + + This attribute is a :class:`tuple` (possibly of length 1) of generic + types passed to the original :meth:`__class_getitem__` + of the generic container:: + + >>> dict[str, list[int]].__args__ + (, list[int]) + + +.. attribute:: genericalias.__parameters__ + + This attribute is a lazily computed tuple (possibly empty) of unique type + variables found in ``__args__``:: + + >>> from typing import TypeVar + + >>> T = TypeVar('T') + >>> list[T].__parameters__ + (~T,) + + +.. seealso:: + + * :pep:`585` -- "Type Hinting Generics In Standard Collections" + * :meth:`__class_getitem__` -- Used to implement parameterized generics. + * :ref:`generics` -- Generics in the :mod:`typing` module. + +.. versionadded:: 3.9 + + .. _typesother: Other Built-in Types diff --git a/Doc/library/types.rst b/Doc/library/types.rst index a88e882305ff3e..1573e460f2f2be 100644 --- a/Doc/library/types.rst +++ b/Doc/library/types.rst @@ -242,6 +242,14 @@ Standard names are defined for the following types: Defaults to ``None``. Previously the attribute was optional. +.. data:: GenericAlias + + The type of :ref:`parameterized generics ` such as + ``list[int]``. + + .. versionadded:: 3.9 + + .. class:: TracebackType(tb_next, tb_frame, tb_lasti, tb_lineno) The type of traceback objects such as found in ``sys.exc_info()[2]``. diff --git a/Misc/NEWS.d/next/Documentation/2020-10-10-01-36-37.bpo-41805.l-CGv5.rst b/Misc/NEWS.d/next/Documentation/2020-10-10-01-36-37.bpo-41805.l-CGv5.rst new file mode 100644 index 00000000000000..9c9134350a3176 --- /dev/null +++ b/Misc/NEWS.d/next/Documentation/2020-10-10-01-36-37.bpo-41805.l-CGv5.rst @@ -0,0 +1,3 @@ +Documented :ref:`generic alias type ` and +:data:`types.GenericAlias`. Also added an entry in glossary for +:term:`generic types `. From 60324d26b58c89d68abb23fb42f1563d395c3910 Mon Sep 17 00:00:00 2001 From: "Miss Skeleton (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 29 Oct 2020 04:02:50 -0700 Subject: [PATCH 0656/1314] bpo-42143: Ensure PyFunction_NewWithQualName() can't fail after creating the func object (GH-22953) (GH-23021) func_dealloc() does not handle partially-created objects. Best not to give it any. (cherry picked from commit 350526105fa9b131d8b941ae753378b741dabb2f) Co-authored-by: Yonatan Goldschmidt --- .../2020-10-27-21-34-05.bpo-42143.N6KXUO.rst | 2 ++ Objects/funcobject.c | 29 ++++++++++--------- 2 files changed, 18 insertions(+), 13 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2020-10-27-21-34-05.bpo-42143.N6KXUO.rst diff --git a/Misc/NEWS.d/next/Core and Builtins/2020-10-27-21-34-05.bpo-42143.N6KXUO.rst b/Misc/NEWS.d/next/Core and Builtins/2020-10-27-21-34-05.bpo-42143.N6KXUO.rst new file mode 100644 index 00000000000000..2b16e69da73b5f --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2020-10-27-21-34-05.bpo-42143.N6KXUO.rst @@ -0,0 +1,2 @@ +Fix handling of errors during creation of ``PyFunctionObject``, which resulted +in operations on uninitialized memory. Patch by Yonatan Goldschmidt. diff --git a/Objects/funcobject.c b/Objects/funcobject.c index bd24f67b9740af..2c60275d90619c 100644 --- a/Objects/funcobject.c +++ b/Objects/funcobject.c @@ -20,9 +20,23 @@ PyFunction_NewWithQualName(PyObject *code, PyObject *globals, PyObject *qualname return NULL; } + /* __module__: If module name is in globals, use it. + Otherwise, use None. */ + module = PyDict_GetItemWithError(globals, __name__); + if (module) { + Py_INCREF(module); + } + else if (PyErr_Occurred()) { + return NULL; + } + op = PyObject_GC_New(PyFunctionObject, &PyFunction_Type); - if (op == NULL) + if (op == NULL) { + Py_XDECREF(module); return NULL; + } + /* Note: No failures from this point on, since func_dealloc() does not + expect a partially-created object. */ op->func_weakreflist = NULL; Py_INCREF(code); @@ -35,6 +49,7 @@ PyFunction_NewWithQualName(PyObject *code, PyObject *globals, PyObject *qualname op->func_kwdefaults = NULL; /* No keyword only defaults */ op->func_closure = NULL; op->vectorcall = _PyFunction_Vectorcall; + op->func_module = module; consts = ((PyCodeObject *)code)->co_consts; if (PyTuple_Size(consts) >= 1) { @@ -48,20 +63,8 @@ PyFunction_NewWithQualName(PyObject *code, PyObject *globals, PyObject *qualname op->func_doc = doc; op->func_dict = NULL; - op->func_module = NULL; op->func_annotations = NULL; - /* __module__: If module name is in globals, use it. - Otherwise, use None. */ - module = PyDict_GetItemWithError(globals, __name__); - if (module) { - Py_INCREF(module); - op->func_module = module; - } - else if (PyErr_Occurred()) { - Py_DECREF(op); - return NULL; - } if (qualname) op->func_qualname = qualname; else From b626d2218c03127502025ccdf93d555e0487ea95 Mon Sep 17 00:00:00 2001 From: "Miss Skeleton (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 29 Oct 2020 15:38:12 -0700 Subject: [PATCH 0657/1314] bpo-42061: Document __format__ for IP addresses (GH-23018) Automerge-Triggered-By: GH:ericvsmith (cherry picked from commit 3317466061509c83dce257caab3661d52571cab1) Co-authored-by: Teugea Ioan-Teodor --- Doc/library/ipaddress.rst | 36 +++++++++++++++++-- Doc/tools/susp-ignored.csv | 6 ++-- .../2020-10-28-21-39-45.bpo-42061._x-0sg.rst | 1 + 3 files changed, 39 insertions(+), 4 deletions(-) create mode 100644 Misc/NEWS.d/next/Documentation/2020-10-28-21-39-45.bpo-42061._x-0sg.rst diff --git a/Doc/library/ipaddress.rst b/Doc/library/ipaddress.rst index 5f5e66412da477..d6d1f1e362137b 100644 --- a/Doc/library/ipaddress.rst +++ b/Doc/library/ipaddress.rst @@ -202,6 +202,32 @@ write code that handles both IP versions correctly. Address objects are .. _iana-ipv4-special-registry: https://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml .. _iana-ipv6-special-registry: https://www.iana.org/assignments/iana-ipv6-special-registry/iana-ipv6-special-registry.xhtml +.. method:: IPv4Address.__format__(fmt) + + Returns a string representation of the IP address, controlled by + an explicit format string. + *fmt* can be one of the following: ``'s'``, the default option, + equivalent to :func:`str`, ``'b'`` for a zero-padded binary string, + ``'X'`` or ``'x'`` for an uppercase or lowercase hexadecimal + representation, or ``'n'``, which is equivalent to ``'b'`` for IPv4 + addresses and ``'x'`` for IPv6. For binary and hexadecimal + representations, the form specifier ``'#'`` and the grouping option + ``'_'`` are available. ``__format__`` is used by ``format``, ``str.format`` + and f-strings. + + >>> format(ipaddress.IPv4Address('192.168.0.1')) + '192.168.0.1' + >>> '{:#b}'.format(ipaddress.IPv4Address('192.168.0.1')) + '0b11000000101010000000000000000001' + >>> f'{ipaddress.IPv6Address("2001:db8::1000"):s}' + '2001:db8::1000' + >>> format(ipaddress.IPv6Address('2001:db8::1000'), '_X') + '2001_0DB8_0000_0000_0000_0000_0000_1000' + >>> '{:#_n}'.format(ipaddress.IPv6Address('2001:db8::1000')) + '0x2001_0db8_0000_0000_0000_0000_0000_1000' + + .. versionadded:: 3.9 + .. class:: IPv6Address(address) @@ -246,8 +272,8 @@ write code that handles both IP versions correctly. Address objects are groups consisting entirely of zeroes included. - For the following attributes, see the corresponding documentation of the - :class:`IPv4Address` class: + For the following attributes and methods, see the corresponding + documentation of the :class:`IPv4Address` class: .. attribute:: packed .. attribute:: reverse_pointer @@ -297,6 +323,12 @@ write code that handles both IP versions correctly. Address objects are the embedded ``(server, client)`` IP address pair. For any other address, this property will be ``None``. +.. method:: IPv6Address.__format__(fmt) + + Refer to the corresponding method documentation in + :class:`IPv4Address`. + + .. versionadded:: 3.9 Conversion to Strings and Integers ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/Doc/tools/susp-ignored.csv b/Doc/tools/susp-ignored.csv index 80e77be45f95b1..7739e7ab7603dd 100644 --- a/Doc/tools/susp-ignored.csv +++ b/Doc/tools/susp-ignored.csv @@ -149,8 +149,10 @@ library/ipaddress,,:db8,IPv6Address('2001:db8::') library/ipaddress,,::,IPv6Address('2001:db8::') library/ipaddress,,:db8,>>> ipaddress.IPv6Address('2001:db8::1000') library/ipaddress,,::,>>> ipaddress.IPv6Address('2001:db8::1000') -library/ipaddress,,:db8,IPv6Address('2001:db8::1000') -library/ipaddress,,::,IPv6Address('2001:db8::1000') +library/ipaddress,,:db8,'2001:db8::1000' +library/ipaddress,,::,'2001:db8::1000' +library/ipaddress,231,:db8,">>> f'{ipaddress.IPv6Address(""2001:db8::1000""):s}'" +library/ipaddress,231,::,">>> f'{ipaddress.IPv6Address(""2001:db8::1000""):s}'" library/ipaddress,,::,IPv6Address('ff02::5678%1') library/ipaddress,,::,fe80::1234 library/ipaddress,,:db8,">>> ipaddress.ip_address(""2001:db8::1"").reverse_pointer" diff --git a/Misc/NEWS.d/next/Documentation/2020-10-28-21-39-45.bpo-42061._x-0sg.rst b/Misc/NEWS.d/next/Documentation/2020-10-28-21-39-45.bpo-42061._x-0sg.rst new file mode 100644 index 00000000000000..b38bb84350171e --- /dev/null +++ b/Misc/NEWS.d/next/Documentation/2020-10-28-21-39-45.bpo-42061._x-0sg.rst @@ -0,0 +1 @@ +Document __format__ functionality for IP addresses. \ No newline at end of file From a39068bf48766e5520e175eae8cda33531e16039 Mon Sep 17 00:00:00 2001 From: "Miss Skeleton (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 29 Oct 2020 21:23:33 -0700 Subject: [PATCH 0658/1314] bpo-42198: Link to GenericAlias in typing and expressions (GH-23030) Follow up to 7cdf30fff39ea97f403b5472096349998d190e30 and 4173320920706b49a004bdddd8d7108e8984e3fc. This addresses the point "1. Update links in typing, subscription and union to point to GenericAlias." in the bpo for this PR. (cherry picked from commit 9129af6050b747f288baa9d4e7d43031647ed222) Co-authored-by: kj <28750310+Fidget-Spinner@users.noreply.github.com> --- Doc/library/typing.rst | 111 ++++++++++++++++++++++------------ Doc/reference/expressions.rst | 8 +-- 2 files changed, 75 insertions(+), 44 deletions(-) diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst index 67e8a3fa9e50df..a5f8b0403f8031 100644 --- a/Doc/library/typing.rst +++ b/Doc/library/typing.rst @@ -509,7 +509,8 @@ These can be used as types in annotations using ``[]``, each having a unique syn is equivalent to ``Tuple[Any, ...]``, and in turn to :class:`tuple`. .. deprecated:: 3.9 - :class:`builtins.tuple ` now supports ``[]``. See :pep:`585`. + :class:`builtins.tuple ` now supports ``[]``. See :pep:`585` and + :ref:`types-genericalias`. .. data:: Union @@ -583,7 +584,8 @@ These can be used as types in annotations using ``[]``, each having a unique syn :class:`collections.abc.Callable`. .. deprecated:: 3.9 - :class:`collections.abc.Callable` now supports ``[]``. See :pep:`585`. + :class:`collections.abc.Callable` now supports ``[]``. See :pep:`585` and + :ref:`types-genericalias`. .. class:: Type(Generic[CT_co]) @@ -628,7 +630,8 @@ These can be used as types in annotations using ``[]``, each having a unique syn .. versionadded:: 3.5.2 .. deprecated:: 3.9 - :class:`builtins.type ` now supports ``[]``. See :pep:`585`. + :class:`builtins.type ` now supports ``[]``. See :pep:`585` and + :ref:`types-genericalias`. .. data:: Literal @@ -1060,7 +1063,8 @@ Corresponding to built-in types ... .. deprecated:: 3.9 - :class:`builtins.dict ` now supports ``[]``. See :pep:`585`. + :class:`builtins.dict ` now supports ``[]``. See :pep:`585` and + :ref:`types-genericalias`. .. class:: List(list, MutableSequence[T]) @@ -1080,7 +1084,8 @@ Corresponding to built-in types return [item for item in vector if item > 0] .. deprecated:: 3.9 - :class:`builtins.list ` now supports ``[]``. See :pep:`585`. + :class:`builtins.list ` now supports ``[]``. See :pep:`585` and + :ref:`types-genericalias`. .. class:: Set(set, MutableSet[T]) @@ -1089,14 +1094,16 @@ Corresponding to built-in types to use an abstract collection type such as :class:`AbstractSet`. .. deprecated:: 3.9 - :class:`builtins.set ` now supports ``[]``. See :pep:`585`. + :class:`builtins.set ` now supports ``[]``. See :pep:`585` and + :ref:`types-genericalias`. .. class:: FrozenSet(frozenset, AbstractSet[T_co]) A generic version of :class:`builtins.frozenset `. .. deprecated:: 3.9 - :class:`builtins.frozenset ` now supports ``[]``. See :pep:`585`. + :class:`builtins.frozenset ` now supports ``[]``. See + :pep:`585` and :ref:`types-genericalias`. .. note:: :data:`Tuple` is a special form. @@ -1110,7 +1117,8 @@ Corresponding to types in :mod:`collections` .. versionadded:: 3.5.2 .. deprecated:: 3.9 - :class:`collections.defaultdict` now supports ``[]``. See :pep:`585`. + :class:`collections.defaultdict` now supports ``[]``. See :pep:`585` and + :ref:`types-genericalias`. .. class:: OrderedDict(collections.OrderedDict, MutableMapping[KT, VT]) @@ -1119,7 +1127,8 @@ Corresponding to types in :mod:`collections` .. versionadded:: 3.7.2 .. deprecated:: 3.9 - :class:`collections.OrderedDict` now supports ``[]``. See :pep:`585`. + :class:`collections.OrderedDict` now supports ``[]``. See :pep:`585` and + :ref:`types-genericalias`. .. class:: ChainMap(collections.ChainMap, MutableMapping[KT, VT]) @@ -1129,7 +1138,8 @@ Corresponding to types in :mod:`collections` .. versionadded:: 3.6.1 .. deprecated:: 3.9 - :class:`collections.ChainMap` now supports ``[]``. See :pep:`585`. + :class:`collections.ChainMap` now supports ``[]``. See :pep:`585` and + :ref:`types-genericalias`. .. class:: Counter(collections.Counter, Dict[T, int]) @@ -1139,7 +1149,8 @@ Corresponding to types in :mod:`collections` .. versionadded:: 3.6.1 .. deprecated:: 3.9 - :class:`collections.Counter` now supports ``[]``. See :pep:`585`. + :class:`collections.Counter` now supports ``[]``. See :pep:`585` and + :ref:`types-genericalias`. .. class:: Deque(deque, MutableSequence[T]) @@ -1149,7 +1160,8 @@ Corresponding to types in :mod:`collections` .. versionadded:: 3.6.1 .. deprecated:: 3.9 - :class:`collections.deque` now supports ``[]``. See :pep:`585`. + :class:`collections.deque` now supports ``[]``. See :pep:`585` and + :ref:`types-genericalias`. Other concrete types """""""""""""""""""" @@ -1174,7 +1186,8 @@ Other concrete types ``Match[bytes]``. These types are also in the ``typing.re`` namespace. .. deprecated:: 3.9 - Classes ``Pattern`` and ``Match`` from :mod:`re` now support ``[]``. See :pep:`585`. + Classes ``Pattern`` and ``Match`` from :mod:`re` now support ``[]``. + See :pep:`585` and :ref:`types-genericalias`. .. class:: Text @@ -1201,7 +1214,8 @@ Corresponding to collections in :mod:`collections.abc` A generic version of :class:`collections.abc.Set`. .. deprecated:: 3.9 - :class:`collections.abc.Set` now supports ``[]``. See :pep:`585`. + :class:`collections.abc.Set` now supports ``[]``. See :pep:`585` and + :ref:`types-genericalias`. .. class:: ByteString(Sequence[int]) @@ -1214,7 +1228,8 @@ Corresponding to collections in :mod:`collections.abc` annotate arguments of any of the types mentioned above. .. deprecated:: 3.9 - :class:`collections.abc.ByteString` now supports ``[]``. See :pep:`585`. + :class:`collections.abc.ByteString` now supports ``[]``. See :pep:`585` + and :ref:`types-genericalias`. .. class:: Collection(Sized, Iterable[T_co], Container[T_co]) @@ -1223,28 +1238,32 @@ Corresponding to collections in :mod:`collections.abc` .. versionadded:: 3.6.0 .. deprecated:: 3.9 - :class:`collections.abc.Collection` now supports ``[]``. See :pep:`585`. + :class:`collections.abc.Collection` now supports ``[]``. See :pep:`585` + and :ref:`types-genericalias`. .. class:: Container(Generic[T_co]) A generic version of :class:`collections.abc.Container`. .. deprecated:: 3.9 - :class:`collections.abc.Container` now supports ``[]``. See :pep:`585`. + :class:`collections.abc.Container` now supports ``[]``. See :pep:`585` + and :ref:`types-genericalias`. .. class:: ItemsView(MappingView, Generic[KT_co, VT_co]) A generic version of :class:`collections.abc.ItemsView`. .. deprecated:: 3.9 - :class:`collections.abc.ItemsView` now supports ``[]``. See :pep:`585`. + :class:`collections.abc.ItemsView` now supports ``[]``. See :pep:`585` + and :ref:`types-genericalias`. .. class:: KeysView(MappingView[KT_co], AbstractSet[KT_co]) A generic version of :class:`collections.abc.KeysView`. .. deprecated:: 3.9 - :class:`collections.abc.KeysView` now supports ``[]``. See :pep:`585`. + :class:`collections.abc.KeysView` now supports ``[]``. See :pep:`585` + and :ref:`types-genericalias`. .. class:: Mapping(Sized, Collection[KT], Generic[VT_co]) @@ -1255,49 +1274,56 @@ Corresponding to collections in :mod:`collections.abc` return word_list[word] .. deprecated:: 3.9 - :class:`collections.abc.Mapping` now supports ``[]``. See :pep:`585`. + :class:`collections.abc.Mapping` now supports ``[]``. See :pep:`585` + and :ref:`types-genericalias`. .. class:: MappingView(Sized, Iterable[T_co]) A generic version of :class:`collections.abc.MappingView`. .. deprecated:: 3.9 - :class:`collections.abc.MappingView` now supports ``[]``. See :pep:`585`. + :class:`collections.abc.MappingView` now supports ``[]``. See :pep:`585` + and :ref:`types-genericalias`. .. class:: MutableMapping(Mapping[KT, VT]) A generic version of :class:`collections.abc.MutableMapping`. .. deprecated:: 3.9 - :class:`collections.abc.MutableMapping` now supports ``[]``. See :pep:`585`. + :class:`collections.abc.MutableMapping` now supports ``[]``. See + :pep:`585` and :ref:`types-genericalias`. .. class:: MutableSequence(Sequence[T]) A generic version of :class:`collections.abc.MutableSequence`. .. deprecated:: 3.9 - :class:`collections.abc.MutableSequence` now supports ``[]``. See :pep:`585`. + :class:`collections.abc.MutableSequence` now supports ``[]``. See + :pep:`585` and :ref:`types-genericalias`. .. class:: MutableSet(AbstractSet[T]) A generic version of :class:`collections.abc.MutableSet`. .. deprecated:: 3.9 - :class:`collections.abc.MutableSet` now supports ``[]``. See :pep:`585`. + :class:`collections.abc.MutableSet` now supports ``[]``. See :pep:`585` + and :ref:`types-genericalias`. .. class:: Sequence(Reversible[T_co], Collection[T_co]) A generic version of :class:`collections.abc.Sequence`. .. deprecated:: 3.9 - :class:`collections.abc.Sequence` now supports ``[]``. See :pep:`585`. + :class:`collections.abc.Sequence` now supports ``[]``. See :pep:`585` + and :ref:`types-genericalias`. .. class:: ValuesView(MappingView[VT_co]) A generic version of :class:`collections.abc.ValuesView`. .. deprecated:: 3.9 - :class:`collections.abc.ValuesView` now supports ``[]``. See :pep:`585`. + :class:`collections.abc.ValuesView` now supports ``[]``. See :pep:`585` + and :ref:`types-genericalias`. Corresponding to other types in :mod:`collections.abc` """""""""""""""""""""""""""""""""""""""""""""""""""""" @@ -1307,14 +1333,16 @@ Corresponding to other types in :mod:`collections.abc` A generic version of :class:`collections.abc.Iterable`. .. deprecated:: 3.9 - :class:`collections.abc.Iterable` now supports ``[]``. See :pep:`585`. + :class:`collections.abc.Iterable` now supports ``[]``. See :pep:`585` + and :ref:`types-genericalias`. .. class:: Iterator(Iterable[T_co]) A generic version of :class:`collections.abc.Iterator`. .. deprecated:: 3.9 - :class:`collections.abc.Iterator` now supports ``[]``. See :pep:`585`. + :class:`collections.abc.Iterator` now supports ``[]``. See :pep:`585` + and :ref:`types-genericalias`. .. class:: Generator(Iterator[T_co], Generic[T_co, T_contra, V_co]) @@ -1348,7 +1376,8 @@ Corresponding to other types in :mod:`collections.abc` start += 1 .. deprecated:: 3.9 - :class:`collections.abc.Generator` now supports ``[]``. See :pep:`585`. + :class:`collections.abc.Generator` now supports ``[]``. See :pep:`585` + and :ref:`types-genericalias`. .. class:: Hashable @@ -1359,7 +1388,8 @@ Corresponding to other types in :mod:`collections.abc` A generic version of :class:`collections.abc.Reversible`. .. deprecated:: 3.9 - :class:`collections.abc.Reversible` now supports ``[]``. See :pep:`585`. + :class:`collections.abc.Reversible` now supports ``[]``. See :pep:`585` + and :ref:`types-genericalias`. .. class:: Sized @@ -1384,7 +1414,8 @@ Asynchronous programming .. versionadded:: 3.5.3 .. deprecated:: 3.9 - :class:`collections.abc.Coroutine` now supports ``[]``. See :pep:`585`. + :class:`collections.abc.Coroutine` now supports ``[]``. See :pep:`585` + and :ref:`types-genericalias`. .. class:: AsyncGenerator(AsyncIterator[T_co], Generic[T_co, T_contra]) @@ -1420,7 +1451,8 @@ Asynchronous programming .. versionadded:: 3.6.1 .. deprecated:: 3.9 - :class:`collections.abc.AsyncGenerator` now supports ``[]``. See :pep:`585`. + :class:`collections.abc.AsyncGenerator` now supports ``[]``. See + :pep:`585` and :ref:`types-genericalias`. .. class:: AsyncIterable(Generic[T_co]) @@ -1429,7 +1461,8 @@ Asynchronous programming .. versionadded:: 3.5.2 .. deprecated:: 3.9 - :class:`collections.abc.AsyncIterable` now supports ``[]``. See :pep:`585`. + :class:`collections.abc.AsyncIterable` now supports ``[]``. See :pep:`585` + and :ref:`types-genericalias`. .. class:: AsyncIterator(AsyncIterable[T_co]) @@ -1438,7 +1471,8 @@ Asynchronous programming .. versionadded:: 3.5.2 .. deprecated:: 3.9 - :class:`collections.abc.AsyncIterator` now supports ``[]``. See :pep:`585`. + :class:`collections.abc.AsyncIterator` now supports ``[]``. See :pep:`585` + and :ref:`types-genericalias`. .. class:: Awaitable(Generic[T_co]) @@ -1447,7 +1481,8 @@ Asynchronous programming .. versionadded:: 3.5.2 .. deprecated:: 3.9 - :class:`collections.abc.Awaitable` now supports ``[]``. See :pep:`585`. + :class:`collections.abc.Awaitable` now supports ``[]``. See :pep:`585` + and :ref:`types-genericalias`. Context manager types @@ -1461,7 +1496,8 @@ Context manager types .. versionadded:: 3.6.0 .. deprecated:: 3.9 - :class:`contextlib.AbstractContextManager` now supports ``[]``. See :pep:`585`. + :class:`contextlib.AbstractContextManager` now supports ``[]``. See + :pep:`585` and :ref:`types-genericalias`. .. class:: AsyncContextManager(Generic[T_co]) @@ -1471,7 +1507,8 @@ Context manager types .. versionadded:: 3.6.2 .. deprecated:: 3.9 - :class:`contextlib.AbstractAsyncContextManager` now supports ``[]``. See :pep:`585`. + :class:`contextlib.AbstractAsyncContextManager` now supports ``[]``. See + :pep:`585` and :ref:`types-genericalias`. Protocols --------- diff --git a/Doc/reference/expressions.rst b/Doc/reference/expressions.rst index 938a9732f5a250..512aa5af956198 100644 --- a/Doc/reference/expressions.rst +++ b/Doc/reference/expressions.rst @@ -837,14 +837,8 @@ this method will need to explicitly add that support. A string's items are characters. A character is not a separate data type but a string of exactly one character. -.. - At the time of writing this, there is no documentation for generic alias - or PEP 585. Thus the link currently points to PEP 585 itself. - Please change the link for generic alias to reference the correct - documentation once documentation for PEP 585 becomes available. - Subscription of certain :term:`classes ` or :term:`types ` -creates a `generic alias `_. +creates a :ref:`generic alias `. In this case, user-defined classes can support subscription by providing a :meth:`__class_getitem__` classmethod. From 09c6120be8c70366495b027ae3daa213609de3ed Mon Sep 17 00:00:00 2001 From: "Miss Skeleton (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 30 Oct 2020 15:16:17 -0700 Subject: [PATCH 0659/1314] bpo-42208: GitHub Action: Add gdb to posix dependencies (GH-23043) (GH-23047) Sort also dependencies and remove duplicates (liblzma-dev). (cherry picked from commit 6e03c0ad156797cd6e9132e895d55dac0344d340) Co-authored-by: Victor Stinner Co-authored-by: Victor Stinner --- .github/workflows/posix-deps-apt.sh | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/posix-deps-apt.sh b/.github/workflows/posix-deps-apt.sh index 2b879d32f8150d..5c7b9988be4511 100755 --- a/.github/workflows/posix-deps-apt.sh +++ b/.github/workflows/posix-deps-apt.sh @@ -3,19 +3,19 @@ apt-get update apt-get -yq install \ build-essential \ - zlib1g-dev \ + gdb \ + lcov \ libbz2-dev \ + libffi-dev \ + libgdbm-dev \ liblzma-dev \ libncurses5-dev \ libreadline6-dev \ libsqlite3-dev \ libssl-dev \ - libgdbm-dev \ - tk-dev \ lzma \ lzma-dev \ - liblzma-dev \ - libffi-dev \ + tk-dev \ uuid-dev \ xvfb \ - lcov + zlib1g-dev From ddcd57e3ea75ab0ad370bbaaa6b76338edbca395 Mon Sep 17 00:00:00 2001 From: Pablo Galindo Date: Sat, 31 Oct 2020 00:40:42 +0000 Subject: [PATCH 0660/1314] [3.9] bpo-42214: Fix check for NOTEQUAL token in the PEG parser for the barry_as_flufl rule (GH-23048) (GH-23051) (cherry picked from commit 06f8c3328dcd81c84d1ee2b3a57b5381dcb38482) Co-authored-by: Pablo Galindo --- Grammar/python.gram | 2 +- Lib/test/test_syntax.py | 17 +++++++++++++++++ .../2020-10-30-22-16-30.bpo-42214.lXskM_.rst | 2 ++ Parser/pegen/parse.c | 2 +- Parser/pegen/pegen.c | 3 +-- Parser/pegen/pegen.h | 2 +- 6 files changed, 23 insertions(+), 5 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2020-10-30-22-16-30.bpo-42214.lXskM_.rst diff --git a/Grammar/python.gram b/Grammar/python.gram index b709d3d5c3214f..60eeb367e95ba5 100644 --- a/Grammar/python.gram +++ b/Grammar/python.gram @@ -413,7 +413,7 @@ compare_op_bitwise_or_pair[CmpopExprPair*]: | is_bitwise_or eq_bitwise_or[CmpopExprPair*]: '==' a=bitwise_or { _PyPegen_cmpop_expr_pair(p, Eq, a) } noteq_bitwise_or[CmpopExprPair*]: - | (tok='!=' {_PyPegen_check_barry_as_flufl(p) ? NULL : tok}) a=bitwise_or {_PyPegen_cmpop_expr_pair(p, NotEq, a) } + | (tok='!=' { _PyPegen_check_barry_as_flufl(p, tok) ? NULL : tok}) a=bitwise_or {_PyPegen_cmpop_expr_pair(p, NotEq, a) } lte_bitwise_or[CmpopExprPair*]: '<=' a=bitwise_or { _PyPegen_cmpop_expr_pair(p, LtE, a) } lt_bitwise_or[CmpopExprPair*]: '<' a=bitwise_or { _PyPegen_cmpop_expr_pair(p, Lt, a) } gte_bitwise_or[CmpopExprPair*]: '>=' a=bitwise_or { _PyPegen_cmpop_expr_pair(p, GtE, a) } diff --git a/Lib/test/test_syntax.py b/Lib/test/test_syntax.py index b0527e6cd85ba4..a95992d869e5ea 100644 --- a/Lib/test/test_syntax.py +++ b/Lib/test/test_syntax.py @@ -947,6 +947,23 @@ def test_empty_line_after_linecont(self): self.fail("Empty line after a line continuation character is valid.") + def test_barry_as_flufl_with_syntax_errors(self): + # The "barry_as_flufl" rule can produce some "bugs-at-a-distance" if + # is reading the wrong token in the presence of syntax errors later + # in the file. See bpo-42214 for more information. + code = """ +def func1(): + if a != b: + raise ValueError + +def func2(): + try + return 1 + finally: + pass +""" + self._check_error(code, "invalid syntax") + def test_main(): support.run_unittest(SyntaxTestCase) from test import test_syntax diff --git a/Misc/NEWS.d/next/Core and Builtins/2020-10-30-22-16-30.bpo-42214.lXskM_.rst b/Misc/NEWS.d/next/Core and Builtins/2020-10-30-22-16-30.bpo-42214.lXskM_.rst new file mode 100644 index 00000000000000..3f85bbe83901a0 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2020-10-30-22-16-30.bpo-42214.lXskM_.rst @@ -0,0 +1,2 @@ +Fixed a possible crash in the PEG parser when checking for the '!=' token in +the ``barry_as_flufl`` rule. Patch by Pablo Galindo. diff --git a/Parser/pegen/parse.c b/Parser/pegen/parse.c index 48a24434746848..bae9463e274a35 100644 --- a/Parser/pegen/parse.c +++ b/Parser/pegen/parse.c @@ -21307,7 +21307,7 @@ _tmp_93_rule(Parser *p) ) { D(fprintf(stderr, "%*c+ _tmp_93[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'!='")); - _res = _PyPegen_check_barry_as_flufl ( p ) ? NULL : tok; + _res = _PyPegen_check_barry_as_flufl ( p , tok ) ? NULL : tok; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; D(p->level--); diff --git a/Parser/pegen/pegen.c b/Parser/pegen/pegen.c index 78891af8250073..4e742a5ec71751 100644 --- a/Parser/pegen/pegen.c +++ b/Parser/pegen/pegen.c @@ -62,8 +62,7 @@ init_normalization(Parser *p) /* Checks if the NOTEQUAL token is valid given the current parser flags 0 indicates success and nonzero indicates failure (an exception may be set) */ int -_PyPegen_check_barry_as_flufl(Parser *p) { - Token *t = p->tokens[p->fill - 1]; +_PyPegen_check_barry_as_flufl(Parser *p, Token* t) { assert(t->bytes != NULL); assert(t->type == NOTEQUAL); diff --git a/Parser/pegen/pegen.h b/Parser/pegen/pegen.h index 2fea84fd22ab40..a2f524a597d232 100644 --- a/Parser/pegen/pegen.h +++ b/Parser/pegen/pegen.h @@ -263,7 +263,7 @@ expr_ty _PyPegen_collect_call_seqs(Parser *, asdl_seq *, asdl_seq *, int end_col_offset, PyArena *arena); expr_ty _PyPegen_concatenate_strings(Parser *p, asdl_seq *); asdl_seq *_PyPegen_join_sequences(Parser *, asdl_seq *, asdl_seq *); -int _PyPegen_check_barry_as_flufl(Parser *); +int _PyPegen_check_barry_as_flufl(Parser *, Token *); mod_ty _PyPegen_make_module(Parser *, asdl_seq *); // Error reporting helpers From dbaa07db671c4e5842629c8be912f2b0370be794 Mon Sep 17 00:00:00 2001 From: kj <28750310+Fidget-Spinner@users.noreply.github.com> Date: Sat, 31 Oct 2020 23:05:36 +0800 Subject: [PATCH 0661/1314] [3.9] bpo-42198: Document __new__ for types.GenericAlias (GH-23039) (GH-23061) (cherry picked from commit bcbf758476c1148993ddf4b54d3f6169b973ee1c) --- Doc/library/stdtypes.rst | 3 ++- Doc/library/types.rst | 13 ++++++++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst index e19e76f8311c8e..a48cfa13277910 100644 --- a/Doc/library/stdtypes.rst +++ b/Doc/library/stdtypes.rst @@ -4760,7 +4760,8 @@ The ``GenericAlias`` object acts as a proxy for :term:`generic types of a generic which provides the types for container elements. The user-exposed type for the ``GenericAlias`` object can be accessed from -:data:`types.GenericAlias` and used for :func:`isinstance` checks. +:class:`types.GenericAlias` and used for :func:`isinstance` checks. It can +also be used to create ``GenericAlias`` objects directly. .. describe:: T[X, Y, ...] diff --git a/Doc/library/types.rst b/Doc/library/types.rst index 1573e460f2f2be..5d68c6852678c2 100644 --- a/Doc/library/types.rst +++ b/Doc/library/types.rst @@ -242,11 +242,22 @@ Standard names are defined for the following types: Defaults to ``None``. Previously the attribute was optional. -.. data:: GenericAlias +.. class:: GenericAlias(t_origin, t_args) The type of :ref:`parameterized generics ` such as ``list[int]``. + ``t_origin`` should be a non-parameterized generic class, such as ``list``, + ``tuple`` or ``dict``. ``t_args`` should be a :class:`tuple` (possibly of + length 1) of types which parameterize ``t_origin``:: + + >>> from types import GenericAlias + + >>> list[int] == GenericAlias(list, (int,)) + True + >>> dict[str, int] == GenericAlias(dict, (str, int)) + True + .. versionadded:: 3.9 From cfcb952e30e01d7cce430829af8edc7afc94e0b1 Mon Sep 17 00:00:00 2001 From: Lysandros Nikolaou Date: Sat, 31 Oct 2020 21:06:03 +0200 Subject: [PATCH 0662/1314] [3.9] bpo-42218: Correctly handle errors in left-recursive rules (GH-23065) (GH-23066) Left-recursive rules need to check for errors explicitly, since even if the rule returns NULL, the parsing might continue and lead to long-distance failures. Co-authored-by: Pablo Galindo (cherry picked from commit 02cdfc93f82fecdb7eae97a868d4ee222b9875d9) Automerge-Triggered-By: GH:lysnikolaou --- Lib/test/test_syntax.py | 8 ++++++++ .../2020-10-31-17-50-23.bpo-42218.Dp_Z3v.rst | 3 +++ Parser/pegen/parse.c | 18 ++++++++++++++++++ Tools/peg_generator/pegen/c_generator.py | 3 +++ 4 files changed, 32 insertions(+) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2020-10-31-17-50-23.bpo-42218.Dp_Z3v.rst diff --git a/Lib/test/test_syntax.py b/Lib/test/test_syntax.py index a95992d869e5ea..1336231fbbfbfa 100644 --- a/Lib/test/test_syntax.py +++ b/Lib/test/test_syntax.py @@ -964,6 +964,14 @@ def func2(): """ self._check_error(code, "invalid syntax") + def test_invalid_line_continuation_left_recursive(self): + # Check bpo-42218: SyntaxErrors following left-recursive rules + # (t_primary_raw in this case) need to be tested explicitly + self._check_error("A.\u018a\\ ", + "unexpected character after line continuation character") + self._check_error("A.\u03bc\\\n", + "unexpected EOF while parsing") + def test_main(): support.run_unittest(SyntaxTestCase) from test import test_syntax diff --git a/Misc/NEWS.d/next/Core and Builtins/2020-10-31-17-50-23.bpo-42218.Dp_Z3v.rst b/Misc/NEWS.d/next/Core and Builtins/2020-10-31-17-50-23.bpo-42218.Dp_Z3v.rst new file mode 100644 index 00000000000000..a38a310e4b45b8 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2020-10-31-17-50-23.bpo-42218.Dp_Z3v.rst @@ -0,0 +1,3 @@ +Fixed a bug in the PEG parser that was causing crashes in debug mode. Now errors are checked +in left-recursive rules to avoid cases where such errors do not get handled in time and appear +as long-distance crashes in other places. diff --git a/Parser/pegen/parse.c b/Parser/pegen/parse.c index bae9463e274a35..97cefa9c2a3d42 100644 --- a/Parser/pegen/parse.c +++ b/Parser/pegen/parse.c @@ -3460,6 +3460,8 @@ dotted_name_rule(Parser *p) } p->mark = _mark; void *_raw = dotted_name_raw(p); + if (p->error_indicator) + return NULL; if (_raw == NULL || p->mark <= _resmark) break; _resmark = p->mark; @@ -9044,6 +9046,8 @@ bitwise_or_rule(Parser *p) } p->mark = _mark; void *_raw = bitwise_or_raw(p); + if (p->error_indicator) + return NULL; if (_raw == NULL || p->mark <= _resmark) break; _resmark = p->mark; @@ -9158,6 +9162,8 @@ bitwise_xor_rule(Parser *p) } p->mark = _mark; void *_raw = bitwise_xor_raw(p); + if (p->error_indicator) + return NULL; if (_raw == NULL || p->mark <= _resmark) break; _resmark = p->mark; @@ -9272,6 +9278,8 @@ bitwise_and_rule(Parser *p) } p->mark = _mark; void *_raw = bitwise_and_raw(p); + if (p->error_indicator) + return NULL; if (_raw == NULL || p->mark <= _resmark) break; _resmark = p->mark; @@ -9386,6 +9394,8 @@ shift_expr_rule(Parser *p) } p->mark = _mark; void *_raw = shift_expr_raw(p); + if (p->error_indicator) + return NULL; if (_raw == NULL || p->mark <= _resmark) break; _resmark = p->mark; @@ -9539,6 +9549,8 @@ sum_rule(Parser *p) } p->mark = _mark; void *_raw = sum_raw(p); + if (p->error_indicator) + return NULL; if (_raw == NULL || p->mark <= _resmark) break; _resmark = p->mark; @@ -9698,6 +9710,8 @@ term_rule(Parser *p) } p->mark = _mark; void *_raw = term_raw(p); + if (p->error_indicator) + return NULL; if (_raw == NULL || p->mark <= _resmark) break; _resmark = p->mark; @@ -10302,6 +10316,8 @@ primary_rule(Parser *p) } p->mark = _mark; void *_raw = primary_raw(p); + if (p->error_indicator) + return NULL; if (_raw == NULL || p->mark <= _resmark) break; _resmark = p->mark; @@ -13962,6 +13978,8 @@ t_primary_rule(Parser *p) } p->mark = _mark; void *_raw = t_primary_raw(p); + if (p->error_indicator) + return NULL; if (_raw == NULL || p->mark <= _resmark) break; _resmark = p->mark; diff --git a/Tools/peg_generator/pegen/c_generator.py b/Tools/peg_generator/pegen/c_generator.py index d0abc12b4026ae..b4d6a0bab51f4a 100644 --- a/Tools/peg_generator/pegen/c_generator.py +++ b/Tools/peg_generator/pegen/c_generator.py @@ -496,6 +496,9 @@ def _set_up_rule_memoization(self, node: Rule, result_type: str) -> None: ) self.print("p->mark = _mark;") self.print(f"void *_raw = {node.name}_raw(p);") + self.print("if (p->error_indicator)") + with self.indent(): + self.print("return NULL;") self.print("if (_raw == NULL || p->mark <= _resmark)") with self.indent(): self.print("break;") From 3defcbac2c9ff4306ed5b7fb37d12637eb188306 Mon Sep 17 00:00:00 2001 From: "Miss Skeleton (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 1 Nov 2020 01:39:26 -0800 Subject: [PATCH 0663/1314] [3.9] bpo-29566: binhex.binhex now consitently writes MacOS 9 line endings. (GH-23059) (GH-23071) [[bpo-29566]()]() notes that binhex.binhex uses inconsistent line endings (both Unix and MacOS9 line endings are used). This PR changes this to use the MacOS9 line endings everywhere. (cherry picked from commit 2165cea548f961b308050f30d1f042a377651d44) Co-authored-by: Ronald Oussoren Automerge-Triggered-By: GH:ronaldoussoren --- Lib/binhex.py | 4 ++-- Lib/test/test_binhex.py | 12 ++++++++++++ .../Library/2020-10-31-13-28-36.bpo-29566.6aDbty.rst | 1 + 3 files changed, 15 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2020-10-31-13-28-36.bpo-29566.6aDbty.rst diff --git a/Lib/binhex.py b/Lib/binhex.py index 9559f46d5a2882..ace5217d271392 100644 --- a/Lib/binhex.py +++ b/Lib/binhex.py @@ -117,12 +117,12 @@ def _flush(self, force): first = 0 while first <= len(self.hqxdata) - self.linelen: last = first + self.linelen - self.ofp.write(self.hqxdata[first:last] + b'\n') + self.ofp.write(self.hqxdata[first:last] + b'\r') self.linelen = LINELEN first = last self.hqxdata = self.hqxdata[first:] if force: - self.ofp.write(self.hqxdata + b':\n') + self.ofp.write(self.hqxdata + b':\r') def close(self): if self.data: diff --git a/Lib/test/test_binhex.py b/Lib/test/test_binhex.py index 591f32a4f0f7f0..9c9486e142a902 100644 --- a/Lib/test/test_binhex.py +++ b/Lib/test/test_binhex.py @@ -48,6 +48,18 @@ def test_binhex_error_on_long_filename(self): self.assertRaises(binhex.Error, binhex.binhex, self.fname3, self.fname2) + def test_binhex_line_endings(self): + # bpo-29566: Ensure the line endings are those for macOS 9 + with open(self.fname1, 'wb') as f: + f.write(self.DATA) + + binhex.binhex(self.fname1, self.fname2) + + with open(self.fname2, 'rb') as fp: + contents = fp.read() + + self.assertNotIn(b'\n', contents) + def test_main(): support.run_unittest(BinHexTestCase) diff --git a/Misc/NEWS.d/next/Library/2020-10-31-13-28-36.bpo-29566.6aDbty.rst b/Misc/NEWS.d/next/Library/2020-10-31-13-28-36.bpo-29566.6aDbty.rst new file mode 100644 index 00000000000000..d54c714688531a --- /dev/null +++ b/Misc/NEWS.d/next/Library/2020-10-31-13-28-36.bpo-29566.6aDbty.rst @@ -0,0 +1 @@ +``binhex.binhex()`` consisently writes macOS 9 line endings. From 0312efcd2bb3d7964dbfe2b4cbd5f5b440aed049 Mon Sep 17 00:00:00 2001 From: "Miss Skeleton (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 1 Nov 2020 05:27:01 -0800 Subject: [PATCH 0664/1314] bpo-37483: Add PyObject_CallOneArg() in the What's New in Python 3.9 (GH-23062) (cherry picked from commit 7feb54a6348f6220b27986777786c812f110b53d) Co-authored-by: Dong-hee Na --- Doc/whatsnew/3.9.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Doc/whatsnew/3.9.rst b/Doc/whatsnew/3.9.rst index 1a37f16ea2b09a..a601b16f1c6059 100644 --- a/Doc/whatsnew/3.9.rst +++ b/Doc/whatsnew/3.9.rst @@ -1289,6 +1289,10 @@ New Features representation of a function-like object. (Patch by Jeroen Demeyer in :issue:`37645`.) +* Added :c:func:`PyObject_CallOneArg` for calling an object with one + positional argument + (Patch by Jeroen Demeyer in :issue:`37483`.) + Porting to Python 3.9 --------------------- From 81dd2c0914dc422b46ce898f61ad1c7049f9dd08 Mon Sep 17 00:00:00 2001 From: "Miss Skeleton (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 1 Nov 2020 10:09:46 -0800 Subject: [PATCH 0665/1314] Expand and clarify the "Invoking Descriptors" section of the Descriptor HowTo (GH-23078) (GH-23080) --- Doc/howto/descriptor.rst | 115 +++++++++++++++++++++++++------------ Doc/tools/susp-ignored.csv | 2 +- 2 files changed, 79 insertions(+), 38 deletions(-) diff --git a/Doc/howto/descriptor.rst b/Doc/howto/descriptor.rst index f1d1ab1d1d6101..5de6d32f22f906 100644 --- a/Doc/howto/descriptor.rst +++ b/Doc/howto/descriptor.rst @@ -52,7 +52,7 @@ To use the descriptor, it must be stored as a class variable in another class:: class A: x = 5 # Regular class attribute - y = Ten() # Descriptor + y = Ten() # Descriptor instance An interactive session shows the difference between normal attribute lookup and descriptor lookup:: @@ -80,7 +80,6 @@ Dynamic lookups Interesting descriptors typically run computations instead of doing lookups:: - import os class DirectorySize: @@ -90,7 +89,7 @@ Interesting descriptors typically run computations instead of doing lookups:: class Directory: - size = DirectorySize() # Descriptor + size = DirectorySize() # Descriptor instance def __init__(self, dirname): self.dirname = dirname # Regular instance attribute @@ -147,11 +146,11 @@ the lookup or update:: class Person: - age = LoggedAgeAccess() # Descriptor + age = LoggedAgeAccess() # Descriptor instance def __init__(self, name, age): self.name = name # Regular instance attribute - self.age = age # Calls the descriptor + self.age = age # Calls __set__() def birthday(self): self.age += 1 # Calls both __get__() and __set__() @@ -221,8 +220,8 @@ be recorded, giving each descriptor its own *public_name* and *private_name*:: class Person: - name = LoggedAccess() # First descriptor - age = LoggedAccess() # Second descriptor + name = LoggedAccess() # First descriptor instance + age = LoggedAccess() # Second descriptor instance def __init__(self, name, age): self.name = name # Calls the first descriptor @@ -494,56 +493,98 @@ called. Defining the :meth:`__set__` method with an exception raising placeholder is enough to make it a data descriptor. -Invoking Descriptors --------------------- +Overview of Descriptor Invocation +--------------------------------- -A descriptor can be called directly by its method name. For example, -``d.__get__(obj)``. +A descriptor can be called directly with ``desc.__get__(obj)`` or +``desc.__get__(None, cls)``. But it is more common for a descriptor to be invoked automatically from -attribute access. The expression ``obj.d`` looks up ``d`` in the dictionary of -``obj``. If ``d`` defines the method :meth:`__get__`, then ``d.__get__(obj)`` -is invoked according to the precedence rules listed below. +attribute access. + +The expression ``obj.x`` looks up the attribute ``x`` in the chain of +namespaces for ``obj``. If the search finds a descriptor, its :meth:`__get__` +method is invoked according to the precedence rules listed below. The details of invocation depend on whether ``obj`` is an object, class, or instance of super. -**Objects**: The machinery is in :meth:`object.__getattribute__`. -It transforms ``b.x`` into ``type(b).__dict__['x'].__get__(b, type(b))``. +Invocation from an Instance +--------------------------- + +Instance lookup scans through a chain of namespaces giving data descriptors +the highest priority, followed by instance variables, then non-data +descriptors, then class variables, and lastly :meth:`__getattr__` if it is +provided. + +If a descriptor is found for ``a.x``, then it is invoked with: +``desc.__get__(a, type(a))``. + +The logic for a dotted lookup is in :meth:`object.__getattribute__`. Here is +a pure Python equivalent:: + + def object_getattribute(obj, name): + "Emulate PyObject_GenericGetAttr() in Objects/object.c" + null = object() + objtype = type(obj) + value = getattr(objtype, name, null) + if value is not null and hasattr(value, '__get__'): + if hasattr(value, '__set__') or hasattr(value, '__delete__'): + return value.__get__(obj, objtype) # data descriptor + try: + return vars(obj)[name] # instance variable + except (KeyError, TypeError): + pass + if hasattr(value, '__get__'): + return value.__get__(obj, objtype) # non-data descriptor + if value is not null: + return value # class variable + # Emulate slot_tp_getattr_hook() in Objects/typeobject.c + if hasattr(objtype, '__getattr__'): + return objtype.__getattr__(obj, name) # __getattr__ hook + raise AttributeError(name) + +The :exc:`TypeError` exception handler is needed because the instance dictionary +doesn't exist when its class defines :term:`__slots__`. -The implementation works through a precedence chain that gives data descriptors -priority over instance variables, instance variables priority over non-data -descriptors, and assigns lowest priority to :meth:`__getattr__` if provided. -The full C implementation can be found in :c:func:`PyObject_GenericGetAttr()` in -:source:`Objects/object.c`. +Invocation from a Class +----------------------- -**Classes**: The machinery is in :meth:`type.__getattribute__`. +The logic for a dotted lookup such as ``A.x`` is in +:meth:`type.__getattribute__`. The steps are similar to those for +:meth:`object.__getattribute__` but the instance dictionary lookup is replaced +by a search through the class's :term:`method resolution order`. -It transforms ``A.x`` into ``A.__dict__['x'].__get__(None, A)``. +If a descriptor is found, it is invoked with ``desc.__get__(None, A)``. -The full C implementation can be found in :c:func:`type_getattro()` in -:source:`Objects/typeobject.c`. +The full C implementation can be found in :c:func:`type_getattro()` and +:c:func:`_PyType_Lookup()` in :source:`Objects/typeobject.c`. -**Super**: The machinery is in the custom :meth:`__getattribute__` method for + +Invocation from Super +--------------------- + +The logic for super's dotted lookup is in the :meth:`__getattribute__` method for object returned by :class:`super()`. -The attribute lookup ``super(A, obj).m`` searches ``obj.__class__.__mro__`` for -the base class ``B`` immediately following ``A`` and then returns +A dotted lookup such as ``super(A, obj).m`` searches ``obj.__class__.__mro__`` +for the base class ``B`` immediately following ``A`` and then returns ``B.__dict__['m'].__get__(obj, A)``. If not a descriptor, ``m`` is returned -unchanged. If not in the dictionary, ``m`` reverts to a search using -:meth:`object.__getattribute__`. +unchanged. -The implementation details are in :c:func:`super_getattro()` in +The full C implementation can be found in :c:func:`super_getattro()` in :source:`Objects/typeobject.c`. A pure Python equivalent can be found in -`Guido's Tutorial`_. +`Guido's Tutorial +`_. -.. _`Guido's Tutorial`: https://www.python.org/download/releases/2.2.3/descrintro/#cooperation -**Summary**: The mechanism for descriptors is embedded in the -:meth:`__getattribute__()` methods for :class:`object`, :class:`type`, and -:func:`super`. +Summary of Invocation Logic +--------------------------- + +The mechanism for descriptors is embedded in the :meth:`__getattribute__()` +methods for :class:`object`, :class:`type`, and :func:`super`. The important points to remember are: @@ -652,7 +693,7 @@ Pure Python Equivalents ^^^^^^^^^^^^^^^^^^^^^^^ The descriptor protocol is simple and offers exciting possibilities. Several -use cases are so common that they have been prepackaged into builtin tools. +use cases are so common that they have been prepackaged into built-in tools. Properties, bound methods, static methods, and class methods are all based on the descriptor protocol. diff --git a/Doc/tools/susp-ignored.csv b/Doc/tools/susp-ignored.csv index 7739e7ab7603dd..c9777c6be9334d 100644 --- a/Doc/tools/susp-ignored.csv +++ b/Doc/tools/susp-ignored.csv @@ -5,7 +5,7 @@ c-api/sequence,,:i2,o[i1:i2] c-api/tuple,,:high,p[low:high] c-api/unicode,,:end,str[start:end] c-api/unicode,,:start,unicode[start:start+length] -distutils/examples,267,`,This is the description of the ``foobar`` package. +distutils/examples,,`,This is the description of the ``foobar`` package. distutils/setupscript,,::, extending/embedding,,:numargs,"if(!PyArg_ParseTuple(args, "":numargs""))" extending/extending,,:myfunction,"PyArg_ParseTuple(args, ""D:myfunction"", &c);" From d4cfbfe9a206494cfb6107d2e07699674c60c462 Mon Sep 17 00:00:00 2001 From: "Miss Skeleton (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 1 Nov 2020 18:27:58 -0800 Subject: [PATCH 0666/1314] Add member objects to the descriptor howto guide (GH-23084) (GH-23090) --- Doc/howto/descriptor.rst | 156 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 156 insertions(+) diff --git a/Doc/howto/descriptor.rst b/Doc/howto/descriptor.rst index 5de6d32f22f906..5373025e5407de 100644 --- a/Doc/howto/descriptor.rst +++ b/Doc/howto/descriptor.rst @@ -990,3 +990,159 @@ For example, a classmethod and property could be chained together:: @property def __doc__(cls): return f'A doc for {cls.__name__!r}' + +Member Objects +-------------- + +When a class defines ``__slots__``, it replaces instance dictionaries with a +fixed-length array of slot values. From a user point of view that has +several effects: + +1. Provides immediate detection of bugs due to misspelled attribute +assignments. Only attribute names specified in ``__slots__`` are allowed:: + + class Vehicle: + __slots__ = ('id_number', 'make', 'model') + + >>> auto = Vehicle() + >>> auto.id_nubmer = 'VYE483814LQEX' + Traceback (most recent call last): + ... + AttributeError: 'Vehicle' object has no attribute 'id_nubmer' + +2. Helps create immutable objects where descriptors manage access to private +attributes stored in ``__slots__``:: + + class Immutable: + + __slots__ = ('_dept', '_name') # Replace instance dictionary + + def __init__(self, dept, name): + self._dept = dept # Store to private attribute + self._name = name # Store to private attribute + + @property # Read-only descriptor + def dept(self): + return self._dept + + @property + def name(self): # Read-only descriptor + return self._name + + mark = Immutable('Botany', 'Mark Watney') # Create an immutable instance + +3. Saves memory. On a 64-bit Linux build, an instance with two attributes +takes 48 bytes with ``__slots__`` and 152 bytes without. This `flyweight +design pattern `_ likely only +matters when a large number of instances are going to be created. + +4. Blocks tools like :func:`functools.cached_property` which require an +instance dictionary to function correctly:: + + from functools import cached_property + + class CP: + __slots__ = () # Eliminates the instance dict + + @cached_property # Requires an instance dict + def pi(self): + return 4 * sum((-1.0)**n / (2.0*n + 1.0) + for n in reversed(range(100_000))) + + >>> CP().pi + Traceback (most recent call last): + ... + TypeError: No '__dict__' attribute on 'CP' instance to cache 'pi' property. + +It's not possible to create an exact drop-in pure Python version of +``__slots__`` because it requires direct access to C structures and control +over object memory allocation. However, we can build a mostly faithful +simulation where the actual C structure for slots is emulated by a private +``_slotvalues`` list. Reads and writes to that private structure are managed +by member descriptors:: + + class Member: + + def __init__(self, name, clsname, offset): + 'Emulate PyMemberDef in Include/structmember.h' + # Also see descr_new() in Objects/descrobject.c + self.name = name + self.clsname = clsname + self.offset = offset + + def __get__(self, obj, objtype=None): + 'Emulate member_get() in Objects/descrobject.c' + # Also see PyMember_GetOne() in Python/structmember.c + return obj._slotvalues[self.offset] + + def __set__(self, obj, value): + 'Emulate member_set() in Objects/descrobject.c' + obj._slotvalues[self.offset] = value + + def __repr__(self): + 'Emulate member_repr() in Objects/descrobject.c' + return f'' + +The :meth:`type.__new__` method takes care of adding member objects to class +variables. The :meth:`object.__new__` method takes care of creating instances +that have slots instead of a instance dictionary. Here is a rough equivalent +in pure Python:: + + class Type(type): + 'Simulate how the type metaclass adds member objects for slots' + + def __new__(mcls, clsname, bases, mapping): + 'Emuluate type_new() in Objects/typeobject.c' + # type_new() calls PyTypeReady() which calls add_methods() + slot_names = mapping.get('slot_names', []) + for offset, name in enumerate(slot_names): + mapping[name] = Member(name, clsname, offset) + return type.__new__(mcls, clsname, bases, mapping) + + class Object: + 'Simulate how object.__new__() allocates memory for __slots__' + + def __new__(cls, *args): + 'Emulate object_new() in Objects/typeobject.c' + inst = super().__new__(cls) + if hasattr(cls, 'slot_names'): + inst._slotvalues = [None] * len(cls.slot_names) + return inst + +To use the simulation in a real class, just inherit from :class:`Object` and +set the :term:`metaclass` to :class:`Type`:: + + class H(Object, metaclass=Type): + + slot_names = ['x', 'y'] + + def __init__(self, x, y): + self.x = x + self.y = y + +At this point, the metaclass has loaded member objects for *x* and *y*:: + + >>> import pprint + >>> pprint.pp(dict(vars(H))) + {'__module__': '__main__', + 'slot_names': ['x', 'y'], + '__init__': , + 'x': , + 'y': , + '__doc__': None} + +When instances are created, they have a ``slot_values`` list where the +attributes are stored:: + + >>> h = H(10, 20) + >>> vars(h) + {'_slotvalues': [10, 20]} + >>> h.x = 55 + >>> vars(h) + {'_slotvalues': [55, 20]} + +Unlike the real ``__slots__``, this simulation does have an instance +dictionary just to hold the ``_slotvalues`` array. So, unlike the real code, +this simulation doesn't block assignments to misspelled attributes:: + + >>> h.xz = 30 # For actual __slots__ this would raise an AttributeError From 79e9f06149f92798a8e11e3f1c62dad171312ab3 Mon Sep 17 00:00:00 2001 From: "Miss Skeleton (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 1 Nov 2020 20:49:39 -0800 Subject: [PATCH 0667/1314] bpo-40511: Stop unwanted flashing of IDLE calltips (GH-20910) They were occurring with both repeated 'force-calltip' invocations and by typing parentheses in expressions, strings, and comments in the argument code. Co-authored-by: Terry Jan Reedy (cherry picked from commit da7bb7b4d769350c5fd03e6cfb16b23dc265ed72) Co-authored-by: Tal Einat --- Lib/idlelib/calltip.py | 36 ++++++- Lib/idlelib/idle_test/mock_tk.py | 13 ++- Lib/idlelib/idle_test/test_calltip.py | 99 ++++++++++++++++++- .../2020-06-16-12-16-13.bpo-40511.XkihpM.rst | 3 + 4 files changed, 144 insertions(+), 7 deletions(-) create mode 100644 Misc/NEWS.d/next/IDLE/2020-06-16-12-16-13.bpo-40511.XkihpM.rst diff --git a/Lib/idlelib/calltip.py b/Lib/idlelib/calltip.py index b02f87207d8db1..549e224015cccb 100644 --- a/Lib/idlelib/calltip.py +++ b/Lib/idlelib/calltip.py @@ -55,18 +55,50 @@ def refresh_calltip_event(self, event): self.open_calltip(False) def open_calltip(self, evalfuncs): - self.remove_calltip_window() + """Maybe close an existing calltip and maybe open a new calltip. + Called from (force_open|try_open|refresh)_calltip_event functions. + """ hp = HyperParser(self.editwin, "insert") sur_paren = hp.get_surrounding_brackets('(') + + # If not inside parentheses, no calltip. if not sur_paren: + self.remove_calltip_window() return + + # If a calltip is shown for the current parentheses, do + # nothing. + if self.active_calltip: + opener_line, opener_col = map(int, sur_paren[0].split('.')) + if ( + (opener_line, opener_col) == + (self.active_calltip.parenline, self.active_calltip.parencol) + ): + return + hp.set_index(sur_paren[0]) - expression = hp.get_expression() + try: + expression = hp.get_expression() + except ValueError: + expression = None if not expression: + # No expression before the opening parenthesis, e.g. + # because it's in a string or the opener for a tuple: + # Do nothing. return + + # At this point, the current index is after an opening + # parenthesis, in a section of code, preceded by a valid + # expression. If there is a calltip shown, it's not for the + # same index and should be closed. + self.remove_calltip_window() + + # Simple, fast heuristic: If the preceding expression includes + # an opening parenthesis, it likely includes a function call. if not evalfuncs and (expression.find('(') != -1): return + argspec = self.fetch_tip(expression) if not argspec: return diff --git a/Lib/idlelib/idle_test/mock_tk.py b/Lib/idlelib/idle_test/mock_tk.py index 576f7d5d609e4d..b736bd001da87f 100644 --- a/Lib/idlelib/idle_test/mock_tk.py +++ b/Lib/idlelib/idle_test/mock_tk.py @@ -3,6 +3,9 @@ A gui object is anything with a master or parent parameter, which is typically required in spite of what the doc strings say. """ +import re +from _tkinter import TclError + class Event: '''Minimal mock with attributes for testing event handlers. @@ -22,6 +25,7 @@ def __init__(self, **kwds): "Create event with attributes needed for test" self.__dict__.update(kwds) + class Var: "Use for String/Int/BooleanVar: incomplete" def __init__(self, master=None, value=None, name=None): @@ -33,6 +37,7 @@ def set(self, value): def get(self): return self.value + class Mbox_func: """Generic mock for messagebox functions, which all have the same signature. @@ -50,6 +55,7 @@ def __call__(self, title, message, *args, **kwds): self.kwds = kwds return self.result # Set by tester for ask functions + class Mbox: """Mock for tkinter.messagebox with an Mbox_func for each function. @@ -85,7 +91,6 @@ def tearDownClass(cls): showinfo = Mbox_func() # None showwarning = Mbox_func() # None -from _tkinter import TclError class Text: """A semi-functional non-gui replacement for tkinter.Text text editors. @@ -154,6 +159,8 @@ def _decode(self, index, endflag=0): if char.endswith(' lineend') or char == 'end': return line, linelength # Tk requires that ignored chars before ' lineend' be valid int + if m := re.fullmatch(r'end-(\d*)c', char, re.A): # Used by hyperparser. + return line, linelength - int(m.group(1)) # Out of bounds char becomes first or last index of line char = int(char) @@ -177,7 +184,6 @@ def _endex(self, endflag): n -= 1 return n, len(self.data[n]) + endflag - def insert(self, index, chars): "Insert chars before the character at index." @@ -193,7 +199,6 @@ def insert(self, index, chars): self.data[line+1:line+1] = chars[1:] self.data[line+len(chars)-1] += after - def get(self, index1, index2=None): "Return slice from index1 to index2 (default is 'index1+1')." @@ -212,7 +217,6 @@ def get(self, index1, index2=None): lines.append(self.data[endline][:endchar]) return ''.join(lines) - def delete(self, index1, index2=None): '''Delete slice from index1 to index2 (default is 'index1+1'). @@ -297,6 +301,7 @@ def bind(sequence=None, func=None, add=None): "Bind to this widget at event sequence a call to function func." pass + class Entry: "Mock for tkinter.Entry." def focus_set(self): diff --git a/Lib/idlelib/idle_test/test_calltip.py b/Lib/idlelib/idle_test/test_calltip.py index 4d53df17d8cc7c..489b6899baf424 100644 --- a/Lib/idlelib/idle_test/test_calltip.py +++ b/Lib/idlelib/idle_test/test_calltip.py @@ -1,10 +1,12 @@ -"Test calltip, coverage 60%" +"Test calltip, coverage 76%" from idlelib import calltip import unittest +from unittest.mock import Mock import textwrap import types import re +from idlelib.idle_test.mock_tk import Text # Test Class TC is used in multiple get_argspec test methods @@ -257,5 +259,100 @@ def test_good_entity(self): self.assertIs(calltip.get_entity('int'), int) +# Test the 9 Calltip methods. +# open_calltip is about half the code; the others are fairly trivial. +# The default mocks are what are needed for open_calltip. + +class mock_Shell(): + "Return mock sufficient to pass to hyperparser." + def __init__(self, text): + text.tag_prevrange = Mock(return_value=None) + self.text = text + self.prompt_last_line = ">>> " + self.indentwidth = 4 + self.tabwidth = 8 + + +class mock_TipWindow: + def __init__(self): + pass + + def showtip(self, text, parenleft, parenright): + self.args = parenleft, parenright + self.parenline, self.parencol = map(int, parenleft.split('.')) + + +class WrappedCalltip(calltip.Calltip): + def _make_tk_calltip_window(self): + return mock_TipWindow() + + def remove_calltip_window(self, event=None): + if self.active_calltip: # Setup to None. + self.active_calltip = None + self.tips_removed += 1 # Setup to 0. + + def fetch_tip(self, expression): + return 'tip' + + +class CalltipTest(unittest.TestCase): + + @classmethod + def setUpClass(cls): + cls.text = Text() + cls.ct = WrappedCalltip(mock_Shell(cls.text)) + + def setUp(self): + self.text.delete('1.0', 'end') # Insert and call + self.ct.active_calltip = None + # Test .active_calltip, +args + self.ct.tips_removed = 0 + + def open_close(self, testfunc): + # Open-close template with testfunc called in between. + opentip = self.ct.open_calltip + self.text.insert(1.0, 'f(') + opentip(False) + self.tip = self.ct.active_calltip + testfunc(self) ### + self.text.insert('insert', ')') + opentip(False) + self.assertIsNone(self.ct.active_calltip, None) + + def test_open_close(self): + def args(self): + self.assertEqual(self.tip.args, ('1.1', '1.end')) + self.open_close(args) + + def test_repeated_force(self): + def force(self): + for char in 'abc': + self.text.insert('insert', 'a') + self.ct.open_calltip(True) + self.ct.open_calltip(True) + self.assertIs(self.ct.active_calltip, self.tip) + self.open_close(force) + + def test_repeated_parens(self): + def parens(self): + for context in "a", "'": + with self.subTest(context=context): + self.text.insert('insert', context) + for char in '(()())': + self.text.insert('insert', char) + self.assertIs(self.ct.active_calltip, self.tip) + self.text.insert('insert', "'") + self.open_close(parens) + + def test_comment_parens(self): + def comment(self): + self.text.insert('insert', "# ") + for char in '(()())': + self.text.insert('insert', char) + self.assertIs(self.ct.active_calltip, self.tip) + self.text.insert('insert', "\n") + self.open_close(comment) + + if __name__ == '__main__': unittest.main(verbosity=2) diff --git a/Misc/NEWS.d/next/IDLE/2020-06-16-12-16-13.bpo-40511.XkihpM.rst b/Misc/NEWS.d/next/IDLE/2020-06-16-12-16-13.bpo-40511.XkihpM.rst new file mode 100644 index 00000000000000..cc967981381769 --- /dev/null +++ b/Misc/NEWS.d/next/IDLE/2020-06-16-12-16-13.bpo-40511.XkihpM.rst @@ -0,0 +1,3 @@ +Typing opening and closing parentheses inside the parentheses of a function +call will no longer cause unnecessary "flashing" off and on of an existing +open call-tip, e.g. when typed in a string literal. From 27c72ba45af9c59e84992a0f6e1169b7403fb894 Mon Sep 17 00:00:00 2001 From: "Miss Skeleton (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 1 Nov 2020 20:55:57 -0800 Subject: [PATCH 0668/1314] Minor formatting edits to the descriptor howto guide (GH-23092) (GH-23095) --- Doc/howto/descriptor.rst | 39 ++++++++++++++++++++------------------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/Doc/howto/descriptor.rst b/Doc/howto/descriptor.rst index 5373025e5407de..fedf8a8c09eac4 100644 --- a/Doc/howto/descriptor.rst +++ b/Doc/howto/descriptor.rst @@ -27,8 +27,9 @@ This guide has four major sections: 4) The last section has pure Python equivalents for built-in descriptors that are written in C. Read this if you're curious about how functions turn - into bound methods or about how to implement common tools like - :func:`classmethod`, :func:`staticmethod`, and :func:`property`. + into bound methods or about the implementation of common tools like + :func:`classmethod`, :func:`staticmethod`, :func:`property`, and + :term:`__slots__`. Primer @@ -188,7 +189,7 @@ logged attribute and that its name is unchangeable. In the next example, we'll fix that problem. -Customized Names +Customized names ---------------- When a class uses descriptors, it can inform each descriptor about what @@ -438,7 +439,7 @@ creates a deeper understanding of how Python works and an appreciation for the elegance of its design. -Definition and Introduction +Definition and introduction --------------------------- In general, a descriptor is an object attribute with "binding behavior", one @@ -463,7 +464,7 @@ simplify the underlying C code and offer a flexible set of new tools for everyday Python programs. -Descriptor Protocol +Descriptor protocol ------------------- ``descr.__get__(self, obj, type=None) -> value`` @@ -493,7 +494,7 @@ called. Defining the :meth:`__set__` method with an exception raising placeholder is enough to make it a data descriptor. -Overview of Descriptor Invocation +Overview of descriptor invocation --------------------------------- A descriptor can be called directly with ``desc.__get__(obj)`` or @@ -510,7 +511,7 @@ The details of invocation depend on whether ``obj`` is an object, class, or instance of super. -Invocation from an Instance +Invocation from an instance --------------------------- Instance lookup scans through a chain of namespaces giving data descriptors @@ -549,7 +550,7 @@ The :exc:`TypeError` exception handler is needed because the instance dictionary doesn't exist when its class defines :term:`__slots__`. -Invocation from a Class +Invocation from a class ----------------------- The logic for a dotted lookup such as ``A.x`` is in @@ -563,7 +564,7 @@ The full C implementation can be found in :c:func:`type_getattro()` and :c:func:`_PyType_Lookup()` in :source:`Objects/typeobject.c`. -Invocation from Super +Invocation from super --------------------- The logic for super's dotted lookup is in the :meth:`__getattribute__` method for @@ -580,7 +581,7 @@ The full C implementation can be found in :c:func:`super_getattro()` in `_. -Summary of Invocation Logic +Summary of invocation logic --------------------------- The mechanism for descriptors is embedded in the :meth:`__getattribute__()` @@ -606,7 +607,7 @@ The important points to remember are: * Non-data descriptors may be overridden by instance dictionaries. -Automatic Name Notification +Automatic name notification --------------------------- Sometimes it is desirable for a descriptor to know what class variable name it @@ -624,7 +625,7 @@ place at the time of class creation. If descriptors are added to the class afterwards, :meth:`__set_name__` will need to be called manually. -ORM Example +ORM example ----------- The following code is simplified skeleton showing how data descriptors could @@ -694,8 +695,8 @@ Pure Python Equivalents The descriptor protocol is simple and offers exciting possibilities. Several use cases are so common that they have been prepackaged into built-in tools. -Properties, bound methods, static methods, and class methods are all based on -the descriptor protocol. +Properties, bound methods, static methods, class methods, and \_\_slots\_\_ are +all based on the descriptor protocol. Properties @@ -774,7 +775,7 @@ to wrap access to the value attribute in a property data descriptor:: return self._value -Functions and Methods +Functions and methods --------------------- Python's object oriented features are built upon a function based environment. @@ -858,7 +859,7 @@ If you have ever wondered where *self* comes from in regular methods or where *cls* comes from in class methods, this is it! -Static Methods +Static methods -------------- Non-data descriptors provide a simple mechanism for variations on the usual @@ -926,7 +927,7 @@ Using the non-data descriptor protocol, a pure Python version of return self.f -Class Methods +Class methods ------------- Unlike static methods, class methods prepend the class reference to the @@ -991,8 +992,8 @@ For example, a classmethod and property could be chained together:: def __doc__(cls): return f'A doc for {cls.__name__!r}' -Member Objects --------------- +Member objects and __slots__ +---------------------------- When a class defines ``__slots__``, it replaces instance dictionaries with a fixed-length array of slot values. From a user point of view that has From ff852aabf22908e7ef0325af65bab5d02c421fd8 Mon Sep 17 00:00:00 2001 From: "Miss Skeleton (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 2 Nov 2020 03:19:45 -0800 Subject: [PATCH 0669/1314] bpo-42230: Improve asyncio documentation regarding accepting sets vs iterables (GH-23073) People call wait() and as_completed() with various non-set iterables, a list should be the most common but there are others as well[1]. Considering typeshed also documents wait()[2] and as_completed()[3] as accepting arbitrary iterables I think it's a good idea to document the status quo better. [1] https://github.com/aio-libs/aiokafka/pull/672 [2] https://github.com/python/typeshed/blob/620989bac572f30349b95590ebe81a73ce0fe862/stdlib/3/asyncio/tasks.pyiGH-L161 [3] https://github.com/python/typeshed/blob/620989bac572f30349b95590ebe81a73ce0fe862/stdlib/3/asyncio/tasks.pyiGH-L40 (cherry picked from commit 3d86d090dcbbdfdd3e5a5951cab30612d6131222) Co-authored-by: Jakub Stasiak --- Doc/library/asyncio-task.rst | 8 ++++---- Lib/asyncio/tasks.py | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Doc/library/asyncio-task.rst b/Doc/library/asyncio-task.rst index 99f012540d989b..eb51c704cea394 100644 --- a/Doc/library/asyncio-task.rst +++ b/Doc/library/asyncio-task.rst @@ -504,10 +504,10 @@ Waiting Primitives return_when=ALL_COMPLETED) Run :ref:`awaitable objects ` in the *aws* - set concurrently and block until the condition specified + iterable concurrently and block until the condition specified by *return_when*. - The *aws* set must not be empty. + The *aws* iterable must not be empty. Returns two sets of Tasks/Futures: ``(done, pending)``. @@ -593,9 +593,9 @@ Waiting Primitives .. function:: as_completed(aws, \*, loop=None, timeout=None) Run :ref:`awaitable objects ` in the *aws* - set concurrently. Return an iterator of coroutines. + iterable concurrently. Return an iterator of coroutines. Each coroutine returned can be awaited to get the earliest next - result from the set of the remaining awaitables. + result from the iterable of the remaining awaitables. Raises :exc:`asyncio.TimeoutError` if the timeout occurs before all Futures are done. diff --git a/Lib/asyncio/tasks.py b/Lib/asyncio/tasks.py index 8b05434f273b52..ad31f5d59796b1 100644 --- a/Lib/asyncio/tasks.py +++ b/Lib/asyncio/tasks.py @@ -373,7 +373,7 @@ def create_task(coro, *, name=None): async def wait(fs, *, loop=None, timeout=None, return_when=ALL_COMPLETED): """Wait for the Futures and coroutines given by fs to complete. - The sequence futures must not be empty. + The fs iterable must not be empty. Coroutines will be wrapped in Tasks. @@ -573,7 +573,7 @@ def as_completed(fs, *, loop=None, timeout=None): Note: The futures 'f' are not necessarily members of fs. """ if futures.isfuture(fs) or coroutines.iscoroutine(fs): - raise TypeError(f"expect a list of futures, not {type(fs).__name__}") + raise TypeError(f"expect an iterable of futures, not {type(fs).__name__}") from .queues import Queue # Import here to avoid circular import problem. done = Queue(loop=loop) From 723e21a8e79815ae77474d1f21b9847b9c9bdbeb Mon Sep 17 00:00:00 2001 From: Lysandros Nikolaou Date: Mon, 2 Nov 2020 17:51:56 +0200 Subject: [PATCH 0670/1314] bpo-42224: Fix test_format when locale does not expect number grouping (GH-23067) (cherry picked from commit 301822859b3fc34801a06f1090d62f9f2ee5b092) --- Lib/test/test_format.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_format.py b/Lib/test/test_format.py index d2744cdfdca60e..9653e46ecc52d8 100644 --- a/Lib/test/test_format.py +++ b/Lib/test/test_format.py @@ -428,13 +428,16 @@ def test_locale(self): localeconv = locale.localeconv() sep = localeconv['thousands_sep'] point = localeconv['decimal_point'] + grouping = localeconv['grouping'] text = format(123456789, "n") - self.assertIn(sep, text) + if grouping: + self.assertIn(sep, text) self.assertEqual(text.replace(sep, ''), '123456789') text = format(1234.5, "n") - self.assertIn(sep, text) + if grouping: + self.assertIn(sep, text) self.assertIn(point, text) self.assertEqual(text.replace(sep, ''), '1234' + point + '5') finally: From e277cb76989958fdbc092bf0b2cb55c43e86610a Mon Sep 17 00:00:00 2001 From: "Miss Skeleton (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 2 Nov 2020 13:34:46 -0800 Subject: [PATCH 0671/1314] bpo-42103: Improve validation of Plist files. (GH-22882) * Prevent some possible DoS attacks via providing invalid Plist files with extremely large number of objects or collection sizes. * Raise InvalidFileException for too large bytes and string size instead of returning garbage. * Raise InvalidFileException instead of ValueError for specific invalid datetime (NaN). * Raise InvalidFileException instead of TypeError for non-hashable dict keys. * Add more tests for invalid Plist files. (cherry picked from commit 34637a0ce21e7261b952fbd9d006474cc29b681f) Co-authored-by: Serhiy Storchaka --- Lib/plistlib.py | 26 +- Lib/test/test_plistlib.py | 389 +++++++++++++++--- .../2020-10-23-19-20-14.bpo-42103.C5obK2.rst | 3 + .../2020-10-23-19-19-30.bpo-42103.cILT66.rst | 2 + 4 files changed, 363 insertions(+), 57 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2020-10-23-19-20-14.bpo-42103.C5obK2.rst create mode 100644 Misc/NEWS.d/next/Security/2020-10-23-19-19-30.bpo-42103.cILT66.rst diff --git a/Lib/plistlib.py b/Lib/plistlib.py index a7403510a32168..83b214e9dc49bf 100644 --- a/Lib/plistlib.py +++ b/Lib/plistlib.py @@ -477,7 +477,7 @@ def parse(self, fp): return self._read_object(top_object) except (OSError, IndexError, struct.error, OverflowError, - UnicodeDecodeError): + ValueError): raise InvalidFileException() def _get_size(self, tokenL): @@ -493,7 +493,7 @@ def _get_size(self, tokenL): def _read_ints(self, n, size): data = self._fp.read(size * n) if size in _BINARY_FORMAT: - return struct.unpack('>' + _BINARY_FORMAT[size] * n, data) + return struct.unpack(f'>{n}{_BINARY_FORMAT[size]}', data) else: if not size or len(data) != size * n: raise InvalidFileException() @@ -553,14 +553,22 @@ def _read_object(self, ref): elif tokenH == 0x40: # data s = self._get_size(tokenL) result = self._fp.read(s) + if len(result) != s: + raise InvalidFileException() elif tokenH == 0x50: # ascii string s = self._get_size(tokenL) - result = self._fp.read(s).decode('ascii') + data = self._fp.read(s) + if len(data) != s: + raise InvalidFileException() + result = data.decode('ascii') elif tokenH == 0x60: # unicode string - s = self._get_size(tokenL) - result = self._fp.read(s * 2).decode('utf-16be') + s = self._get_size(tokenL) * 2 + data = self._fp.read(s) + if len(data) != s: + raise InvalidFileException() + result = data.decode('utf-16be') elif tokenH == 0x80: # UID # used by Key-Archiver plist files @@ -585,9 +593,11 @@ def _read_object(self, ref): obj_refs = self._read_refs(s) result = self._dict_type() self._objects[ref] = result - for k, o in zip(key_refs, obj_refs): - result[self._read_object(k)] = self._read_object(o) - + try: + for k, o in zip(key_refs, obj_refs): + result[self._read_object(k)] = self._read_object(o) + except TypeError: + raise InvalidFileException() else: raise InvalidFileException() diff --git a/Lib/test/test_plistlib.py b/Lib/test/test_plistlib.py index f821e1da774844..9e53305b8ecef1 100644 --- a/Lib/test/test_plistlib.py +++ b/Lib/test/test_plistlib.py @@ -2,6 +2,7 @@ import copy import operator import pickle +import struct import unittest import plistlib import os @@ -118,6 +119,285 @@ ''' +INVALID_BINARY_PLISTS = [ + ('too short data', + b'' + ), + ('too large offset_table_offset and offset_size = 1', + b'\x00\x08' + b'\x00\x00\x00\x00\x00\x00\x01\x01' + b'\x00\x00\x00\x00\x00\x00\x00\x01' + b'\x00\x00\x00\x00\x00\x00\x00\x00' + b'\x00\x00\x00\x00\x00\x00\x00\x2a' + ), + ('too large offset_table_offset and nonstandard offset_size', + b'\x00\x00\x00\x08' + b'\x00\x00\x00\x00\x00\x00\x03\x01' + b'\x00\x00\x00\x00\x00\x00\x00\x01' + b'\x00\x00\x00\x00\x00\x00\x00\x00' + b'\x00\x00\x00\x00\x00\x00\x00\x2c' + ), + ('integer overflow in offset_table_offset', + b'\x00\x08' + b'\x00\x00\x00\x00\x00\x00\x01\x01' + b'\x00\x00\x00\x00\x00\x00\x00\x01' + b'\x00\x00\x00\x00\x00\x00\x00\x00' + b'\xff\xff\xff\xff\xff\xff\xff\xff' + ), + ('too large top_object', + b'\x00\x08' + b'\x00\x00\x00\x00\x00\x00\x01\x01' + b'\x00\x00\x00\x00\x00\x00\x00\x01' + b'\x00\x00\x00\x00\x00\x00\x00\x01' + b'\x00\x00\x00\x00\x00\x00\x00\x09' + ), + ('integer overflow in top_object', + b'\x00\x08' + b'\x00\x00\x00\x00\x00\x00\x01\x01' + b'\x00\x00\x00\x00\x00\x00\x00\x01' + b'\xff\xff\xff\xff\xff\xff\xff\xff' + b'\x00\x00\x00\x00\x00\x00\x00\x09' + ), + ('too large num_objects and offset_size = 1', + b'\x00\x08' + b'\x00\x00\x00\x00\x00\x00\x01\x01' + b'\x00\x00\x00\x00\x00\x00\x00\xff' + b'\x00\x00\x00\x00\x00\x00\x00\x00' + b'\x00\x00\x00\x00\x00\x00\x00\x09' + ), + ('too large num_objects and nonstandard offset_size', + b'\x00\x00\x00\x08' + b'\x00\x00\x00\x00\x00\x00\x03\x01' + b'\x00\x00\x00\x00\x00\x00\x00\xff' + b'\x00\x00\x00\x00\x00\x00\x00\x00' + b'\x00\x00\x00\x00\x00\x00\x00\x09' + ), + ('extremally large num_objects (32 bit)', + b'\x00\x08' + b'\x00\x00\x00\x00\x00\x00\x01\x01' + b'\x00\x00\x00\x00\x7f\xff\xff\xff' + b'\x00\x00\x00\x00\x00\x00\x00\x00' + b'\x00\x00\x00\x00\x00\x00\x00\x09' + ), + ('extremally large num_objects (64 bit)', + b'\x00\x08' + b'\x00\x00\x00\x00\x00\x00\x01\x01' + b'\x00\x00\x00\xff\xff\xff\xff\xff' + b'\x00\x00\x00\x00\x00\x00\x00\x00' + b'\x00\x00\x00\x00\x00\x00\x00\x09' + ), + ('integer overflow in num_objects', + b'\x00\x08' + b'\x00\x00\x00\x00\x00\x00\x01\x01' + b'\xff\xff\xff\xff\xff\xff\xff\xff' + b'\x00\x00\x00\x00\x00\x00\x00\x00' + b'\x00\x00\x00\x00\x00\x00\x00\x09' + ), + ('offset_size = 0', + b'\x00\x08' + b'\x00\x00\x00\x00\x00\x00\x00\x01' + b'\x00\x00\x00\x00\x00\x00\x00\x01' + b'\x00\x00\x00\x00\x00\x00\x00\x00' + b'\x00\x00\x00\x00\x00\x00\x00\x09' + ), + ('ref_size = 0', + b'\xa1\x01\x00\x08\x0a' + b'\x00\x00\x00\x00\x00\x00\x01\x00' + b'\x00\x00\x00\x00\x00\x00\x00\x02' + b'\x00\x00\x00\x00\x00\x00\x00\x00' + b'\x00\x00\x00\x00\x00\x00\x00\x0b' + ), + ('too large offset', + b'\x00\x2a' + b'\x00\x00\x00\x00\x00\x00\x01\x01' + b'\x00\x00\x00\x00\x00\x00\x00\x01' + b'\x00\x00\x00\x00\x00\x00\x00\x00' + b'\x00\x00\x00\x00\x00\x00\x00\x09' + ), + ('integer overflow in offset', + b'\x00\xff\xff\xff\xff\xff\xff\xff\xff' + b'\x00\x00\x00\x00\x00\x00\x08\x01' + b'\x00\x00\x00\x00\x00\x00\x00\x01' + b'\x00\x00\x00\x00\x00\x00\x00\x00' + b'\x00\x00\x00\x00\x00\x00\x00\x09' + ), + ('too large array size', + b'\xaf\x00\x01\xff\x00\x08\x0c' + b'\x00\x00\x00\x00\x00\x00\x01\x01' + b'\x00\x00\x00\x00\x00\x00\x00\x02' + b'\x00\x00\x00\x00\x00\x00\x00\x00' + b'\x00\x00\x00\x00\x00\x00\x00\x0d' + ), + ('extremally large array size (32-bit)', + b'\xaf\x02\x7f\xff\xff\xff\x01\x00\x08\x0f' + b'\x00\x00\x00\x00\x00\x00\x01\x01' + b'\x00\x00\x00\x00\x00\x00\x00\x02' + b'\x00\x00\x00\x00\x00\x00\x00\x00' + b'\x00\x00\x00\x00\x00\x00\x00\x10' + ), + ('extremally large array size (64-bit)', + b'\xaf\x03\x00\x00\x00\xff\xff\xff\xff\xff\x01\x00\x08\x13' + b'\x00\x00\x00\x00\x00\x00\x01\x01' + b'\x00\x00\x00\x00\x00\x00\x00\x02' + b'\x00\x00\x00\x00\x00\x00\x00\x00' + b'\x00\x00\x00\x00\x00\x00\x00\x14' + ), + ('integer overflow in array size', + b'\xaf\x03\xff\xff\xff\xff\xff\xff\xff\xff\x01\x00\x08\x13' + b'\x00\x00\x00\x00\x00\x00\x01\x01' + b'\x00\x00\x00\x00\x00\x00\x00\x02' + b'\x00\x00\x00\x00\x00\x00\x00\x00' + b'\x00\x00\x00\x00\x00\x00\x00\x14' + ), + ('too large reference index', + b'\xa1\x02\x00\x08\x0a' + b'\x00\x00\x00\x00\x00\x00\x01\x01' + b'\x00\x00\x00\x00\x00\x00\x00\x02' + b'\x00\x00\x00\x00\x00\x00\x00\x00' + b'\x00\x00\x00\x00\x00\x00\x00\x0b' + ), + ('integer overflow in reference index', + b'\xa1\xff\xff\xff\xff\xff\xff\xff\xff\x00\x08\x11' + b'\x00\x00\x00\x00\x00\x00\x01\x08' + b'\x00\x00\x00\x00\x00\x00\x00\x02' + b'\x00\x00\x00\x00\x00\x00\x00\x00' + b'\x00\x00\x00\x00\x00\x00\x00\x12' + ), + ('too large bytes size', + b'\x4f\x00\x23\x41\x08' + b'\x00\x00\x00\x00\x00\x00\x01\x01' + b'\x00\x00\x00\x00\x00\x00\x00\x01' + b'\x00\x00\x00\x00\x00\x00\x00\x00' + b'\x00\x00\x00\x00\x00\x00\x00\x0c' + ), + ('extremally large bytes size (32-bit)', + b'\x4f\x02\x7f\xff\xff\xff\x41\x08' + b'\x00\x00\x00\x00\x00\x00\x01\x01' + b'\x00\x00\x00\x00\x00\x00\x00\x01' + b'\x00\x00\x00\x00\x00\x00\x00\x00' + b'\x00\x00\x00\x00\x00\x00\x00\x0f' + ), + ('extremally large bytes size (64-bit)', + b'\x4f\x03\x00\x00\x00\xff\xff\xff\xff\xff\x41\x08' + b'\x00\x00\x00\x00\x00\x00\x01\x01' + b'\x00\x00\x00\x00\x00\x00\x00\x01' + b'\x00\x00\x00\x00\x00\x00\x00\x00' + b'\x00\x00\x00\x00\x00\x00\x00\x13' + ), + ('integer overflow in bytes size', + b'\x4f\x03\xff\xff\xff\xff\xff\xff\xff\xff\x41\x08' + b'\x00\x00\x00\x00\x00\x00\x01\x01' + b'\x00\x00\x00\x00\x00\x00\x00\x01' + b'\x00\x00\x00\x00\x00\x00\x00\x00' + b'\x00\x00\x00\x00\x00\x00\x00\x13' + ), + ('too large ASCII size', + b'\x5f\x00\x23\x41\x08' + b'\x00\x00\x00\x00\x00\x00\x01\x01' + b'\x00\x00\x00\x00\x00\x00\x00\x01' + b'\x00\x00\x00\x00\x00\x00\x00\x00' + b'\x00\x00\x00\x00\x00\x00\x00\x0c' + ), + ('extremally large ASCII size (32-bit)', + b'\x5f\x02\x7f\xff\xff\xff\x41\x08' + b'\x00\x00\x00\x00\x00\x00\x01\x01' + b'\x00\x00\x00\x00\x00\x00\x00\x01' + b'\x00\x00\x00\x00\x00\x00\x00\x00' + b'\x00\x00\x00\x00\x00\x00\x00\x0f' + ), + ('extremally large ASCII size (64-bit)', + b'\x5f\x03\x00\x00\x00\xff\xff\xff\xff\xff\x41\x08' + b'\x00\x00\x00\x00\x00\x00\x01\x01' + b'\x00\x00\x00\x00\x00\x00\x00\x01' + b'\x00\x00\x00\x00\x00\x00\x00\x00' + b'\x00\x00\x00\x00\x00\x00\x00\x13' + ), + ('integer overflow in ASCII size', + b'\x5f\x03\xff\xff\xff\xff\xff\xff\xff\xff\x41\x08' + b'\x00\x00\x00\x00\x00\x00\x01\x01' + b'\x00\x00\x00\x00\x00\x00\x00\x01' + b'\x00\x00\x00\x00\x00\x00\x00\x00' + b'\x00\x00\x00\x00\x00\x00\x00\x13' + ), + ('invalid ASCII', + b'\x51\xff\x08' + b'\x00\x00\x00\x00\x00\x00\x01\x01' + b'\x00\x00\x00\x00\x00\x00\x00\x01' + b'\x00\x00\x00\x00\x00\x00\x00\x00' + b'\x00\x00\x00\x00\x00\x00\x00\x0a' + ), + ('too large UTF-16 size', + b'\x6f\x00\x13\x20\xac\x00\x08' + b'\x00\x00\x00\x00\x00\x00\x01\x01' + b'\x00\x00\x00\x00\x00\x00\x00\x01' + b'\x00\x00\x00\x00\x00\x00\x00\x00' + b'\x00\x00\x00\x00\x00\x00\x00\x0e' + ), + ('extremally large UTF-16 size (32-bit)', + b'\x6f\x02\x4f\xff\xff\xff\x20\xac\x00\x08' + b'\x00\x00\x00\x00\x00\x00\x01\x01' + b'\x00\x00\x00\x00\x00\x00\x00\x01' + b'\x00\x00\x00\x00\x00\x00\x00\x00' + b'\x00\x00\x00\x00\x00\x00\x00\x11' + ), + ('extremally large UTF-16 size (64-bit)', + b'\x6f\x03\x00\x00\x00\xff\xff\xff\xff\xff\x20\xac\x00\x08' + b'\x00\x00\x00\x00\x00\x00\x01\x01' + b'\x00\x00\x00\x00\x00\x00\x00\x01' + b'\x00\x00\x00\x00\x00\x00\x00\x00' + b'\x00\x00\x00\x00\x00\x00\x00\x15' + ), + ('integer overflow in UTF-16 size', + b'\x6f\x03\xff\xff\xff\xff\xff\xff\xff\xff\x20\xac\x00\x08' + b'\x00\x00\x00\x00\x00\x00\x01\x01' + b'\x00\x00\x00\x00\x00\x00\x00\x01' + b'\x00\x00\x00\x00\x00\x00\x00\x00' + b'\x00\x00\x00\x00\x00\x00\x00\x15' + ), + ('invalid UTF-16', + b'\x61\xd8\x00\x08' + b'\x00\x00\x00\x00\x00\x00\x01\x01' + b'\x00\x00\x00\x00\x00\x00\x00\x01' + b'\x00\x00\x00\x00\x00\x00\x00\x00' + b'\x00\x00\x00\x00\x00\x00\x00\x0b' + ), + ('non-hashable key', + b'\xd1\x01\x01\xa0\x08\x0b' + b'\x00\x00\x00\x00\x00\x00\x01\x01' + b'\x00\x00\x00\x00\x00\x00\x00\x02' + b'\x00\x00\x00\x00\x00\x00\x00\x00' + b'\x00\x00\x00\x00\x00\x00\x00\x0c' + ), + ('too large datetime (datetime overflow)', + b'\x33\x42\x50\x00\x00\x00\x00\x00\x00\x08' + b'\x00\x00\x00\x00\x00\x00\x01\x01' + b'\x00\x00\x00\x00\x00\x00\x00\x01' + b'\x00\x00\x00\x00\x00\x00\x00\x00' + b'\x00\x00\x00\x00\x00\x00\x00\x11' + ), + ('too large datetime (timedelta overflow)', + b'\x33\x42\xe0\x00\x00\x00\x00\x00\x00\x08' + b'\x00\x00\x00\x00\x00\x00\x01\x01' + b'\x00\x00\x00\x00\x00\x00\x00\x01' + b'\x00\x00\x00\x00\x00\x00\x00\x00' + b'\x00\x00\x00\x00\x00\x00\x00\x11' + ), + ('invalid datetime (Infinity)', + b'\x33\x7f\xf0\x00\x00\x00\x00\x00\x00\x08' + b'\x00\x00\x00\x00\x00\x00\x01\x01' + b'\x00\x00\x00\x00\x00\x00\x00\x01' + b'\x00\x00\x00\x00\x00\x00\x00\x00' + b'\x00\x00\x00\x00\x00\x00\x00\x11' + ), + ('invalid datetime (NaN)', + b'\x33\x7f\xf8\x00\x00\x00\x00\x00\x00\x08' + b'\x00\x00\x00\x00\x00\x00\x01\x01' + b'\x00\x00\x00\x00\x00\x00\x00\x01' + b'\x00\x00\x00\x00\x00\x00\x00\x00' + b'\x00\x00\x00\x00\x00\x00\x00\x11' + ), +] + class TestPlistlib(unittest.TestCase): @@ -557,6 +837,21 @@ def test_xml_plist_with_entity_decl(self): class TestBinaryPlistlib(unittest.TestCase): + @staticmethod + def decode(*objects, offset_size=1, ref_size=1): + data = [b'bplist00'] + offset = 8 + offsets = [] + for x in objects: + offsets.append(offset.to_bytes(offset_size, 'big')) + data.append(x) + offset += len(x) + tail = struct.pack('>6xBBQQQ', offset_size, ref_size, + len(objects), 0, offset) + data.extend(offsets) + data.append(tail) + return plistlib.loads(b''.join(data), fmt=plistlib.FMT_BINARY) + def test_nonstandard_refs_size(self): # Issue #21538: Refs and offsets are 24-bit integers data = (b'bplist00' @@ -571,7 +866,7 @@ def test_nonstandard_refs_size(self): def test_dump_duplicates(self): # Test effectiveness of saving duplicated objects - for x in (None, False, True, 12345, 123.45, 'abcde', b'abcde', + for x in (None, False, True, 12345, 123.45, 'abcde', 'абвгд', b'abcde', datetime.datetime(2004, 10, 26, 10, 33, 33), bytearray(b'abcde'), [12, 345], (12, 345), {'12': 345}): with self.subTest(x=x): @@ -608,6 +903,20 @@ def test_cycles(self): b = plistlib.loads(plistlib.dumps(a, fmt=plistlib.FMT_BINARY)) self.assertIs(b['x'], b) + def test_deep_nesting(self): + for N in [300, 100000]: + chunks = [b'\xa1' + (i + 1).to_bytes(4, 'big') for i in range(N)] + try: + result = self.decode(*chunks, b'\x54seed', offset_size=4, ref_size=4) + except RecursionError: + pass + else: + for i in range(N): + self.assertIsInstance(result, list) + self.assertEqual(len(result), 1) + result = result[0] + self.assertEqual(result, 'seed') + def test_large_timestamp(self): # Issue #26709: 32-bit timestamp out of range for ts in -2**31-1, 2**31: @@ -617,55 +926,37 @@ def test_large_timestamp(self): data = plistlib.dumps(d, fmt=plistlib.FMT_BINARY) self.assertEqual(plistlib.loads(data), d) + def test_load_singletons(self): + self.assertIs(self.decode(b'\x00'), None) + self.assertIs(self.decode(b'\x08'), False) + self.assertIs(self.decode(b'\x09'), True) + self.assertEqual(self.decode(b'\x0f'), b'') + + def test_load_int(self): + self.assertEqual(self.decode(b'\x10\x00'), 0) + self.assertEqual(self.decode(b'\x10\xfe'), 0xfe) + self.assertEqual(self.decode(b'\x11\xfe\xdc'), 0xfedc) + self.assertEqual(self.decode(b'\x12\xfe\xdc\xba\x98'), 0xfedcba98) + self.assertEqual(self.decode(b'\x13\x01\x23\x45\x67\x89\xab\xcd\xef'), + 0x0123456789abcdef) + self.assertEqual(self.decode(b'\x13\xfe\xdc\xba\x98\x76\x54\x32\x10'), + -0x123456789abcdf0) + + def test_unsupported(self): + unsupported = [*range(1, 8), *range(10, 15), + 0x20, 0x21, *range(0x24, 0x33), *range(0x34, 0x40)] + for i in [0x70, 0x90, 0xb0, 0xc0, 0xe0, 0xf0]: + unsupported.extend(i + j for j in range(16)) + for token in unsupported: + with self.subTest(f'token {token:02x}'): + with self.assertRaises(plistlib.InvalidFileException): + self.decode(bytes([token]) + b'\x00'*16) + def test_invalid_binary(self): - for data in [ - # too short data - b'', - # too large offset_table_offset and nonstandard offset_size - b'\x00\x08' - b'\x00\x00\x00\x00\x00\x00\x03\x01' - b'\x00\x00\x00\x00\x00\x00\x00\x01' - b'\x00\x00\x00\x00\x00\x00\x00\x00' - b'\x00\x00\x00\x00\x00\x00\x00\x2a', - # integer overflow in offset_table_offset - b'\x00\x08' - b'\x00\x00\x00\x00\x00\x00\x01\x01' - b'\x00\x00\x00\x00\x00\x00\x00\x01' - b'\x00\x00\x00\x00\x00\x00\x00\x00' - b'\xff\xff\xff\xff\xff\xff\xff\xff', - # offset_size = 0 - b'\x00\x08' - b'\x00\x00\x00\x00\x00\x00\x00\x01' - b'\x00\x00\x00\x00\x00\x00\x00\x01' - b'\x00\x00\x00\x00\x00\x00\x00\x00' - b'\x00\x00\x00\x00\x00\x00\x00\x09', - # ref_size = 0 - b'\xa1\x01\x00\x08\x0a' - b'\x00\x00\x00\x00\x00\x00\x01\x00' - b'\x00\x00\x00\x00\x00\x00\x00\x02' - b'\x00\x00\x00\x00\x00\x00\x00\x00' - b'\x00\x00\x00\x00\x00\x00\x00\x0b', - # integer overflow in offset - b'\x00\xff\xff\xff\xff\xff\xff\xff\xff' - b'\x00\x00\x00\x00\x00\x00\x08\x01' - b'\x00\x00\x00\x00\x00\x00\x00\x01' - b'\x00\x00\x00\x00\x00\x00\x00\x00' - b'\x00\x00\x00\x00\x00\x00\x00\x09', - # invalid ASCII - b'\x51\xff\x08' - b'\x00\x00\x00\x00\x00\x00\x01\x01' - b'\x00\x00\x00\x00\x00\x00\x00\x01' - b'\x00\x00\x00\x00\x00\x00\x00\x00' - b'\x00\x00\x00\x00\x00\x00\x00\x0a', - # invalid UTF-16 - b'\x61\xd8\x00\x08' - b'\x00\x00\x00\x00\x00\x00\x01\x01' - b'\x00\x00\x00\x00\x00\x00\x00\x01' - b'\x00\x00\x00\x00\x00\x00\x00\x00' - b'\x00\x00\x00\x00\x00\x00\x00\x0b', - ]: - with self.assertRaises(plistlib.InvalidFileException): - plistlib.loads(b'bplist00' + data, fmt=plistlib.FMT_BINARY) + for name, data in INVALID_BINARY_PLISTS: + with self.subTest(name): + with self.assertRaises(plistlib.InvalidFileException): + plistlib.loads(b'bplist00' + data, fmt=plistlib.FMT_BINARY) class TestKeyedArchive(unittest.TestCase): diff --git a/Misc/NEWS.d/next/Library/2020-10-23-19-20-14.bpo-42103.C5obK2.rst b/Misc/NEWS.d/next/Library/2020-10-23-19-20-14.bpo-42103.C5obK2.rst new file mode 100644 index 00000000000000..4eb694c16a0633 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2020-10-23-19-20-14.bpo-42103.C5obK2.rst @@ -0,0 +1,3 @@ +:exc:`~plistlib.InvalidFileException` and :exc:`RecursionError` are now +the only errors caused by loading malformed binary Plist file (previously +ValueError and TypeError could be raised in some specific cases). diff --git a/Misc/NEWS.d/next/Security/2020-10-23-19-19-30.bpo-42103.cILT66.rst b/Misc/NEWS.d/next/Security/2020-10-23-19-19-30.bpo-42103.cILT66.rst new file mode 100644 index 00000000000000..15d7b6549ed465 --- /dev/null +++ b/Misc/NEWS.d/next/Security/2020-10-23-19-19-30.bpo-42103.cILT66.rst @@ -0,0 +1,2 @@ +Prevented potential DoS attack via CPU and RAM exhaustion when processing +malformed Apple Property List files in binary format. From 6b7a90db362253d67201c2a438a3f38f1ec6180c Mon Sep 17 00:00:00 2001 From: "Miss Skeleton (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 2 Nov 2020 17:08:38 -0800 Subject: [PATCH 0672/1314] bpo-42180: fix plural in arguments and control (GH-23015) (GH-23114) https://bugs.python.org/issue42180 (cherry picked from commit b76a8400217827e604ebb543f45156f3caacd9a0) Co-authored-by: Rafael Fontenelle --- Doc/library/functions.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/functions.rst b/Doc/library/functions.rst index 2a54ce5baf6384..9c12b6c48d8ff0 100644 --- a/Doc/library/functions.rst +++ b/Doc/library/functions.rst @@ -245,7 +245,7 @@ are always available. They are listed here in alphabetical order. interactive statement (in the latter case, expression statements that evaluate to something other than ``None`` will be printed). - The optional argument *flags* and *dont_inherit* controls which + The optional arguments *flags* and *dont_inherit* control which :ref:`compiler options ` should be activated and which :ref:`future features ` should be allowed. If neither is present (or both are zero) the code is compiled with the same flags that From 9bc07874e34930d4e816a9a3330aab009404991e Mon Sep 17 00:00:00 2001 From: "Miss Skeleton (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 3 Nov 2020 13:32:59 -0800 Subject: [PATCH 0673/1314] bpo-42249: Fix writing binary Plist files larger than 4 GiB. (GH-23121) (cherry picked from commit 212d32f45c91849c17a82750df1ac498d63976be) Co-authored-by: Serhiy Storchaka --- Lib/plistlib.py | 2 +- .../next/Library/2020-11-03-09-22-56.bpo-42249.vfNO2u.rst | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Library/2020-11-03-09-22-56.bpo-42249.vfNO2u.rst diff --git a/Lib/plistlib.py b/Lib/plistlib.py index 83b214e9dc49bf..2eeebe4c9a4244 100644 --- a/Lib/plistlib.py +++ b/Lib/plistlib.py @@ -611,7 +611,7 @@ def _count_to_size(count): elif count < 1 << 16: return 2 - elif count << 1 << 32: + elif count < 1 << 32: return 4 else: diff --git a/Misc/NEWS.d/next/Library/2020-11-03-09-22-56.bpo-42249.vfNO2u.rst b/Misc/NEWS.d/next/Library/2020-11-03-09-22-56.bpo-42249.vfNO2u.rst new file mode 100644 index 00000000000000..071a0fdda1ff80 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2020-11-03-09-22-56.bpo-42249.vfNO2u.rst @@ -0,0 +1 @@ +Fixed writing binary Plist files larger than 4 GiB. From e899c016ecb508e943a0b77d6aa8f0063b39c678 Mon Sep 17 00:00:00 2001 From: "Miss Skeleton (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 3 Nov 2020 14:52:41 -0800 Subject: [PATCH 0674/1314] Enable signing of nuget.org packages and update to supported timestamp server (GH-23132) (cherry picked from commit db6434c474f7389a98b8118ca87fca988416bf33) Co-authored-by: Steve Dower --- .azure-pipelines/windows-release/stage-pack-msix.yml | 3 ++- .azure-pipelines/windows-release/stage-pack-nuget.yml | 10 +++++++++- .azure-pipelines/windows-release/stage-sign.yml | 2 +- PCbuild/pyproject.props | 4 ++-- Tools/msi/sdktools.psm1 | 6 +++--- 5 files changed, 17 insertions(+), 8 deletions(-) diff --git a/.azure-pipelines/windows-release/stage-pack-msix.yml b/.azure-pipelines/windows-release/stage-pack-msix.yml index 26a5712e845ca9..f967cfdbe326f8 100644 --- a/.azure-pipelines/windows-release/stage-pack-msix.yml +++ b/.azure-pipelines/windows-release/stage-pack-msix.yml @@ -120,10 +120,11 @@ jobs: artifactName: unsigned_msix downloadPath: $(Build.BinariesDirectory) + # MSIX must be signed and timestamped simultaneously - powershell: | $failed = $true foreach ($retry in 1..3) { - signtool sign /a /n "$(SigningCertificate)" /fd sha256 /t http://timestamp.verisign.com/scripts/timestamp.dll /d "$(SigningDescription)" (gi *.msix) + signtool sign /a /n "$(SigningCertificate)" /fd sha256 /tr http://timestamp.digicert.com/ /td sha256 /d "$(SigningDescription)" (gi *.msix) if ($?) { $failed = $false break diff --git a/.azure-pipelines/windows-release/stage-pack-nuget.yml b/.azure-pipelines/windows-release/stage-pack-nuget.yml index b100364820d95b..8dfea382c35622 100644 --- a/.azure-pipelines/windows-release/stage-pack-nuget.yml +++ b/.azure-pipelines/windows-release/stage-pack-nuget.yml @@ -4,7 +4,7 @@ jobs: condition: and(succeeded(), eq(variables['DoNuget'], 'true')) pool: - vmImage: windows-2019 + name: 'Windows Release' workspace: clean: all @@ -36,6 +36,14 @@ jobs: nuget pack "$(Build.BinariesDirectory)\layout\python.nuspec" -OutputDirectory $(Build.ArtifactStagingDirectory) -NoPackageAnalysis -NonInteractive displayName: 'Create nuget package' + - powershell: | + gci *.nupkg | %{ + nuget sign "$_" -CertificateSubjectName "$(SigningCertificate)" -Timestamper http://timestamp.digicert.com/ -Overwrite + } + displayName: 'Sign nuget package' + workingDirectory: $(Build.ArtifactStagingDirectory) + condition: and(succeeded(), variables['SigningCertificate']) + - task: PublishBuildArtifacts@1 displayName: 'Publish Artifact: nuget' inputs: diff --git a/.azure-pipelines/windows-release/stage-sign.yml b/.azure-pipelines/windows-release/stage-sign.yml index 584772af8b428e..c21e1c9f2b0f9b 100644 --- a/.azure-pipelines/windows-release/stage-sign.yml +++ b/.azure-pipelines/windows-release/stage-sign.yml @@ -57,7 +57,7 @@ jobs: $files = (gi ${{ parameters.Include }} -Exclude ${{ parameters.Exclude }}) $failed = $true foreach ($retry in 1..10) { - signtool timestamp /t http://timestamp.verisign.com/scripts/timestamp.dll $files + signtool timestamp /tr http://timestamp.digicert.com/ /td sha256 $files if ($?) { $failed = $false break diff --git a/PCbuild/pyproject.props b/PCbuild/pyproject.props index c659d14ff8dc93..d7762ca1bc685f 100644 --- a/PCbuild/pyproject.props +++ b/PCbuild/pyproject.props @@ -176,8 +176,8 @@ public override bool Execute() { $(registry:HKEY_LOCAL_MACHINE\Software\Microsoft\Windows Kits\Installed Roots@KitsRoot81)\bin\x86 $(registry:HKEY_LOCAL_MACHINE\Software\Microsoft\Windows Kits\Installed Roots@KitsRoot)\bin\x86 $(registry:HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SDKs\Windows\v7.1A@InstallationFolder)\Bin\ - <_SignCommand Condition="Exists($(SdkBinPath)) and '$(SigningCertificate)' != '' and $(SupportSigning)">"$(SdkBinPath)\signtool.exe" sign /a /n "$(SigningCertificate)" /fd sha256 /t http://timestamp.verisign.com/scripts/timestamp.dll /d "Python $(PythonVersion)" - <_SignCommand Condition="Exists($(SdkBinPath)) and '$(SigningCertificateSha1)' != '' and $(SupportSigning)">"$(SdkBinPath)\signtool.exe" sign /a /sha1 "$(SigningCertificateSha1)" /fd sha256 /t http://timestamp.verisign.com/scripts/timestamp.dll /d "Python $(PythonVersion)" + <_SignCommand Condition="Exists($(SdkBinPath)) and '$(SigningCertificate)' != '' and $(SupportSigning)">"$(SdkBinPath)\signtool.exe" sign /a /n "$(SigningCertificate)" /fd sha256 /tr http://timestamp.digicert.com/ /td sha256 /d "Python $(PythonVersion)" + <_SignCommand Condition="Exists($(SdkBinPath)) and '$(SigningCertificateSha1)' != '' and $(SupportSigning)">"$(SdkBinPath)\signtool.exe" sign /a /sha1 "$(SigningCertificateSha1)" /fd sha256 /tr http://timestamp.digicert.com/ /td sha256 /d "Python $(PythonVersion)" <_MakeCatCommand Condition="Exists($(SdkBinPath))">"$(SdkBinPath)\makecat.exe" diff --git a/Tools/msi/sdktools.psm1 b/Tools/msi/sdktools.psm1 index 8081b104d85a7f..c5973f9abc6abf 100644 --- a/Tools/msi/sdktools.psm1 +++ b/Tools/msi/sdktools.psm1 @@ -37,11 +37,11 @@ function Sign-File { foreach ($a in $files) { if ($certsha1) { - SignTool sign /sha1 $certsha1 /fd sha256 /t http://timestamp.verisign.com/scripts/timestamp.dll /d $description $a + SignTool sign /sha1 $certsha1 /fd sha256 /tr http://timestamp.digicert.com/ /td sha256 /d $description $a } elseif ($certname) { - SignTool sign /a /n $certname /fd sha256 /t http://timestamp.verisign.com/scripts/timestamp.dll /d $description $a + SignTool sign /a /n $certname /fd sha256 /tr http://timestamp.digicert.com/ /td sha256 /d $description $a } elseif ($certfile) { - SignTool sign /f $certfile /fd sha256 /t http://timestamp.verisign.com/scripts/timestamp.dll /d $description $a + SignTool sign /f $certfile /fd sha256 /tr http://timestamp.digicert.com/ /td sha256 /d $description $a } } } From 72bb4c6c1fc5f5209819a2e62d55475ddc888192 Mon Sep 17 00:00:00 2001 From: "Miss Skeleton (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 4 Nov 2020 05:16:28 -0800 Subject: [PATCH 0675/1314] bpo-35455: Fix thread_time for Solaris OS (GH-11118) (GH-23130) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit (cherry picked from commit 9568622c9983b682b2a2a7bacfd3c341028ea099) Co-authored-by: Jakub Kulík Co-authored-by: Jakub Kulík --- .../2020-11-02-14-10-48.bpo-35455.Q1xTIo.rst | 3 +++ Modules/timemodule.c | 17 +++++++++++++++++ 2 files changed, 20 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2020-11-02-14-10-48.bpo-35455.Q1xTIo.rst diff --git a/Misc/NEWS.d/next/Library/2020-11-02-14-10-48.bpo-35455.Q1xTIo.rst b/Misc/NEWS.d/next/Library/2020-11-02-14-10-48.bpo-35455.Q1xTIo.rst new file mode 100644 index 00000000000000..e72c7d277a1123 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2020-11-02-14-10-48.bpo-35455.Q1xTIo.rst @@ -0,0 +1,3 @@ +On Solaris, :func:`~time.thread_time` is now implemented with +``gethrvtime()`` because ``clock_gettime(CLOCK_THREAD_CPUTIME_ID)`` is not +always available. Patch by Jakub Kulik. diff --git a/Modules/timemodule.c b/Modules/timemodule.c index 8a4d149befb52a..eb192c5e7fd31e 100644 --- a/Modules/timemodule.c +++ b/Modules/timemodule.c @@ -1371,6 +1371,23 @@ _PyTime_GetThreadTimeWithInfo(_PyTime_t *tp, _Py_clock_info_t *info) return 0; } +#elif defined(__sun) && defined(__SVR4) +#define HAVE_THREAD_TIME +static int +_PyTime_GetThreadTimeWithInfo(_PyTime_t *tp, _Py_clock_info_t *info) +{ + /* bpo-35455: On Solaris, CLOCK_THREAD_CPUTIME_ID clock is not always + available; use gethrvtime() to substitute this functionality. */ + if (info) { + info->implementation = "gethrvtime()"; + info->resolution = 1e-9; + info->monotonic = 1; + info->adjustable = 0; + } + *tp = _PyTime_FromNanoseconds(gethrvtime()); + return 0; +} + #elif defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_PROCESS_CPUTIME_ID) #define HAVE_THREAD_TIME static int From 3997a4e6bca18c7f220d6212ef1e86d8aa9c7aee Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 4 Nov 2020 15:22:13 -0800 Subject: [PATCH 0676/1314] Disable peg generator tests when building with PGO (GH-23141) Otherwise, when running the testsuite, test_peg_generator tries to compile C code using the optimized flags and fails because it cannot find the profile data. (cherry picked from commit 100964e0310d3a2040d0db976f7984d0507b2dbd) Co-authored-by: serge-sans-paille --- Lib/test/test_peg_generator/test_c_parser.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Lib/test/test_peg_generator/test_c_parser.py b/Lib/test/test_peg_generator/test_c_parser.py index f9935258c861e0..9701d4f9feb16b 100644 --- a/Lib/test/test_peg_generator/test_c_parser.py +++ b/Lib/test/test_peg_generator/test_c_parser.py @@ -1,3 +1,4 @@ +import sysconfig import textwrap import unittest from distutils.tests.support import TempdirManager @@ -7,6 +8,11 @@ from test import support from test.support.script_helper import assert_python_ok +_py_cflags_nodist = sysconfig.get_config_var('PY_CFLAGS_NODIST') +_pgo_flag = sysconfig.get_config_var('PGO_PROF_USE_FLAG') +if _pgo_flag and _py_cflags_nodist and _pgo_flag in _py_cflags_nodist: + raise unittest.SkipTest("peg_generator test disabled under PGO build") + test_tools.skip_if_missing("peg_generator") with test_tools.imports_under_tool("peg_generator"): from pegen.grammar_parser import GeneratedParser as GrammarParser From e74fb2d7666eea43ad738528a565bb56bc88c28d Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 5 Nov 2020 19:05:57 -0800 Subject: [PATCH 0677/1314] bpo-42179: Doc/tutorial: Remove mention of __cause__ (GH-23162) (cherry picked from commit bde33e428d5b5f88ec7667598fd27d1091840537) Co-authored-by: Inada Naoki --- Doc/tutorial/errors.rst | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/Doc/tutorial/errors.rst b/Doc/tutorial/errors.rst index 0ce96466e8c286..efe44da3043c5e 100644 --- a/Doc/tutorial/errors.rst +++ b/Doc/tutorial/errors.rst @@ -273,15 +273,15 @@ Exception Chaining ================== The :keyword:`raise` statement allows an optional :keyword:`from` which enables -chaining exceptions by setting the ``__cause__`` attribute of the raised -exception. For example:: +chaining exceptions. For example:: - raise RuntimeError from OSError + # exc must be exception instance or None. + raise RuntimeError from exc This can be useful when you are transforming exceptions. For example:: >>> def func(): - ... raise IOError + ... raise IOError ... >>> try: ... func() @@ -297,12 +297,11 @@ This can be useful when you are transforming exceptions. For example:: Traceback (most recent call last): File "", line 4, in - RuntimeError + RuntimeError: Failed to open database -The expression following the :keyword:`from` must be either an exception or -``None``. Exception chaining happens automatically when an exception is raised -inside an exception handler or :keyword:`finally` section. Exception chaining -can be disabled by using ``from None`` idiom: +Exception chaining happens automatically when an exception is raised inside an +:keyword:`except` or :keyword:`finally` section. Exception chaining can be +disabled by using ``from None`` idiom: >>> try: ... open('database.sqlite') @@ -313,6 +312,8 @@ can be disabled by using ``from None`` idiom: File "", line 4, in RuntimeError +For more information about chaining mechanics, see :ref:`bltin-exceptions`. + .. _tut-userexceptions: From 6255296c5060973f1f1d46e2ecddcc827f33490c Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 6 Nov 2020 11:22:00 -0800 Subject: [PATCH 0678/1314] Remove outdated reference to pywin32 from platform module (GH-22005) (cherry picked from commit 7c01f1540f958d4f52188b28afca721a9a6925c3) Co-authored-by: Andre Delfino --- Doc/library/platform.rst | 7 ------- 1 file changed, 7 deletions(-) diff --git a/Doc/library/platform.rst b/Doc/library/platform.rst index 8e8e3775aaff4a..b293adf48e6e33 100644 --- a/Doc/library/platform.rst +++ b/Doc/library/platform.rst @@ -209,13 +209,6 @@ Windows Platform which means the OS version uses debugging code, i.e. code that checks arguments, ranges, etc. - .. note:: - - This function works best with Mark Hammond's - :mod:`win32all` package installed, but also on Python 2.3 and - later (support for this was added in Python 2.6). It obviously - only runs on Win32 compatible platforms. - .. function:: win32_edition() Returns a string representing the current Windows edition. Possible From 4c239a3222296c7d85ccd46e27835cc7880350be Mon Sep 17 00:00:00 2001 From: Raymond Hettinger Date: Fri, 6 Nov 2020 16:46:10 -0800 Subject: [PATCH 0679/1314] Minor grammar edits for the descriptor howto guide (GH-#23175) (GH-23186) --- Doc/howto/descriptor.rst | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/Doc/howto/descriptor.rst b/Doc/howto/descriptor.rst index fedf8a8c09eac4..8c2e8d562153db 100644 --- a/Doc/howto/descriptor.rst +++ b/Doc/howto/descriptor.rst @@ -112,7 +112,7 @@ different, updated answers each time:: Besides showing how descriptors can run computations, this example also reveals the purpose of the parameters to :meth:`__get__`. The *self* parameter is *size*, an instance of *DirectorySize*. The *obj* parameter is -either *g* or *s*, an instance of *Directory*. It is *obj* parameter that +either *g* or *s*, an instance of *Directory*. It is the *obj* parameter that lets the :meth:`__get__` method learn the target directory. The *objtype* parameter is the class *Directory*. @@ -183,7 +183,7 @@ logged, but that the regular attribute *name* is not logged:: INFO:root:Accessing 'age' giving 40 40 -One major issue with this example is the private name *_age* is hardwired in +One major issue with this example is that the private name *_age* is hardwired in the *LoggedAgeAccess* class. That means that each instance can only have one logged attribute and that its name is unchangeable. In the next example, we'll fix that problem. @@ -192,7 +192,7 @@ we'll fix that problem. Customized names ---------------- -When a class uses descriptors, it can inform each descriptor about what +When a class uses descriptors, it can inform each descriptor about which variable name was used. In this example, the :class:`Person` class has two descriptor instances, @@ -233,7 +233,7 @@ be recorded, giving each descriptor its own *public_name* and *private_name*:: An interactive session shows that the :class:`Person` class has called :meth:`__set_name__` so that the field names would be recorded. Here -we call :func:`vars` to lookup the descriptor without triggering it:: +we call :func:`vars` to look up the descriptor without triggering it:: >>> vars(vars(Person)['name']) {'public_name': 'name', 'private_name': '_name'} @@ -614,8 +614,8 @@ Sometimes it is desirable for a descriptor to know what class variable name it was assigned to. When a new class is created, the :class:`type` metaclass scans the dictionary of the new class. If any of the entries are descriptors and if they define :meth:`__set_name__`, that method is called with two -arguments. The *owner* is the class where the descriptor is used, the *name* -is class variable the descriptor was assigned to. +arguments. The *owner* is the class where the descriptor is used, and the +*name* is the class variable the descriptor was assigned to. The implementation details are in :c:func:`type_new()` and :c:func:`set_names()` in :source:`Objects/typeobject.c`. @@ -703,7 +703,7 @@ Properties ---------- Calling :func:`property` is a succinct way of building a data descriptor that -triggers function calls upon access to an attribute. Its signature is:: +triggers a function call upon access to an attribute. Its signature is:: property(fget=None, fset=None, fdel=None, doc=None) -> property @@ -803,7 +803,7 @@ roughly equivalent to:: To support automatic creation of methods, functions include the :meth:`__get__` method for binding methods during attribute access. This -means that functions are non-data descriptors which return bound methods +means that functions are non-data descriptors that return bound methods during dotted lookup from an instance. Here's how it works:: class Function: @@ -1016,7 +1016,7 @@ attributes stored in ``__slots__``:: class Immutable: - __slots__ = ('_dept', '_name') # Replace instance dictionary + __slots__ = ('_dept', '_name') # Replace the instance dictionary def __init__(self, dept, name): self._dept = dept # Store to private attribute @@ -1086,7 +1086,7 @@ by member descriptors:: The :meth:`type.__new__` method takes care of adding member objects to class variables. The :meth:`object.__new__` method takes care of creating instances -that have slots instead of a instance dictionary. Here is a rough equivalent +that have slots instead of an instance dictionary. Here is a rough equivalent in pure Python:: class Type(type): From e81e09bfc8a29a44a649a962870a26fe0c097cfa Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 7 Nov 2020 08:46:08 -0800 Subject: [PATCH 0680/1314] bpo-42233: Correctly repr GenericAlias when used with typing module (GH-23081) Noticed by @serhiy-storchaka in the bpo. `typing`'s types were not showing the parameterized generic. Eg. previously: ```python >>> typing.Union[dict[str, float], list[int]] 'typing.Union[dict, list]' ``` Now: ```python >>> typing.Union[dict[str, float], list[int]] 'typing.Union[dict[str, float], list[int]]' ``` Automerge-Triggered-By: GH:gvanrossum (cherry picked from commit 1f7dfb277e5b88cddc13e5024766be787a3e9127) Co-authored-by: kj <28750310+Fidget-Spinner@users.noreply.github.com> --- Lib/test/test_typing.py | 7 +++++++ Lib/typing.py | 2 ++ .../next/Library/2020-11-02-01-31-15.bpo-42233.YxRj-h.rst | 3 +++ 3 files changed, 12 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2020-11-02-01-31-15.bpo-42233.YxRj-h.rst diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index 7f96aff7104551..67cadc37e4fbe4 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -300,6 +300,8 @@ def test_repr(self): self.assertEqual(repr(u), repr(int)) u = Union[List[int], int] self.assertEqual(repr(u), 'typing.Union[typing.List[int], int]') + u = Union[list[int], dict[str, float]] + self.assertEqual(repr(u), 'typing.Union[list[int], dict[str, float]]') def test_cannot_subclass(self): with self.assertRaises(TypeError): @@ -411,6 +413,7 @@ def test_repr(self): self.assertEqual(repr(Tuple[()]), 'typing.Tuple[()]') self.assertEqual(repr(Tuple[int, float]), 'typing.Tuple[int, float]') self.assertEqual(repr(Tuple[int, ...]), 'typing.Tuple[int, ...]') + self.assertEqual(repr(Tuple[list[int]]), 'typing.Tuple[list[int]]') def test_errors(self): with self.assertRaises(TypeError): @@ -483,6 +486,8 @@ def test_repr(self): self.assertEqual(repr(ct2), 'typing.Callable[[str, float], int]') ctv = Callable[..., str] self.assertEqual(repr(ctv), 'typing.Callable[..., str]') + ct3 = Callable[[str, float], list[int]] + self.assertEqual(repr(ct3), 'typing.Callable[[str, float], list[int]]') def test_callable_with_ellipsis(self): @@ -2273,6 +2278,8 @@ def test_repr(self): self.assertEqual(repr(cv), 'typing.Final[int]') cv = Final[Employee] self.assertEqual(repr(cv), 'typing.Final[%s.Employee]' % __name__) + cv = Final[tuple[int]] + self.assertEqual(repr(cv), 'typing.Final[tuple[int]]') def test_cannot_subclass(self): with self.assertRaises(TypeError): diff --git a/Lib/typing.py b/Lib/typing.py index 39c956dd1834da..6fd67b038834e1 100644 --- a/Lib/typing.py +++ b/Lib/typing.py @@ -160,6 +160,8 @@ def _type_repr(obj): typically enough to uniquely identify a type. For everything else, we fall back on repr(obj). """ + if isinstance(obj, types.GenericAlias): + return repr(obj) if isinstance(obj, type): if obj.__module__ == 'builtins': return obj.__qualname__ diff --git a/Misc/NEWS.d/next/Library/2020-11-02-01-31-15.bpo-42233.YxRj-h.rst b/Misc/NEWS.d/next/Library/2020-11-02-01-31-15.bpo-42233.YxRj-h.rst new file mode 100644 index 00000000000000..aad4249fa165bf --- /dev/null +++ b/Misc/NEWS.d/next/Library/2020-11-02-01-31-15.bpo-42233.YxRj-h.rst @@ -0,0 +1,3 @@ +The :func:`repr` of :mod:`typing` types containing +:ref:`Generic Alias Types ` previously did not show the +parameterized types in the ``GenericAlias``. They have now been changed to do so. From 2e5bd4f6775b693bfc3a9f8986f88c0f1f41ff58 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 8 Nov 2020 01:45:45 -0800 Subject: [PATCH 0681/1314] Minor wording change in concurrent.futures. (GH-23194) Fixes a grammar problem by adding a missing "as", and clarifies the wording of the valid ranges for max_workers. (cherry picked from commit fd6f6fa403789c8877b1099cc6fcc437d2e54634) Co-authored-by: Don Kirkby --- Doc/library/concurrent.futures.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Doc/library/concurrent.futures.rst b/Doc/library/concurrent.futures.rst index 675a9ffdd0711a..61d6c1143cfdd5 100644 --- a/Doc/library/concurrent.futures.rst +++ b/Doc/library/concurrent.futures.rst @@ -236,9 +236,9 @@ to a :class:`ProcessPoolExecutor` will result in deadlock. An :class:`Executor` subclass that executes calls asynchronously using a pool of at most *max_workers* processes. If *max_workers* is ``None`` or not given, it will default to the number of processors on the machine. - If *max_workers* is lower or equal to ``0``, then a :exc:`ValueError` + If *max_workers* is less than or equal to ``0``, then a :exc:`ValueError` will be raised. - On Windows, *max_workers* must be equal or lower than ``61``. If it is not + On Windows, *max_workers* must be less than or equal to ``61``. If it is not then :exc:`ValueError` will be raised. If *max_workers* is ``None``, then the default chosen will be at most ``61``, even if more processors are available. @@ -250,7 +250,7 @@ to a :class:`ProcessPoolExecutor` will result in deadlock. each worker process; *initargs* is a tuple of arguments passed to the initializer. Should *initializer* raise an exception, all currently pending jobs will raise a :exc:`~concurrent.futures.process.BrokenProcessPool`, - as well any attempt to submit more jobs to the pool. + as well as any attempt to submit more jobs to the pool. .. versionchanged:: 3.3 When one of the worker processes terminates abruptly, a From 371c33567a0b6afb93ffde2fb4564fe57a41945b Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 8 Nov 2020 02:07:44 -0800 Subject: [PATCH 0682/1314] bpo-41754: Ignore NotADirectoryError in invocation of xdg-settings (GH-23075) It is not clear why this can happen, but several users have mentioned getting this exception on macOS. (cherry picked from commit 23831a7a90956e38b7d70304bb6afe30d37936de) Co-authored-by: Ronald Oussoren --- Lib/webbrowser.py | 2 +- .../next/Library/2020-11-01-15-07-20.bpo-41754.DraSZh.rst | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Library/2020-11-01-15-07-20.bpo-41754.DraSZh.rst diff --git a/Lib/webbrowser.py b/Lib/webbrowser.py index cea91308ce1b30..6023c1e13841d2 100755 --- a/Lib/webbrowser.py +++ b/Lib/webbrowser.py @@ -550,7 +550,7 @@ def register_standard_browsers(): cmd = "xdg-settings get default-web-browser".split() raw_result = subprocess.check_output(cmd, stderr=subprocess.DEVNULL) result = raw_result.decode().strip() - except (FileNotFoundError, subprocess.CalledProcessError, PermissionError) : + except (FileNotFoundError, subprocess.CalledProcessError, PermissionError, NotADirectoryError) : pass else: global _os_preferred_browser diff --git a/Misc/NEWS.d/next/Library/2020-11-01-15-07-20.bpo-41754.DraSZh.rst b/Misc/NEWS.d/next/Library/2020-11-01-15-07-20.bpo-41754.DraSZh.rst new file mode 100644 index 00000000000000..181c2d9650a14c --- /dev/null +++ b/Misc/NEWS.d/next/Library/2020-11-01-15-07-20.bpo-41754.DraSZh.rst @@ -0,0 +1 @@ +webbrowser: Ignore *NotADirectoryError* when calling ``xdg-settings``. From 2a86ade9e38168ba49c68d1dd52ced588a80d945 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 9 Nov 2020 22:18:34 -0800 Subject: [PATCH 0683/1314] Fix typo in unicodeobject.c (GH-23180) exeeds -> exceeds Automerge-Triggered-By: GH:Mariatta (cherry picked from commit 38811d68caf9b782ea7168479acb09557e126efe) Co-authored-by: Ikko Ashimine --- Objects/unicodeobject.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c index d5fbf158d50b42..ea359039528b60 100644 --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -1882,7 +1882,7 @@ _PyUnicode_Ready(PyObject *unicode) _PyUnicode_WSTR_LENGTH(unicode) = 0; #endif } - /* maxchar exeeds 16 bit, wee need 4 bytes for unicode characters */ + /* maxchar exceeds 16 bit, wee need 4 bytes for unicode characters */ else { #if SIZEOF_WCHAR_T == 2 /* in case the native representation is 2-bytes, we need to allocate a From 90115a2cf7033c990a54d1ecb90ebd850b5f13cf Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 10 Nov 2020 06:20:52 -0800 Subject: [PATCH 0684/1314] bpo-42183: Fix a stack overflow error for asyncio Task or Future repr() (GH-23020) The overflow occurs under some circumstances when a task or future recursively returns itself. Co-authored-by: Kyle Stanley (cherry picked from commit 42d873c63aa9d160c132be4a34599531574db12c) Co-authored-by: Andrew Svetlov --- Lib/asyncio/base_futures.py | 25 ++++++++++++++++--- Lib/test/test_asyncio/test_futures2.py | 18 +++++++++++++ .../2020-10-29-11-17-35.bpo-42183.50ZcIi.rst | 4 +++ 3 files changed, 44 insertions(+), 3 deletions(-) create mode 100644 Lib/test/test_asyncio/test_futures2.py create mode 100644 Misc/NEWS.d/next/Library/2020-10-29-11-17-35.bpo-42183.50ZcIi.rst diff --git a/Lib/asyncio/base_futures.py b/Lib/asyncio/base_futures.py index 22f298069c505e..2c01ac98e10fca 100644 --- a/Lib/asyncio/base_futures.py +++ b/Lib/asyncio/base_futures.py @@ -1,6 +1,7 @@ __all__ = () import reprlib +from _thread import get_ident from . import format_helpers @@ -41,6 +42,16 @@ def format_cb(callback): return f'cb=[{cb}]' +# bpo-42183: _repr_running is needed for repr protection +# when a Future or Task result contains itself directly or indirectly. +# The logic is borrowed from @reprlib.recursive_repr decorator. +# Unfortunately, the direct decorator usage is impossible because of +# AttributeError: '_asyncio.Task' object has no attribute '__module__' error. +# +# After fixing this thing we can return to the decorator based approach. +_repr_running = set() + + def _future_repr_info(future): # (Future) -> str """helper function for Future.__repr__""" @@ -49,9 +60,17 @@ def _future_repr_info(future): if future._exception is not None: info.append(f'exception={future._exception!r}') else: - # use reprlib to limit the length of the output, especially - # for very long strings - result = reprlib.repr(future._result) + key = id(future), get_ident() + if key in _repr_running: + result = '...' + else: + _repr_running.add(key) + try: + # use reprlib to limit the length of the output, especially + # for very long strings + result = reprlib.repr(future._result) + finally: + _repr_running.discard(key) info.append(f'result={result}') if future._callbacks: info.append(_format_callbacks(future._callbacks)) diff --git a/Lib/test/test_asyncio/test_futures2.py b/Lib/test/test_asyncio/test_futures2.py new file mode 100644 index 00000000000000..13dbc703277c81 --- /dev/null +++ b/Lib/test/test_asyncio/test_futures2.py @@ -0,0 +1,18 @@ +# IsolatedAsyncioTestCase based tests +import asyncio +import unittest + + +class FutureTests(unittest.IsolatedAsyncioTestCase): + async def test_recursive_repr_for_pending_tasks(self): + # The call crashes if the guard for recursive call + # in base_futures:_future_repr_info is absent + # See Also: https://bugs.python.org/issue42183 + + async def func(): + return asyncio.all_tasks() + + # The repr() call should not raise RecursiveError at first. + # The check for returned string is not very reliable but + # exact comparison for the whole string is even weaker. + self.assertIn('...', repr(await asyncio.wait_for(func(), timeout=10))) diff --git a/Misc/NEWS.d/next/Library/2020-10-29-11-17-35.bpo-42183.50ZcIi.rst b/Misc/NEWS.d/next/Library/2020-10-29-11-17-35.bpo-42183.50ZcIi.rst new file mode 100644 index 00000000000000..f6d7653f2cf09f --- /dev/null +++ b/Misc/NEWS.d/next/Library/2020-10-29-11-17-35.bpo-42183.50ZcIi.rst @@ -0,0 +1,4 @@ +Fix a stack overflow error for asyncio Task or Future repr(). + +The overflow occurs under some circumstances when a Task or Future +recursively returns itself. From 14a343a9af27725faeab8b330a6d66ff573704d3 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 10 Nov 2020 08:29:35 -0800 Subject: [PATCH 0685/1314] bpo-42014: shutil.rmtree: call onerror with correct function (GH-22585) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The onerror is supposed to be called with failed function, but in this case lstat is wrongly used instead of open. Not sure if this needs bug or not... Automerge-Triggered-By: GH:hynek (cherry picked from commit e59b2deffde61e5641cabd65034fa11b4db898ba) Co-authored-by: Michal ÄŒihaÅ™ --- Lib/shutil.py | 2 +- .../next/Library/2020-11-10-15-40-56.bpo-42014.ShM37l.rst | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Library/2020-11-10-15-40-56.bpo-42014.ShM37l.rst diff --git a/Lib/shutil.py b/Lib/shutil.py index 223e9a8a705064..f0e833dc979b79 100644 --- a/Lib/shutil.py +++ b/Lib/shutil.py @@ -711,7 +711,7 @@ def onerror(*args): try: fd = os.open(path, os.O_RDONLY) except Exception: - onerror(os.lstat, path, sys.exc_info()) + onerror(os.open, path, sys.exc_info()) return try: if os.path.samestat(orig_st, os.fstat(fd)): diff --git a/Misc/NEWS.d/next/Library/2020-11-10-15-40-56.bpo-42014.ShM37l.rst b/Misc/NEWS.d/next/Library/2020-11-10-15-40-56.bpo-42014.ShM37l.rst new file mode 100644 index 00000000000000..d3e1abcd84c1e8 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2020-11-10-15-40-56.bpo-42014.ShM37l.rst @@ -0,0 +1 @@ +The ``onerror`` callback from ``shutil.rmtree`` now receives correct function when ``os.open`` fails. \ No newline at end of file From f8bea0a44d718296a249bdb766b8dbc92f38e8df Mon Sep 17 00:00:00 2001 From: Zackery Spytz Date: Tue, 10 Nov 2020 16:06:34 -0700 Subject: [PATCH 0686/1314] [3.9] bpo-4bpo-42314: Fix the documentation for venv --upgrade-deps (GH-22113) (GH-23232) It was added in 3.9, not 3.8. --- Doc/using/venv-create.inc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/using/venv-create.inc b/Doc/using/venv-create.inc index c8f6e8f87d5674..5e724cd5794ce4 100644 --- a/Doc/using/venv-create.inc +++ b/Doc/using/venv-create.inc @@ -67,7 +67,7 @@ The command, if run with ``-h``, will show the available options:: Once an environment has been created, you may wish to activate it, e.g. by sourcing an activate script in its bin directory. -.. versionchanged:: 3.8 +.. versionchanged:: 3.9 Add ``--upgrade-deps`` option to upgrade pip + setuptools to the latest on PyPI .. versionchanged:: 3.4 From 33922cb0aa0c81ebff91ab4e938a58dfec2acf19 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 10 Nov 2020 15:10:57 -0800 Subject: [PATCH 0687/1314] bpo-42140: Improve asyncio.wait function (GH-22938) GH- Improve asyncio.wait function The original code creates the futures set two times. We can create this set before, avoiding the second creation. This new behaviour [breaks the aiokafka library](https://github.com/aio-libs/aiokafka/pull/672), because it gives an iterator to that function, so the second iteration become empty. Automerge-Triggered-By: GH:1st1 (cherry picked from commit 7e5ef0a5713f968f6e942566c78bf57ffbef01de) Co-authored-by: Diogo Dutra --- Lib/asyncio/tasks.py | 6 +++-- Lib/test/test_asyncio/test_tasks.py | 24 +++++++++++++++++++ .../2020-10-24-04-02-36.bpo-42140.miLqvb.rst | 1 + 3 files changed, 29 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2020-10-24-04-02-36.bpo-42140.miLqvb.rst diff --git a/Lib/asyncio/tasks.py b/Lib/asyncio/tasks.py index ad31f5d59796b1..f486b672294111 100644 --- a/Lib/asyncio/tasks.py +++ b/Lib/asyncio/tasks.py @@ -400,13 +400,15 @@ async def wait(fs, *, loop=None, timeout=None, return_when=ALL_COMPLETED): "and scheduled for removal in Python 3.10.", DeprecationWarning, stacklevel=2) - if any(coroutines.iscoroutine(f) for f in set(fs)): + fs = set(fs) + + if any(coroutines.iscoroutine(f) for f in fs): warnings.warn("The explicit passing of coroutine objects to " "asyncio.wait() is deprecated since Python 3.8, and " "scheduled for removal in Python 3.11.", DeprecationWarning, stacklevel=2) - fs = {ensure_future(f, loop=loop) for f in set(fs)} + fs = {ensure_future(f, loop=loop) for f in fs} return await _wait(fs, timeout, return_when, loop) diff --git a/Lib/test/test_asyncio/test_tasks.py b/Lib/test/test_asyncio/test_tasks.py index 74fc1e4a42133c..01f62b7f408726 100644 --- a/Lib/test/test_asyncio/test_tasks.py +++ b/Lib/test/test_asyncio/test_tasks.py @@ -1548,6 +1548,30 @@ def gen(): loop.advance_time(10) loop.run_until_complete(asyncio.wait([a, b])) + def test_wait_with_iterator_of_tasks(self): + + def gen(): + when = yield + self.assertAlmostEqual(0.1, when) + when = yield 0 + self.assertAlmostEqual(0.15, when) + yield 0.15 + + loop = self.new_test_loop(gen) + + a = self.new_task(loop, asyncio.sleep(0.1)) + b = self.new_task(loop, asyncio.sleep(0.15)) + + async def foo(): + done, pending = await asyncio.wait(iter([b, a])) + self.assertEqual(done, set([a, b])) + self.assertEqual(pending, set()) + return 42 + + res = loop.run_until_complete(self.new_task(loop, foo())) + self.assertEqual(res, 42) + self.assertAlmostEqual(0.15, loop.time()) + def test_as_completed(self): def gen(): diff --git a/Misc/NEWS.d/next/Library/2020-10-24-04-02-36.bpo-42140.miLqvb.rst b/Misc/NEWS.d/next/Library/2020-10-24-04-02-36.bpo-42140.miLqvb.rst new file mode 100644 index 00000000000000..4160234b5ec685 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2020-10-24-04-02-36.bpo-42140.miLqvb.rst @@ -0,0 +1 @@ +Improve asyncio.wait function to create the futures set just one time. From 7ae19ef5cf5d4f464588133bd48f81d80ea54aee Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 12 Nov 2020 02:14:03 -0800 Subject: [PATCH 0688/1314] bpo-42237: Fix os.sendfile() on illumos (GH-23154) (cherry picked from commit fd4ed57674c675e05bd5d577dd5047a333c76c78) Co-authored-by: Jakub Stasiak --- .../2020-11-10-14-27-49.bpo-42237.F363jO.rst | 1 + Modules/posixmodule.c | 15 +++++++++++++++ 2 files changed, 16 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2020-11-10-14-27-49.bpo-42237.F363jO.rst diff --git a/Misc/NEWS.d/next/Library/2020-11-10-14-27-49.bpo-42237.F363jO.rst b/Misc/NEWS.d/next/Library/2020-11-10-14-27-49.bpo-42237.F363jO.rst new file mode 100644 index 00000000000000..50cab6e1f11f84 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2020-11-10-14-27-49.bpo-42237.F363jO.rst @@ -0,0 +1 @@ +Fix `os.sendfile()` on illumos. diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index 01e8bcbd2981a4..8e14ffcc856f85 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -9469,11 +9469,26 @@ os_sendfile_impl(PyObject *module, int out_fd, int in_fd, PyObject *offobj, if (offset >= st.st_size) { return Py_BuildValue("i", 0); } + + // On illumos specifically sendfile() may perform a partial write but + // return -1/an error (in one confirmed case the destination socket + // had a 5 second timeout set and errno was EAGAIN) and it's on the client + // code to check if the offset parameter was modified by sendfile(). + // + // We need this variable to track said change. + off_t original_offset = offset; #endif do { Py_BEGIN_ALLOW_THREADS ret = sendfile(out_fd, in_fd, &offset, count); +#if defined(__sun) && defined(__SVR4) + // This handles illumos-specific sendfile() partial write behavior, + // see a comment above for more details. + if (ret < 0 && offset != original_offset) { + ret = offset - original_offset; + } +#endif Py_END_ALLOW_THREADS } while (ret < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals())); if (ret < 0) From bc777047833256bc6b10b2c7b46cce9e9e6f956c Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 13 Nov 2020 01:05:41 -0800 Subject: [PATCH 0689/1314] [3.9] bpo-42086: Document AST operator nodes acts as a singleton (GH-22896) (GH-22897) Automerge-Triggered-By: GH:gvanrossum (cherry picked from commit b37c994e5ac73268abe23c52005b80cdca099793) Co-authored-by: Batuhan Taskaya --- Doc/library/ast.rst | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Doc/library/ast.rst b/Doc/library/ast.rst index 932f7258f9dcdd..95cb017d145ca8 100644 --- a/Doc/library/ast.rst +++ b/Doc/library/ast.rst @@ -1503,6 +1503,13 @@ Async and await fields as :class:`For` and :class:`With`, respectively. Only valid in the body of an :class:`AsyncFunctionDef`. +.. note:: + When a string is parsed by :func:`ast.parse`, operator nodes (subclasses + of :class:`ast.operator`, :class:`ast.unaryop`, :class:`ast.cmpop`, + :class:`ast.boolop` and :class:`ast.expr_context`) on the returned tree + will be singletons. Changes to one will be reflected in all other + occurrences of the same value (e.g. :class:`ast.Add`). + :mod:`ast` Helpers ------------------ From e5729aef6ff67ae7ed05dffc0855477823826191 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 13 Nov 2020 06:11:38 -0800 Subject: [PATCH 0690/1314] bpo-42296: On Windows, fix CTRL+C regression (GH-23257) On Windows, fix a regression in signal handling which prevented to interrupt a program using CTRL+C. The signal handler can be run in a thread different than the Python thread, in which case the test deciding if the thread can handle signals is wrong. On Windows, _PyEval_SignalReceived() now always sets eval_breaker to 1 since it cannot test _Py_ThreadCanHandleSignals(), and eval_frame_handle_pending() always calls _Py_ThreadCanHandleSignals() to recompute eval_breaker. (cherry picked from commit d96a7a83133250377219227b5cfab4dbdddc5d3a) Co-authored-by: Victor Stinner --- .../2020-11-13-13-53-11.bpo-42296.DuGrLJ.rst | 4 ++ Python/ceval.c | 38 ++++++++++++++++--- 2 files changed, 37 insertions(+), 5 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2020-11-13-13-53-11.bpo-42296.DuGrLJ.rst diff --git a/Misc/NEWS.d/next/Core and Builtins/2020-11-13-13-53-11.bpo-42296.DuGrLJ.rst b/Misc/NEWS.d/next/Core and Builtins/2020-11-13-13-53-11.bpo-42296.DuGrLJ.rst new file mode 100644 index 00000000000000..841a26e791ea08 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2020-11-13-13-53-11.bpo-42296.DuGrLJ.rst @@ -0,0 +1,4 @@ +On Windows, fix a regression in signal handling which prevented to interrupt +a program using CTRL+C. The signal handler can be run in a thread different +than the Python thread, in which case the test deciding if the thread can +handle signals is wrong. diff --git a/Python/ceval.c b/Python/ceval.c index 3392cd0365a285..91e879e8042044 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -196,13 +196,18 @@ UNSIGNAL_PENDING_CALLS(PyInterpreterState *interp) static inline void -SIGNAL_PENDING_SIGNALS(PyInterpreterState *interp) +SIGNAL_PENDING_SIGNALS(PyInterpreterState *interp, int force) { struct _ceval_runtime_state *ceval = &interp->runtime->ceval; struct _ceval_state *ceval2 = &interp->ceval; _Py_atomic_store_relaxed(&ceval->signals_pending, 1); - /* eval_breaker is not set to 1 if thread_can_handle_signals() is false */ - COMPUTE_EVAL_BREAKER(interp, ceval, ceval2); + if (force) { + _Py_atomic_store_relaxed(&ceval2->eval_breaker, 1); + } + else { + /* eval_breaker is not set to 1 if thread_can_handle_signals() is false */ + COMPUTE_EVAL_BREAKER(interp, ceval, ceval2); + } } @@ -491,10 +496,22 @@ PyEval_RestoreThread(PyThreadState *tstate) void _PyEval_SignalReceived(PyInterpreterState *interp) { +#ifdef MS_WINDOWS + // bpo-42296: On Windows, _PyEval_SignalReceived() is called from a signal + // handler which can run in a thread different than the Python thread, in + // which case _Py_ThreadCanHandleSignals() is wrong. Ignore + // _Py_ThreadCanHandleSignals() and always set eval_breaker to 1. + // + // The next eval_frame_handle_pending() call will call + // _Py_ThreadCanHandleSignals() to recompute eval_breaker. + int force = 1; +#else + int force = 0; +#endif /* bpo-30703: Function called when the C signal handler of Python gets a signal. We cannot queue a callback using _PyEval_AddPendingCall() since that function is not async-signal-safe. */ - SIGNAL_PENDING_SIGNALS(interp); + SIGNAL_PENDING_SIGNALS(interp, force); } /* Push one item onto the queue while holding the lock. */ @@ -594,7 +611,7 @@ handle_signals(PyThreadState *tstate) UNSIGNAL_PENDING_SIGNALS(tstate->interp); if (_PyErr_CheckSignalsTstate(tstate) < 0) { /* On failure, re-schedule a call to handle_signals(). */ - SIGNAL_PENDING_SIGNALS(tstate->interp); + SIGNAL_PENDING_SIGNALS(tstate->interp, 0); return -1; } return 0; @@ -883,6 +900,17 @@ eval_frame_handle_pending(PyThreadState *tstate) return -1; } +#ifdef MS_WINDOWS + // bpo-42296: On Windows, _PyEval_SignalReceived() can be called in a + // different thread than the Python thread, in which case + // _Py_ThreadCanHandleSignals() is wrong. Recompute eval_breaker in the + // current Python thread with the correct _Py_ThreadCanHandleSignals() + // value. It prevents to interrupt the eval loop at every instruction if + // the current Python thread cannot handle signals (if + // _Py_ThreadCanHandleSignals() is false). + COMPUTE_EVAL_BREAKER(tstate->interp, ceval, ceval2); +#endif + return 0; } From ec306a2fd91d8b961b2a80c080dd2262bb17d862 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Fri, 13 Nov 2020 16:38:06 +0100 Subject: [PATCH 0691/1314] bpo-41617: Add _Py__has_builtin() macro (GH-23260) (GH-23262) Fix building pycore_bitutils.h internal header on old clang version without __builtin_bswap16() (ex: Xcode 4.6.3 on Mac OS X 10.7). Add a new private _Py__has_builtin() macro to check for availability of a preprocessor builtin function. Co-Authored-By: Joshua Root Co-authored-by: Joshua Root (cherry picked from commit b3b98082c5431e77c64cab2c85525a804436b505) --- Include/internal/pycore_byteswap.h | 15 ++++++--------- Include/pyport.h | 12 ++++++++++++ .../2020-11-13-15-04-53.bpo-41617.98_oaE.rst | 3 +++ 3 files changed, 21 insertions(+), 9 deletions(-) create mode 100644 Misc/NEWS.d/next/Build/2020-11-13-15-04-53.bpo-41617.98_oaE.rst diff --git a/Include/internal/pycore_byteswap.h b/Include/internal/pycore_byteswap.h index 975e150dd91bb3..2b20fc6c7d3136 100644 --- a/Include/internal/pycore_byteswap.h +++ b/Include/internal/pycore_byteswap.h @@ -15,12 +15,9 @@ extern "C" { # error "this header requires Py_BUILD_CORE define" #endif -#if ((defined(__GNUC__) \ - && ((__GNUC__ >= 5) || (__GNUC__ == 4) && (__GNUC_MINOR__ >= 8))) \ - || (defined(__clang__) \ - && (__clang_major__ >= 4 \ - || (__clang_major__ == 3 && __clang_minor__ >= 2)))) - /* __builtin_bswap16() is available since GCC 4.8 and clang 3.2, +#if defined(__GNUC__) \ + && ((__GNUC__ >= 5) || (__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)) + /* __builtin_bswap16() is available since GCC 4.8, __builtin_bswap32() is available since GCC 4.3, __builtin_bswap64() is available since GCC 4.3. */ # define _PY_HAVE_BUILTIN_BSWAP @@ -34,7 +31,7 @@ extern "C" { static inline uint16_t _Py_bswap16(uint16_t word) { -#ifdef _PY_HAVE_BUILTIN_BSWAP +#if defined(_PY_HAVE_BUILTIN_BSWAP) || _Py__has_builtin(__builtin_bswap16) return __builtin_bswap16(word); #elif defined(_MSC_VER) Py_BUILD_ASSERT(sizeof(word) == sizeof(unsigned short)); @@ -49,7 +46,7 @@ _Py_bswap16(uint16_t word) static inline uint32_t _Py_bswap32(uint32_t word) { -#ifdef _PY_HAVE_BUILTIN_BSWAP +#if defined(_PY_HAVE_BUILTIN_BSWAP) || _Py__has_builtin(__builtin_bswap32) return __builtin_bswap32(word); #elif defined(_MSC_VER) Py_BUILD_ASSERT(sizeof(word) == sizeof(unsigned long)); @@ -66,7 +63,7 @@ _Py_bswap32(uint32_t word) static inline uint64_t _Py_bswap64(uint64_t word) { -#ifdef _PY_HAVE_BUILTIN_BSWAP +#if defined(_PY_HAVE_BUILTIN_BSWAP) || _Py__has_builtin(__builtin_bswap64) return __builtin_bswap64(word); #elif defined(_MSC_VER) return _byteswap_uint64(word); diff --git a/Include/pyport.h b/Include/pyport.h index 6505af467683d8..4bd4eb4751b952 100644 --- a/Include/pyport.h +++ b/Include/pyport.h @@ -863,4 +863,16 @@ extern _invalid_parameter_handler _Py_silent_invalid_parameter_handler; # define _Py_NO_RETURN #endif + +// Preprocessor check for a builtin preprocessor function. Always return 0 +// if __has_builtin() macro is not defined. +// +// __has_builtin() is available on clang and GCC 10. +#ifdef __has_builtin +# define _Py__has_builtin(x) __has_builtin(x) +#else +# define _Py__has_builtin(x) 0 +#endif + + #endif /* Py_PYPORT_H */ diff --git a/Misc/NEWS.d/next/Build/2020-11-13-15-04-53.bpo-41617.98_oaE.rst b/Misc/NEWS.d/next/Build/2020-11-13-15-04-53.bpo-41617.98_oaE.rst new file mode 100644 index 00000000000000..a5f35b25e8bf6a --- /dev/null +++ b/Misc/NEWS.d/next/Build/2020-11-13-15-04-53.bpo-41617.98_oaE.rst @@ -0,0 +1,3 @@ +Fix building ``pycore_bitutils.h`` internal header on old clang version +without ``__builtin_bswap16()`` (ex: Xcode 4.6.3 on Mac OS X 10.7). Patch by +Joshua Root and Victor Stinner. From 0f4dd87a31130b245ec4c6ded9fd6f247e700c0d Mon Sep 17 00:00:00 2001 From: Dong-hee Na Date: Sat, 14 Nov 2020 00:45:02 +0900 Subject: [PATCH 0692/1314] [3.9] bpo-42042: Use ids attribute instead of names attribute (GH-22739) (GH-23265) (cherry picked from commit 09490a109faaee9cc393b52742a8575c116c56ba) Co-authored-by: Dong-hee Na --- Doc/tools/extensions/c_annotations.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/tools/extensions/c_annotations.py b/Doc/tools/extensions/c_annotations.py index fa8244a8fd318e..76c9d920cbe31f 100644 --- a/Doc/tools/extensions/c_annotations.py +++ b/Doc/tools/extensions/c_annotations.py @@ -79,9 +79,9 @@ def add_annotations(self, app, doctree): classes=['stableabi'])) if par['objtype'] != 'function': continue - if not par[0].has_key('names') or not par[0]['names']: + if not par[0].has_key('ids') or not par[0]['ids']: continue - name = par[0]['names'][0] + name = par[0]['ids'][0] if name.startswith("c."): name = name[2:] entry = self.get(name) From 4defeb007195d2d17ea404b0b6291d1d233010f4 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 13 Nov 2020 10:19:05 -0800 Subject: [PATCH 0693/1314] bpo-42344: Improve pseudo implementation for SimpleNamespace (GH-23264) (GH-23270) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit (cherry picked from commit bbeb2d266d6fc1ca9778726d0397d9d6f7a946e3) Co-authored-by: Jürgen Gmach Co-authored-by: Jürgen Gmach --- Doc/library/types.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Doc/library/types.rst b/Doc/library/types.rst index 5d68c6852678c2..0fe3822fa542e3 100644 --- a/Doc/library/types.rst +++ b/Doc/library/types.rst @@ -384,7 +384,9 @@ Additional Utility Classes and Functions return "{}({})".format(type(self).__name__, ", ".join(items)) def __eq__(self, other): - return self.__dict__ == other.__dict__ + if isinstance(self, SimpleNamespace) and isinstance(other, SimpleNamespace): + return self.__dict__ == other.__dict__ + return NotImplemented ``SimpleNamespace`` may be useful as a replacement for ``class NS: pass``. However, for a structured record type use :func:`~collections.namedtuple` From faadc52e755cdb316a53f3db5aa11cb97f1c4b87 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 13 Nov 2020 14:47:27 -0800 Subject: [PATCH 0694/1314] bpo-40754: Adds _testinternalcapi to Windows installer for test suite (GH-23271) (cherry picked from commit 9b6934230c35e24d8582ea8c58456fa8eab72ae2) Co-authored-by: Steve Dower --- .../next/Tests/2020-11-13-21-51-34.bpo-40754.Ekoxkg.rst | 1 + Tools/msi/test/test_files.wxs | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Tests/2020-11-13-21-51-34.bpo-40754.Ekoxkg.rst diff --git a/Misc/NEWS.d/next/Tests/2020-11-13-21-51-34.bpo-40754.Ekoxkg.rst b/Misc/NEWS.d/next/Tests/2020-11-13-21-51-34.bpo-40754.Ekoxkg.rst new file mode 100644 index 00000000000000..4bd423b54a4499 --- /dev/null +++ b/Misc/NEWS.d/next/Tests/2020-11-13-21-51-34.bpo-40754.Ekoxkg.rst @@ -0,0 +1 @@ +Include ``_testinternalcapi`` module in Windows installer for test suite diff --git a/Tools/msi/test/test_files.wxs b/Tools/msi/test/test_files.wxs index 82a9115f759023..9127ce894819e5 100644 --- a/Tools/msi/test/test_files.wxs +++ b/Tools/msi/test/test_files.wxs @@ -1,6 +1,6 @@ - + - + From 2837241f22be33a5597707b2aa723cb2cf6f3967 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 14 Nov 2020 04:24:21 -0800 Subject: [PATCH 0695/1314] fix typo in ThreadedChildWatcher docs (GH-23277) (cherry picked from commit 8836574a0f34ae81643c8af79bbb9062e332a4e3) Co-authored-by: Thomas Grainger --- Doc/library/asyncio-policy.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/asyncio-policy.rst b/Doc/library/asyncio-policy.rst index 88e69ceff9adc1..5e69525e90dd27 100644 --- a/Doc/library/asyncio-policy.rst +++ b/Doc/library/asyncio-policy.rst @@ -209,7 +209,7 @@ implementation used by the asyncio event loop: It works reliably even when the asyncio event loop is run in a non-main OS thread. There is no noticeable overhead when handling a big number of children (*O(1)* each - time a child terminates), but stating a thread per process requires extra memory. + time a child terminates), but starting a thread per process requires extra memory. This watcher is used by default. From 2369759a47c5292bacf2eef17b4e2388b7d36675 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 15 Nov 2020 17:52:22 -0800 Subject: [PATCH 0696/1314] bpo-42317: Improve docs of typing.get_args concerning Union (GH-23254) (cherry picked from commit c3b9592244a9112d8af9610ff1c4e1e4cd4bfaca) Co-authored-by: Dominik1123 <15989985+Dominik1123@users.noreply.github.com> --- Doc/library/typing.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst index a5f8b0403f8031..324abdeb5eb5bb 100644 --- a/Doc/library/typing.rst +++ b/Doc/library/typing.rst @@ -1687,6 +1687,9 @@ Introspection helpers For a typing object of the form ``X[Y, Z, ...]`` these functions return ``X`` and ``(Y, Z, ...)``. If ``X`` is a generic alias for a builtin or :mod:`collections` class, it gets normalized to the original class. + If ``X`` is a :class:`Union` contained in another generic type, + the order of ``(Y, Z, ...)`` may be different from the order of + the original arguments ``[Y, Z, ...]`` due to type caching. For unsupported objects return ``None`` and ``()`` correspondingly. Examples:: From ec0788c7c9d10338fe27b34a8db186e324d5cc7f Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 15 Nov 2020 18:27:56 -0800 Subject: [PATCH 0697/1314] More updates to the descriptor howto guide (GH-23238) (GH-23308) --- Doc/howto/descriptor.rst | 107 +++++++++++++++++++++++---------------- 1 file changed, 62 insertions(+), 45 deletions(-) diff --git a/Doc/howto/descriptor.rst b/Doc/howto/descriptor.rst index 8c2e8d562153db..76987fda22b59d 100644 --- a/Doc/howto/descriptor.rst +++ b/Doc/howto/descriptor.rst @@ -16,7 +16,7 @@ storage, and deletion. This guide has four major sections: 1) The "primer" gives a basic overview, moving gently from simple examples, - adding one feature at a time. It is a great place to start. + adding one feature at a time. Start here if you're new to descriptors. 2) The second section shows a complete, practical descriptor example. If you already know the basics, start there. @@ -42,7 +42,8 @@ add new capabilities one by one. Simple example: A descriptor that returns a constant ---------------------------------------------------- -The :class:`Ten` class is a descriptor that always returns the constant ``10``:: +The :class:`Ten` class is a descriptor that always returns the constant ``10`` +from its :meth:`__get__` method:: class Ten: @@ -64,9 +65,11 @@ and descriptor lookup:: >>> a.y # Descriptor lookup 10 -In the ``a.x`` attribute lookup, the dot operator finds the value ``5`` stored -in the class dictionary. In the ``a.y`` descriptor lookup, the dot operator -calls the descriptor's :meth:`__get__()` method. That method returns ``10``. +In the ``a.x`` attribute lookup, the dot operator finds the key ``x`` and the +value ``5`` in the class dictionary. In the ``a.y`` lookup, the dot operator +finds a descriptor instance, recognized by its ``__get__`` method, and calls +that method which returns ``10``. + Note that the value ``10`` is not stored in either the class dictionary or the instance dictionary. Instead, the value ``10`` is computed on demand. @@ -79,7 +82,8 @@ In the next section, we'll create something more useful, a dynamic lookup. Dynamic lookups --------------- -Interesting descriptors typically run computations instead of doing lookups:: +Interesting descriptors typically run computations instead of returning +constants:: import os @@ -98,16 +102,15 @@ Interesting descriptors typically run computations instead of doing lookups:: An interactive session shows that the lookup is dynamic — it computes different, updated answers each time:: - >>> g = Directory('games') >>> s = Directory('songs') + >>> g = Directory('games') + >>> s.size # The songs directory has twenty files + 20 >>> g.size # The games directory has three files 3 - >>> os.system('touch games/newfile') # Add a fourth file to the directory - 0 - >>> g.size # Automatically updated + >>> open('games/newfile').close() # Add a fourth file to the directory + >>> g.size # File count is automatically updated 4 - >>> s.size # The songs directory has twenty files - 20 Besides showing how descriptors can run computations, this example also reveals the purpose of the parameters to :meth:`__get__`. The *self* @@ -208,7 +211,7 @@ be recorded, giving each descriptor its own *public_name* and *private_name*:: def __set_name__(self, owner, name): self.public_name = name - self.private_name = f'_{name}' + self.private_name = '_' + name def __get__(self, obj, objtype=None): value = getattr(obj, self.private_name) @@ -265,9 +268,10 @@ A :term:`descriptor` is what we call any object that defines :meth:`__get__`, Optionally, descriptors can have a :meth:`__set_name__` method. This is only used in cases where a descriptor needs to know either the class where it was -created or the name of class variable it was assigned to. +created or the name of class variable it was assigned to. (This method, if +present, is called even if the class is not a descriptor.) -Descriptors get invoked by the dot operator during attribute lookup. If a +Descriptors get invoked by the dot "operator" during attribute lookup. If a descriptor is accessed indirectly with ``vars(some_class)[descriptor_name]``, the descriptor instance is returned without invoking it. @@ -275,7 +279,7 @@ Descriptors only work when used as class variables. When put in instances, they have no effect. The main motivation for descriptors is to provide a hook allowing objects -stored in class variables to control what happens during dotted lookup. +stored in class variables to control what happens during attribute lookup. Traditionally, the calling class controls what happens during lookup. Descriptors invert that relationship and allow the data being looked-up to @@ -310,7 +314,7 @@ managed attribute descriptor:: class Validator(ABC): def __set_name__(self, owner, name): - self.private_name = f'_{name}' + self.private_name = '_' + name def __get__(self, obj, objtype=None): return getattr(obj, self.private_name) @@ -435,23 +439,21 @@ Defines descriptors, summarizes the protocol, and shows how descriptors are called. Provides an example showing how object relational mappings work. Learning about descriptors not only provides access to a larger toolset, it -creates a deeper understanding of how Python works and an appreciation for the -elegance of its design. +creates a deeper understanding of how Python works. Definition and introduction --------------------------- -In general, a descriptor is an object attribute with "binding behavior", one -whose attribute access has been overridden by methods in the descriptor -protocol. Those methods are :meth:`__get__`, :meth:`__set__`, and -:meth:`__delete__`. If any of those methods are defined for an object, it is -said to be a :term:`descriptor`. +In general, a descriptor is an attribute value that has one of the methods in +the descriptor protocol. Those methods are :meth:`__get__`, :meth:`__set__`, +and :meth:`__delete__`. If any of those methods are defined for an the +attribute, it is said to be a :term:`descriptor`. The default behavior for attribute access is to get, set, or delete the attribute from an object's dictionary. For instance, ``a.x`` has a lookup chain starting with ``a.__dict__['x']``, then ``type(a).__dict__['x']``, and -continuing through the base classes of ``type(a)``. If the +continuing through the method resolution order of ``type(a)``. If the looked-up value is an object defining one of the descriptor methods, then Python may override the default behavior and invoke the descriptor method instead. Where this occurs in the precedence chain depends on which descriptor methods @@ -479,7 +481,7 @@ as an attribute. If an object defines :meth:`__set__` or :meth:`__delete__`, it is considered a data descriptor. Descriptors that only define :meth:`__get__` are called -non-data descriptors (they are typically used for methods but other uses are +non-data descriptors (they are often used for methods but other uses are possible). Data and non-data descriptors differ in how overrides are calculated with @@ -504,8 +506,9 @@ But it is more common for a descriptor to be invoked automatically from attribute access. The expression ``obj.x`` looks up the attribute ``x`` in the chain of -namespaces for ``obj``. If the search finds a descriptor, its :meth:`__get__` -method is invoked according to the precedence rules listed below. +namespaces for ``obj``. If the search finds a descriptor outside of the +instance ``__dict__``, its :meth:`__get__` method is invoked according to the +precedence rules listed below. The details of invocation depend on whether ``obj`` is an object, class, or instance of super. @@ -529,25 +532,38 @@ a pure Python equivalent:: "Emulate PyObject_GenericGetAttr() in Objects/object.c" null = object() objtype = type(obj) - value = getattr(objtype, name, null) - if value is not null and hasattr(value, '__get__'): - if hasattr(value, '__set__') or hasattr(value, '__delete__'): - return value.__get__(obj, objtype) # data descriptor - try: - return vars(obj)[name] # instance variable - except (KeyError, TypeError): - pass - if hasattr(value, '__get__'): - return value.__get__(obj, objtype) # non-data descriptor - if value is not null: - return value # class variable - # Emulate slot_tp_getattr_hook() in Objects/typeobject.c - if hasattr(objtype, '__getattr__'): - return objtype.__getattr__(obj, name) # __getattr__ hook + cls_var = getattr(objtype, name, null) + descr_get = getattr(type(cls_var), '__get__', null) + if descr_get is not null: + if (hasattr(type(cls_var), '__set__') + or hasattr(type(cls_var), '__delete__')): + return descr_get(cls_var, obj, objtype) # data descriptor + if hasattr(obj, '__dict__') and name in vars(obj): + return vars(obj)[name] # instance variable + if descr_get is not null: + return descr_get(cls_var, obj, objtype) # non-data descriptor + if cls_var is not null: + return cls_var # class variable raise AttributeError(name) -The :exc:`TypeError` exception handler is needed because the instance dictionary -doesn't exist when its class defines :term:`__slots__`. +Interestingly, attribute lookup doesn't call :meth:`object.__getattribute__` +directly. Instead, both the dot operator and the :func:`getattr` function +perform attribute lookup by way of a helper function:: + + def getattr_hook(obj, name): + "Emulate slot_tp_getattr_hook() in Objects/typeobject.c" + try: + return obj.__getattribute__(name) + except AttributeError: + if not hasattr(type(obj), '__getattr__'): + raise + return type(obj).__getattr__(obj, name) # __getattr__ + +So if :meth:`__getattr__` exists, it is called whenever :meth:`__getattribute__` +raises :exc:`AttributeError` (either directly or in one of the descriptor calls). + +Also, if a user calls :meth:`object.__getattribute__` directly, the +:meth:`__getattr__` hook is bypassed entirely. Invocation from a class @@ -690,6 +706,7 @@ it can be updated:: >>> Movie('Star Wars').director 'J.J. Abrams' + Pure Python Equivalents ^^^^^^^^^^^^^^^^^^^^^^^ From 7c4d8fa82aae98f2d638be68f21e9524a92a38e6 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 15 Nov 2020 21:27:03 -0800 Subject: [PATCH 0698/1314] bpo-42153 Fix link to IMAP documents in imaplib.rst (GH-23297) The University of Washington stopped hosting the IMAP documents. Link to a rescued copy on GitHub. (cherry picked from commit aa01011003bb855cd52abfd49f2443446590d913) Co-authored-by: Yash Shete --- Doc/library/imaplib.rst | 6 +++--- .../Documentation/2020-11-15-13-46-31.bpo-42153.KjBhx3.rst | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) create mode 100644 Misc/NEWS.d/next/Documentation/2020-11-15-13-46-31.bpo-42153.KjBhx3.rst diff --git a/Doc/library/imaplib.rst b/Doc/library/imaplib.rst index 02ecfd95d43767..65681ec093598c 100644 --- a/Doc/library/imaplib.rst +++ b/Doc/library/imaplib.rst @@ -174,9 +174,9 @@ example of usage. .. seealso:: - Documents describing the protocol, and sources and binaries for servers - implementing it, can all be found at the University of Washington's *IMAP - Information Center* (https://www.washington.edu/imap/). + Documents describing the protocol, sources for servers + implementing it, by the University of Washington's IMAP Information Center + can all be found at (**Source Code**) https://github.com/uw-imap/imap (**Not Maintained**). .. _imap4-objects: diff --git a/Misc/NEWS.d/next/Documentation/2020-11-15-13-46-31.bpo-42153.KjBhx3.rst b/Misc/NEWS.d/next/Documentation/2020-11-15-13-46-31.bpo-42153.KjBhx3.rst new file mode 100644 index 00000000000000..0a9451a63fb4f8 --- /dev/null +++ b/Misc/NEWS.d/next/Documentation/2020-11-15-13-46-31.bpo-42153.KjBhx3.rst @@ -0,0 +1 @@ +Fix the URL for the IMAP protocol documents. From cf70854f10096446115408b5a94030b30594a459 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 16 Nov 2020 07:17:17 -0800 Subject: [PATCH 0699/1314] bpo-42350: Fix Thread._reset_internal_locks() (GH-23268) Fix the threading.Thread class at fork: do nothing if the thread is already stopped (ex: fork called at Python exit). Previously, an error was logged in the child process. (cherry picked from commit 5909a494cd3ba43143b28bd439773ed85a485dfc) Co-authored-by: Victor Stinner --- Lib/test/test_threading.py | 29 +++++++++++++++++++ Lib/threading.py | 8 +++-- .../2020-11-13-18-53-50.bpo-42350.rsql7V.rst | 3 ++ 3 files changed, 38 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2020-11-13-18-53-50.bpo-42350.rsql7V.rst diff --git a/Lib/test/test_threading.py b/Lib/test/test_threading.py index 81e5f70d6d6aea..c21cdf8eb7be9c 100644 --- a/Lib/test/test_threading.py +++ b/Lib/test/test_threading.py @@ -439,6 +439,35 @@ def test_daemon_param(self): t = threading.Thread(daemon=True) self.assertTrue(t.daemon) + @unittest.skipUnless(hasattr(os, 'fork'), 'needs os.fork()') + def test_fork_at_exit(self): + # bpo-42350: Calling os.fork() after threading._shutdown() must + # not log an error. + code = textwrap.dedent(""" + import atexit + import os + import sys + from test.support import wait_process + + # Import the threading module to register its "at fork" callback + import threading + + def exit_handler(): + pid = os.fork() + if not pid: + print("child process ok", file=sys.stderr, flush=True) + # child process + sys.exit() + else: + wait_process(pid, exitcode=0) + + # exit_handler() will be called after threading._shutdown() + atexit.register(exit_handler) + """) + _, out, err = assert_python_ok("-c", code) + self.assertEqual(out, b'') + self.assertEqual(err.rstrip(), b'child process ok') + @unittest.skipUnless(hasattr(os, 'fork'), 'test needs fork()') def test_dummy_thread_after_fork(self): # Issue #14308: a dummy thread in the active list doesn't mess up diff --git a/Lib/threading.py b/Lib/threading.py index ab29db77a747a2..d96d99a713e904 100644 --- a/Lib/threading.py +++ b/Lib/threading.py @@ -826,8 +826,12 @@ def _reset_internal_locks(self, is_alive): # they may be in an invalid state leading to a deadlock or crash. self._started._at_fork_reinit() if is_alive: - self._tstate_lock._at_fork_reinit() - self._tstate_lock.acquire() + # bpo-42350: If the fork happens when the thread is already stopped + # (ex: after threading._shutdown() has been called), _tstate_lock + # is None. Do nothing in this case. + if self._tstate_lock is not None: + self._tstate_lock._at_fork_reinit() + self._tstate_lock.acquire() else: # The thread isn't alive after fork: it doesn't have a tstate # anymore. diff --git a/Misc/NEWS.d/next/Library/2020-11-13-18-53-50.bpo-42350.rsql7V.rst b/Misc/NEWS.d/next/Library/2020-11-13-18-53-50.bpo-42350.rsql7V.rst new file mode 100644 index 00000000000000..090ea2266633e6 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2020-11-13-18-53-50.bpo-42350.rsql7V.rst @@ -0,0 +1,3 @@ +Fix the :class:`threading.Thread` class at fork: do nothing if the thread is +already stopped (ex: fork called at Python exit). Previously, an error was +logged in the child process. From 2b800ef809eefbc96a536e4b43a8285f2353f64d Mon Sep 17 00:00:00 2001 From: Lysandros Nikolaou Date: Tue, 17 Nov 2020 01:38:58 +0200 Subject: [PATCH 0700/1314] bpo-42374: Allow unparenthesized walrus in genexps (GH-23319) (GH-23329) This fixes a regression that was introduced by the new parser. (cherry picked from commit cb3e5ed0716114393696ec7201e51fe0595eab4f) --- Grammar/python.gram | 2 +- Lib/test/test_named_expressions.py | 9 +++++++++ .../2020-11-16-17-57-09.bpo-42374.t7np1E.rst | 2 ++ Parser/pegen/parse.c | 12 ++++++------ 4 files changed, 18 insertions(+), 7 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2020-11-16-17-57-09.bpo-42374.t7np1E.rst diff --git a/Grammar/python.gram b/Grammar/python.gram index 60eeb367e95ba5..257d2f5153263c 100644 --- a/Grammar/python.gram +++ b/Grammar/python.gram @@ -503,7 +503,7 @@ group[expr_ty]: | '(' a=(yield_expr | named_expression) ')' { a } | invalid_group genexp[expr_ty]: - | '(' a=expression ~ b=for_if_clauses ')' { _Py_GeneratorExp(a, b, EXTRA) } + | '(' a=named_expression ~ b=for_if_clauses ')' { _Py_GeneratorExp(a, b, EXTRA) } | invalid_comprehension set[expr_ty]: '{' a=expressions_list '}' { _Py_Set(a, EXTRA) } setcomp[expr_ty]: diff --git a/Lib/test/test_named_expressions.py b/Lib/test/test_named_expressions.py index c813830ce6d3cf..d614f3267fad37 100644 --- a/Lib/test/test_named_expressions.py +++ b/Lib/test/test_named_expressions.py @@ -513,6 +513,15 @@ def g(): self.assertEqual(nonlocal_var, None) f() + def test_named_expression_scope_in_genexp(self): + a = 1 + b = [1, 2, 3, 4] + genexp = (c := i + a for i in b) + + self.assertNotIn("c", locals()) + for idx, elem in enumerate(genexp): + self.assertEqual(elem, b[idx] + a) + if __name__ == "__main__": unittest.main() diff --git a/Misc/NEWS.d/next/Core and Builtins/2020-11-16-17-57-09.bpo-42374.t7np1E.rst b/Misc/NEWS.d/next/Core and Builtins/2020-11-16-17-57-09.bpo-42374.t7np1E.rst new file mode 100644 index 00000000000000..d86d038c8425c5 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2020-11-16-17-57-09.bpo-42374.t7np1E.rst @@ -0,0 +1,2 @@ +Fix a regression introduced by the new parser, where an unparenthesized walrus operator +was not allowed within generator expressions. \ No newline at end of file diff --git a/Parser/pegen/parse.c b/Parser/pegen/parse.c index 97cefa9c2a3d42..c78abfadd2bc91 100644 --- a/Parser/pegen/parse.c +++ b/Parser/pegen/parse.c @@ -11381,7 +11381,7 @@ group_rule(Parser *p) return _res; } -// genexp: '(' expression ~ for_if_clauses ')' | invalid_comprehension +// genexp: '(' named_expression ~ for_if_clauses ')' | invalid_comprehension static expr_ty genexp_rule(Parser *p) { @@ -11401,12 +11401,12 @@ genexp_rule(Parser *p) UNUSED(_start_lineno); // Only used by EXTRA macro int _start_col_offset = p->tokens[_mark]->col_offset; UNUSED(_start_col_offset); // Only used by EXTRA macro - { // '(' expression ~ for_if_clauses ')' + { // '(' named_expression ~ for_if_clauses ')' if (p->error_indicator) { D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> genexp[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'(' expression ~ for_if_clauses ')'")); + D(fprintf(stderr, "%*c> genexp[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'(' named_expression ~ for_if_clauses ')'")); int _cut_var = 0; Token * _literal; Token * _literal_1; @@ -11415,7 +11415,7 @@ genexp_rule(Parser *p) if ( (_literal = _PyPegen_expect_token(p, 7)) // token='(' && - (a = expression_rule(p)) // expression + (a = named_expression_rule(p)) // named_expression && (_cut_var = 1) && @@ -11424,7 +11424,7 @@ genexp_rule(Parser *p) (_literal_1 = _PyPegen_expect_token(p, 8)) // token=')' ) { - D(fprintf(stderr, "%*c+ genexp[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'(' expression ~ for_if_clauses ')'")); + D(fprintf(stderr, "%*c+ genexp[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'(' named_expression ~ for_if_clauses ')'")); Token *_token = _PyPegen_get_last_nonnwhitespace_token(p); if (_token == NULL) { D(p->level--); @@ -11444,7 +11444,7 @@ genexp_rule(Parser *p) } p->mark = _mark; D(fprintf(stderr, "%*c%s genexp[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'(' expression ~ for_if_clauses ')'")); + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'(' named_expression ~ for_if_clauses ')'")); if (_cut_var) { D(p->level--); return NULL; From 2c38e49dba88a39679b2182ca3f5f478d3a3f647 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 16 Nov 2020 23:50:43 -0800 Subject: [PATCH 0701/1314] [3.9] bpo-42120: Remove macro defining copysign to _copysign on Windows (GH-23326) (GH-23331) (cherry picked from commit 9cc9e277254023c0ca08e1a9e379fd89475ca9c2) Co-authored-by: Steve Dower --- .../NEWS.d/next/Windows/2020-11-16-22-41-02.bpo-42120.9scgko.rst | 1 + PC/pyconfig.h | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Windows/2020-11-16-22-41-02.bpo-42120.9scgko.rst diff --git a/Misc/NEWS.d/next/Windows/2020-11-16-22-41-02.bpo-42120.9scgko.rst b/Misc/NEWS.d/next/Windows/2020-11-16-22-41-02.bpo-42120.9scgko.rst new file mode 100644 index 00000000000000..c574956d11d932 --- /dev/null +++ b/Misc/NEWS.d/next/Windows/2020-11-16-22-41-02.bpo-42120.9scgko.rst @@ -0,0 +1 @@ +Remove macro definition of ``copysign`` (to ``_copysign``) in headers. diff --git a/PC/pyconfig.h b/PC/pyconfig.h index 02216b5068012a..d7d3cf081e0505 100644 --- a/PC/pyconfig.h +++ b/PC/pyconfig.h @@ -193,7 +193,6 @@ typedef int pid_t; #define Py_IS_NAN _isnan #define Py_IS_INFINITY(X) (!_finite(X) && !_isnan(X)) #define Py_IS_FINITE(X) _finite(X) -#define copysign _copysign /* define some ANSI types that are not defined in earlier Win headers */ #if _MSC_VER >= 1200 From 656d50f98d9aec5e5283f77adc38e91813273662 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 17 Nov 2020 07:01:55 -0800 Subject: [PATCH 0702/1314] bpo-40637: Don't test builtin PBKDF2 without builtin hashes (GH-20980) Skip testing of pure Python PBKDF2 when one or more builtin hash module is not available. Otherwise the import of hashlib prints noise on stderr. Signed-off-by: Christian Heimes (cherry picked from commit 975022b77b0024ea1548f19d5f91aba5ba1eed59) Co-authored-by: Christian Heimes --- Lib/test/test_hashlib.py | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/Lib/test/test_hashlib.py b/Lib/test/test_hashlib.py index 86f20a7aff83af..86f31a55878239 100644 --- a/Lib/test/test_hashlib.py +++ b/Lib/test/test_hashlib.py @@ -24,17 +24,26 @@ # Were we compiled --with-pydebug or with #define Py_DEBUG? COMPILED_WITH_PYDEBUG = hasattr(sys, 'gettotalrefcount') -c_hashlib = import_fresh_module('hashlib', fresh=['_hashlib']) -py_hashlib = import_fresh_module('hashlib', blocked=['_hashlib']) - +# default builtin hash module +default_builtin_hashes = {'md5', 'sha1', 'sha256', 'sha512', 'sha3', 'blake2'} +# --with-builtin-hashlib-hashes override builtin_hashes = sysconfig.get_config_var("PY_BUILTIN_HASHLIB_HASHES") if builtin_hashes is None: - builtin_hashes = {'md5', 'sha1', 'sha256', 'sha512', 'sha3', 'blake2'} + builtin_hashes = default_builtin_hashes else: builtin_hashes = { m.strip() for m in builtin_hashes.strip('"').lower().split(",") } +# hashlib with and without OpenSSL backend for PBKDF2 +# only import builtin_hashlib when all builtin hashes are available. +# Otherwise import prints noise on stderr +openssl_hashlib = import_fresh_module('hashlib', fresh=['_hashlib']) +if builtin_hashes == default_builtin_hashes: + builtin_hashlib = import_fresh_module('hashlib', blocked=['_hashlib']) +else: + builtin_hashlib = None + try: from _hashlib import HASH, HASHXOF, openssl_md_meth_names except ImportError: @@ -1030,16 +1039,16 @@ def _test_pbkdf2_hmac(self, pbkdf2, supported): iterations=1, dklen=None) self.assertEqual(out, self.pbkdf2_results['sha1'][0][0]) + @unittest.skipIf(builtin_hashlib is None, "test requires builtin_hashlib") def test_pbkdf2_hmac_py(self): - self._test_pbkdf2_hmac(py_hashlib.pbkdf2_hmac, builtin_hashes) + self._test_pbkdf2_hmac(builtin_hashlib.pbkdf2_hmac, builtin_hashes) - @unittest.skipUnless(hasattr(c_hashlib, 'pbkdf2_hmac'), + @unittest.skipUnless(hasattr(openssl_hashlib, 'pbkdf2_hmac'), ' test requires OpenSSL > 1.0') def test_pbkdf2_hmac_c(self): - self._test_pbkdf2_hmac(c_hashlib.pbkdf2_hmac, openssl_md_meth_names) - + self._test_pbkdf2_hmac(openssl_hashlib.pbkdf2_hmac, openssl_md_meth_names) - @unittest.skipUnless(hasattr(c_hashlib, 'scrypt'), + @unittest.skipUnless(hasattr(hashlib, 'scrypt'), ' test requires OpenSSL > 1.1') def test_scrypt(self): for password, salt, n, r, p, expected in self.scrypt_test_vectors: From ac472b316cbb22ab8b750a474e991b46d1e92e15 Mon Sep 17 00:00:00 2001 From: Yurii Karabas <1998uriyyo@gmail.com> Date: Tue, 17 Nov 2020 17:23:36 +0200 Subject: [PATCH 0703/1314] [3.9] bpo-42345: Fix three issues with typing.Literal parameters (GH-23294) (GH-23335) Literal equality no longer depends on the order of arguments. Fix issue related to `typing.Literal` caching by adding `typed` parameter to `typing._tp_cache` function. Add deduplication of `typing.Literal` arguments. (cherry picked from commit f03d318ca42578e45405717aedd4ac26ea52aaed) Co-authored-by: Yurii Karabas <1998uriyyo@gmail.com> --- Lib/test/test_typing.py | 25 +++++ Lib/typing.py | 100 ++++++++++++++---- Misc/ACKS | 1 + .../2020-11-15-15-23-34.bpo-42345.hiIR7x.rst | 2 + 4 files changed, 105 insertions(+), 23 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2020-11-15-15-23-34.bpo-42345.hiIR7x.rst diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index 67cadc37e4fbe4..9d82eec3f53761 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -532,6 +532,7 @@ def test_repr(self): self.assertEqual(repr(Literal[int]), "typing.Literal[int]") self.assertEqual(repr(Literal), "typing.Literal") self.assertEqual(repr(Literal[None]), "typing.Literal[None]") + self.assertEqual(repr(Literal[1, 2, 3, 3]), "typing.Literal[1, 2, 3]") def test_cannot_init(self): with self.assertRaises(TypeError): @@ -563,6 +564,30 @@ def test_no_multiple_subscripts(self): with self.assertRaises(TypeError): Literal[1][1] + def test_equal(self): + self.assertNotEqual(Literal[0], Literal[False]) + self.assertNotEqual(Literal[True], Literal[1]) + self.assertNotEqual(Literal[1], Literal[2]) + self.assertNotEqual(Literal[1, True], Literal[1]) + self.assertEqual(Literal[1], Literal[1]) + self.assertEqual(Literal[1, 2], Literal[2, 1]) + self.assertEqual(Literal[1, 2, 3], Literal[1, 2, 3, 3]) + + def test_args(self): + self.assertEqual(Literal[1, 2, 3].__args__, (1, 2, 3)) + self.assertEqual(Literal[1, 2, 3, 3].__args__, (1, 2, 3)) + self.assertEqual(Literal[1, Literal[2], Literal[3, 4]].__args__, (1, 2, 3, 4)) + # Mutable arguments will not be deduplicated + self.assertEqual(Literal[[], []].__args__, ([], [])) + + def test_flatten(self): + l1 = Literal[Literal[1], Literal[2], Literal[3]] + l2 = Literal[Literal[1, 2], 3] + l3 = Literal[Literal[1, 2, 3]] + for l in l1, l2, l3: + self.assertEqual(l, Literal[1, 2, 3]) + self.assertEqual(l.__args__, (1, 2, 3)) + XK = TypeVar('XK', str, bytes) XV = TypeVar('XV') diff --git a/Lib/typing.py b/Lib/typing.py index 6fd67b038834e1..14952ec6cc6954 100644 --- a/Lib/typing.py +++ b/Lib/typing.py @@ -200,6 +200,20 @@ def _check_generic(cls, parameters, elen): f" actual {alen}, expected {elen}") +def _deduplicate(params): + # Weed out strict duplicates, preserving the first of each occurrence. + all_params = set(params) + if len(all_params) < len(params): + new_params = [] + for t in params: + if t in all_params: + new_params.append(t) + all_params.remove(t) + params = new_params + assert not all_params, all_params + return params + + def _remove_dups_flatten(parameters): """An internal helper for Union creation and substitution: flatten Unions among parameters, then remove duplicates. @@ -213,38 +227,45 @@ def _remove_dups_flatten(parameters): params.extend(p[1:]) else: params.append(p) - # Weed out strict duplicates, preserving the first of each occurrence. - all_params = set(params) - if len(all_params) < len(params): - new_params = [] - for t in params: - if t in all_params: - new_params.append(t) - all_params.remove(t) - params = new_params - assert not all_params, all_params + + return tuple(_deduplicate(params)) + + +def _flatten_literal_params(parameters): + """An internal helper for Literal creation: flatten Literals among parameters""" + params = [] + for p in parameters: + if isinstance(p, _LiteralGenericAlias): + params.extend(p.__args__) + else: + params.append(p) return tuple(params) _cleanups = [] -def _tp_cache(func): +def _tp_cache(func=None, /, *, typed=False): """Internal wrapper caching __getitem__ of generic types with a fallback to original function for non-hashable arguments. """ - cached = functools.lru_cache()(func) - _cleanups.append(cached.cache_clear) + def decorator(func): + cached = functools.lru_cache(typed=typed)(func) + _cleanups.append(cached.cache_clear) - @functools.wraps(func) - def inner(*args, **kwds): - try: - return cached(*args, **kwds) - except TypeError: - pass # All real errors (not unhashable args) are raised below. - return func(*args, **kwds) - return inner + @functools.wraps(func) + def inner(*args, **kwds): + try: + return cached(*args, **kwds) + except TypeError: + pass # All real errors (not unhashable args) are raised below. + return func(*args, **kwds) + return inner + + if func is not None: + return decorator(func) + return decorator def _eval_type(t, globalns, localns, recursive_guard=frozenset()): """Evaluate all forward references in the given type t. @@ -317,6 +338,13 @@ def __subclasscheck__(self, cls): def __getitem__(self, parameters): return self._getitem(self, parameters) + +class _LiteralSpecialForm(_SpecialForm, _root=True): + @_tp_cache(typed=True) + def __getitem__(self, parameters): + return self._getitem(self, parameters) + + @_SpecialForm def Any(self, parameters): """Special type indicating an unconstrained type. @@ -434,7 +462,7 @@ def Optional(self, parameters): arg = _type_check(parameters, f"{self} requires a single type.") return Union[arg, type(None)] -@_SpecialForm +@_LiteralSpecialForm def Literal(self, parameters): """Special typing form to define literal types (a.k.a. value types). @@ -458,7 +486,17 @@ def open_helper(file: str, mode: MODE) -> str: """ # There is no '_type_check' call because arguments to Literal[...] are # values, not types. - return _GenericAlias(self, parameters) + if not isinstance(parameters, tuple): + parameters = (parameters,) + + parameters = _flatten_literal_params(parameters) + + try: + parameters = tuple(p for p, _ in _deduplicate(list(_value_and_type_iter(parameters)))) + except TypeError: # unhashable parameters + pass + + return _LiteralGenericAlias(self, parameters) class ForwardRef(_Final, _root=True): @@ -881,6 +919,22 @@ def __repr__(self): return super().__repr__() +def _value_and_type_iter(parameters): + return ((p, type(p)) for p in parameters) + + +class _LiteralGenericAlias(_GenericAlias, _root=True): + + def __eq__(self, other): + if not isinstance(other, _LiteralGenericAlias): + return NotImplemented + + return set(_value_and_type_iter(self.__args__)) == set(_value_and_type_iter(other.__args__)) + + def __hash__(self): + return hash(tuple(_value_and_type_iter(self.__args__))) + + class Generic: """Abstract base class for generic types. diff --git a/Misc/ACKS b/Misc/ACKS index 9ad9dffe22aea4..12a5ac1410a770 100644 --- a/Misc/ACKS +++ b/Misc/ACKS @@ -855,6 +855,7 @@ Jan Kanis Rafe Kaplan Jacob Kaplan-Moss Allison Kaptur +Yurii Karabas Janne Karila Per Øyvind Karlsen Anton Kasyanov diff --git a/Misc/NEWS.d/next/Library/2020-11-15-15-23-34.bpo-42345.hiIR7x.rst b/Misc/NEWS.d/next/Library/2020-11-15-15-23-34.bpo-42345.hiIR7x.rst new file mode 100644 index 00000000000000..6339182c3ae727 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2020-11-15-15-23-34.bpo-42345.hiIR7x.rst @@ -0,0 +1,2 @@ +Fix various issues with ``typing.Literal`` parameter handling (flatten, +deduplicate, use type to cache key). Patch provided by Yurii Karabas. From 05a5d697f4f097f37c5c1e2ed0e2338a33c3fb6a Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Tue, 17 Nov 2020 18:58:12 +0100 Subject: [PATCH 0704/1314] bpo-41686: Always create the SIGINT event on Windows (GH-23344) (GH-23347) bpo-41686, bpo-41713: On Windows, the SIGINT event, _PyOS_SigintEvent(), is now created even if Python is configured to not install signal handlers (PyConfig.install_signal_handlers=0 or Py_InitializeEx(0)). --- Include/internal/pycore_pylifecycle.h | 1 + .../2020-11-17-16-25-50.bpo-41686.hX77kL.rst | 4 ++ Modules/signalmodule.c | 52 +++++++++++++++++-- Python/pylifecycle.c | 27 +--------- 4 files changed, 54 insertions(+), 30 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2020-11-17-16-25-50.bpo-41686.hX77kL.rst diff --git a/Include/internal/pycore_pylifecycle.h b/Include/internal/pycore_pylifecycle.h index b76bb2c7778aec..50ab645fc74859 100644 --- a/Include/internal/pycore_pylifecycle.h +++ b/Include/internal/pycore_pylifecycle.h @@ -68,6 +68,7 @@ extern void _PyFloat_Fini(void); extern void _PySlice_Fini(void); extern void _PyAsyncGen_Fini(void); +extern int _PySignal_Init(int install_signal_handlers); extern void PyOS_FiniInterrupts(void); extern void _PyExc_Fini(void); diff --git a/Misc/NEWS.d/next/Core and Builtins/2020-11-17-16-25-50.bpo-41686.hX77kL.rst b/Misc/NEWS.d/next/Core and Builtins/2020-11-17-16-25-50.bpo-41686.hX77kL.rst new file mode 100644 index 00000000000000..0265d48660a3c6 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2020-11-17-16-25-50.bpo-41686.hX77kL.rst @@ -0,0 +1,4 @@ +On Windows, the ``SIGINT`` event, ``_PyOS_SigintEvent()``, is now created +even if Python is configured to not install signal handlers (if +:c:member:`PyConfig.install_signal_handlers` equals to 0, or +``Py_InitializeEx(0)``). diff --git a/Modules/signalmodule.c b/Modules/signalmodule.c index 9041848cadf07d..540e2d90448044 100644 --- a/Modules/signalmodule.c +++ b/Modules/signalmodule.c @@ -1632,11 +1632,6 @@ PyInit__signal(void) goto finally; #endif -#ifdef MS_WINDOWS - /* Create manual-reset event, initially unset */ - sigint_event = CreateEvent(NULL, TRUE, FALSE, FALSE); -#endif - if (PyErr_Occurred()) { Py_DECREF(m); m = NULL; @@ -1773,6 +1768,53 @@ PyOS_InitInterrupts(void) } } + +static int +signal_install_handlers(void) +{ +#ifdef SIGPIPE + PyOS_setsig(SIGPIPE, SIG_IGN); +#endif +#ifdef SIGXFZ + PyOS_setsig(SIGXFZ, SIG_IGN); +#endif +#ifdef SIGXFSZ + PyOS_setsig(SIGXFSZ, SIG_IGN); +#endif + + // Import _signal to install the Python SIGINT handler + PyObject *module = PyImport_ImportModule("_signal"); + if (!module) { + return -1; + } + Py_DECREF(module); + + return 0; +} + + +int +_PySignal_Init(int install_signal_handlers) +{ +#ifdef MS_WINDOWS + /* Create manual-reset event, initially unset */ + sigint_event = CreateEvent(NULL, TRUE, FALSE, FALSE); + if (sigint_event == NULL) { + PyErr_SetFromWindowsErr(0); + return -1; + } +#endif + + if (install_signal_handlers) { + if (signal_install_handlers() < 0) { + return -1; + } + } + + return 0; +} + + void PyOS_FiniInterrupts(void) { diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index cfb3a7d941710f..5c50d4d290f4db 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -57,7 +57,6 @@ static PyStatus add_main_module(PyInterpreterState *interp); static PyStatus init_import_site(void); static PyStatus init_set_builtins_open(void); static PyStatus init_sys_streams(PyThreadState *tstate); -static PyStatus init_signals(PyThreadState *tstate); static void call_py_exitfuncs(PyThreadState *tstate); static void wait_for_thread_shutdown(PyThreadState *tstate); static void call_ll_exitfuncs(_PyRuntimeState *runtime); @@ -1013,11 +1012,8 @@ init_interp_main(PyThreadState *tstate) } if (is_main_interp) { - if (config->install_signal_handlers) { - status = init_signals(tstate); - if (_PyStatus_EXCEPTION(status)) { - return status; - } + if (_PySignal_Init(config->install_signal_handlers) < 0) { + return _PyStatus_ERR("can't initialize signals"); } if (_PyTraceMalloc_Init(config->tracemalloc) < 0) { @@ -2442,25 +2438,6 @@ Py_Exit(int sts) exit(sts); } -static PyStatus -init_signals(PyThreadState *tstate) -{ -#ifdef SIGPIPE - PyOS_setsig(SIGPIPE, SIG_IGN); -#endif -#ifdef SIGXFZ - PyOS_setsig(SIGXFZ, SIG_IGN); -#endif -#ifdef SIGXFSZ - PyOS_setsig(SIGXFSZ, SIG_IGN); -#endif - PyOS_InitInterrupts(); /* May imply init_signals() */ - if (_PyErr_Occurred(tstate)) { - return _PyStatus_ERR("can't import signal"); - } - return _PyStatus_OK(); -} - /* Restore signals that the interpreter has called SIG_IGN on to SIG_DFL. * From 48a9c0eb2a3304ea64d1b32fdf9db853d5d8c429 Mon Sep 17 00:00:00 2001 From: Irit Katriel Date: Tue, 17 Nov 2020 19:31:55 +0000 Subject: [PATCH 0705/1314] [3.9] bpo-39934: Account for control blocks in 'except' in compiler. (GH-22395) (GH-23303) * bpo-39934: backport PR 22395 to 3.9 --- Lib/test/test_syntax.py | 9 +++++++++ .../2020-09-24-12-15-45.bpo-39934.YVHTCF.rst | 3 +++ Python/compile.c | 19 +++++++++++-------- 3 files changed, 23 insertions(+), 8 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2020-09-24-12-15-45.bpo-39934.YVHTCF.rst diff --git a/Lib/test/test_syntax.py b/Lib/test/test_syntax.py index 1336231fbbfbfa..f0c9c988e24417 100644 --- a/Lib/test/test_syntax.py +++ b/Lib/test/test_syntax.py @@ -946,6 +946,15 @@ def test_empty_line_after_linecont(self): except SyntaxError: self.fail("Empty line after a line continuation character is valid.") + @support.cpython_only + def test_nested_named_except_blocks(self): + code = "" + for i in range(12): + code += f"{' '*i}try:\n" + code += f"{' '*(i+1)}raise Exception\n" + code += f"{' '*i}except Exception as e:\n" + code += f"{' '*4*12}pass" + self._check_error(code, "too many statically nested blocks") def test_barry_as_flufl_with_syntax_errors(self): # The "barry_as_flufl" rule can produce some "bugs-at-a-distance" if diff --git a/Misc/NEWS.d/next/Core and Builtins/2020-09-24-12-15-45.bpo-39934.YVHTCF.rst b/Misc/NEWS.d/next/Core and Builtins/2020-09-24-12-15-45.bpo-39934.YVHTCF.rst new file mode 100644 index 00000000000000..92cd1ba234d215 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2020-09-24-12-15-45.bpo-39934.YVHTCF.rst @@ -0,0 +1,3 @@ +Correctly count control blocks in 'except' in compiler. Ensures that a +syntax error, rather a fatal error, occurs for deeply nested, named +exception handlers. diff --git a/Python/compile.c b/Python/compile.c index 51af28b54ffb1f..722d52dbcefb1a 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -84,8 +84,8 @@ It's called a frame block to distinguish it from a basic block in the compiler IR. */ -enum fblocktype { WHILE_LOOP, FOR_LOOP, EXCEPT, FINALLY_TRY, FINALLY_END, - WITH, ASYNC_WITH, HANDLER_CLEANUP, POP_VALUE }; +enum fblocktype { WHILE_LOOP, FOR_LOOP, TRY_EXCEPT, FINALLY_TRY, FINALLY_END, + WITH, ASYNC_WITH, HANDLER_CLEANUP, POP_VALUE, EXCEPTION_HANDLER }; struct fblockinfo { enum fblocktype fb_type; @@ -1624,9 +1624,7 @@ compiler_push_fblock(struct compiler *c, enum fblocktype t, basicblock *b, { struct fblockinfo *f; if (c->u->u_nfblocks >= CO_MAXBLOCKS) { - PyErr_SetString(PyExc_SyntaxError, - "too many statically nested blocks"); - return 0; + return compiler_error(c, "too many statically nested blocks"); } f = &c->u->u_fblock[c->u->u_nfblocks++]; f->fb_type = t; @@ -1666,6 +1664,7 @@ compiler_unwind_fblock(struct compiler *c, struct fblockinfo *info, { switch (info->fb_type) { case WHILE_LOOP: + case EXCEPTION_HANDLER: return 1; case FOR_LOOP: @@ -1676,7 +1675,7 @@ compiler_unwind_fblock(struct compiler *c, struct fblockinfo *info, ADDOP(c, POP_TOP); return 1; - case EXCEPT: + case TRY_EXCEPT: ADDOP(c, POP_BLOCK); return 1; @@ -3064,14 +3063,17 @@ compiler_try_except(struct compiler *c, stmt_ty s) return 0; ADDOP_JREL(c, SETUP_FINALLY, except); compiler_use_next_block(c, body); - if (!compiler_push_fblock(c, EXCEPT, body, NULL, NULL)) + if (!compiler_push_fblock(c, TRY_EXCEPT, body, NULL, NULL)) return 0; VISIT_SEQ(c, stmt, s->v.Try.body); ADDOP(c, POP_BLOCK); - compiler_pop_fblock(c, EXCEPT, body); + compiler_pop_fblock(c, TRY_EXCEPT, body); ADDOP_JREL(c, JUMP_FORWARD, orelse); n = asdl_seq_LEN(s->v.Try.handlers); compiler_use_next_block(c, except); + /* Runtime will push a block here, so we need to account for that */ + if (!compiler_push_fblock(c, EXCEPTION_HANDLER, NULL, NULL, NULL)) + return 0; for (i = 0; i < n; i++) { excepthandler_ty handler = (excepthandler_ty)asdl_seq_GET( s->v.Try.handlers, i); @@ -3156,6 +3158,7 @@ compiler_try_except(struct compiler *c, stmt_ty s) } compiler_use_next_block(c, except); } + compiler_pop_fblock(c, EXCEPTION_HANDLER, NULL); ADDOP(c, RERAISE); compiler_use_next_block(c, orelse); VISIT_SEQ(c, stmt, s->v.Try.orelse); From 71ba5f52d2a80e7beffc923c54c0b6345cd0637a Mon Sep 17 00:00:00 2001 From: kj <28750310+Fidget-Spinner@users.noreply.github.com> Date: Wed, 18 Nov 2020 05:45:08 +0700 Subject: [PATCH 0706/1314] [3.9] bpo-42332: Add weakref slot to types.GenericAlias (GH-23250) (GH-23309) (cherry picked from commit 384b7a4bd988986bca227c7e85c32d766da74708) --- Lib/test/test_genericalias.py | 90 +++++++++++-------- .../2020-11-12-23-16-14.bpo-42332.fEQIdk.rst | 1 + Objects/genericaliasobject.c | 6 ++ 3 files changed, 59 insertions(+), 38 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2020-11-12-23-16-14.bpo-42332.fEQIdk.rst diff --git a/Lib/test/test_genericalias.py b/Lib/test/test_genericalias.py index 240aad02518ff6..912fb33af1a21b 100644 --- a/Lib/test/test_genericalias.py +++ b/Lib/test/test_genericalias.py @@ -13,7 +13,10 @@ from dataclasses import Field from functools import partial, partialmethod, cached_property from mailbox import Mailbox, _PartialFile -from ctypes import Array, LibraryLoader +try: + import ctypes +except ImportError: + ctypes = None from difflib import SequenceMatcher from filecmp import dircmp from fileinput import FileInput @@ -44,45 +47,46 @@ class BaseTest(unittest.TestCase): """Test basics.""" + generic_types = [type, tuple, list, dict, set, frozenset, enumerate, + defaultdict, deque, + SequenceMatcher, + dircmp, + FileInput, + OrderedDict, Counter, UserDict, UserList, + Pattern, Match, + partial, partialmethod, cached_property, + AbstractContextManager, AbstractAsyncContextManager, + Awaitable, Coroutine, + AsyncIterable, AsyncIterator, + AsyncGenerator, Generator, + Iterable, Iterator, + Reversible, + Container, Collection, + Callable, + Mailbox, _PartialFile, + ContextVar, Token, + Field, + Set, MutableSet, + Mapping, MutableMapping, MappingView, + KeysView, ItemsView, ValuesView, + Sequence, MutableSequence, + MappingProxyType, AsyncGeneratorType, + DirEntry, + chain, + TemporaryDirectory, SpooledTemporaryFile, + Queue, SimpleQueue, + _AssertRaisesContext, + SplitResult, ParseResult, + ValueProxy, ApplyResult, + WeakSet, ReferenceType, ref, + ShareableList, MPSimpleQueue, + Future, _WorkItem, + Morsel] + if ctypes is not None: + generic_types.extend((ctypes.Array, ctypes.LibraryLoader)) def test_subscriptable(self): - for t in (type, tuple, list, dict, set, frozenset, enumerate, - defaultdict, deque, - SequenceMatcher, - dircmp, - FileInput, - OrderedDict, Counter, UserDict, UserList, - Pattern, Match, - partial, partialmethod, cached_property, - AbstractContextManager, AbstractAsyncContextManager, - Awaitable, Coroutine, - AsyncIterable, AsyncIterator, - AsyncGenerator, Generator, - Iterable, Iterator, - Reversible, - Container, Collection, - Callable, - Mailbox, _PartialFile, - ContextVar, Token, - Field, - Set, MutableSet, - Mapping, MutableMapping, MappingView, - KeysView, ItemsView, ValuesView, - Sequence, MutableSequence, - MappingProxyType, AsyncGeneratorType, - DirEntry, - chain, - TemporaryDirectory, SpooledTemporaryFile, - Queue, SimpleQueue, - _AssertRaisesContext, - Array, LibraryLoader, - SplitResult, ParseResult, - ValueProxy, ApplyResult, - WeakSet, ReferenceType, ref, - ShareableList, MPSimpleQueue, - Future, _WorkItem, - Morsel, - ): + for t in self.generic_types: if t is None: continue tname = t.__name__ @@ -289,5 +293,15 @@ def test_dir(self): for generic_alias_property in ("__origin__", "__args__", "__parameters__"): self.assertIn(generic_alias_property, dir_of_gen_alias) + def test_weakref(self): + for t in self.generic_types: + if t is None: + continue + tname = t.__name__ + with self.subTest(f"Testing {tname}"): + alias = t[int] + self.assertEqual(ref(alias)(), alias) + + if __name__ == "__main__": unittest.main() diff --git a/Misc/NEWS.d/next/Core and Builtins/2020-11-12-23-16-14.bpo-42332.fEQIdk.rst b/Misc/NEWS.d/next/Core and Builtins/2020-11-12-23-16-14.bpo-42332.fEQIdk.rst new file mode 100644 index 00000000000000..8a2cb87cc0bd29 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2020-11-12-23-16-14.bpo-42332.fEQIdk.rst @@ -0,0 +1 @@ +:class:`types.GenericAlias` objects can now be the targets of weakrefs. diff --git a/Objects/genericaliasobject.c b/Objects/genericaliasobject.c index 3e850b51092cc7..4b6c8c6ed8d1fa 100644 --- a/Objects/genericaliasobject.c +++ b/Objects/genericaliasobject.c @@ -9,6 +9,7 @@ typedef struct { PyObject *origin; PyObject *args; PyObject *parameters; + PyObject* weakreflist; } gaobject; static void @@ -17,6 +18,9 @@ ga_dealloc(PyObject *self) gaobject *alias = (gaobject *)self; _PyObject_GC_UNTRACK(self); + if (alias->weakreflist != NULL) { + PyObject_ClearWeakRefs((PyObject *)alias); + } Py_XDECREF(alias->origin); Py_XDECREF(alias->args); Py_XDECREF(alias->parameters); @@ -593,6 +597,7 @@ PyTypeObject Py_GenericAliasType = { .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, .tp_traverse = ga_traverse, .tp_richcompare = ga_richcompare, + .tp_weaklistoffset = offsetof(gaobject, weakreflist), .tp_methods = ga_methods, .tp_members = ga_members, .tp_alloc = PyType_GenericAlloc, @@ -624,6 +629,7 @@ Py_GenericAlias(PyObject *origin, PyObject *args) alias->origin = origin; alias->args = args; alias->parameters = NULL; + alias->weakreflist = NULL; _PyObject_GC_TRACK(alias); return (PyObject *)alias; } From 802ff7c0d339376a1b974e57d2caca898310de3d Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 18 Nov 2020 04:42:38 -0800 Subject: [PATCH 0707/1314] [3.9] bpo-41561: skip test_min_max_version_mismatch (GH-22308) (GH-23363) skip test_min_max_version_mismatch when TLS 1.0 is not available Signed-off-by: Christian Heimes (cherry picked from commit ce04e7105bc396c32667a22b928a712ba0778a3f) Co-authored-by: Christian Heimes Automerge-Triggered-By: GH:tiran --- Lib/test/test_ssl.py | 1 + Misc/NEWS.d/next/Tests/2020-09-18-16-14-03.bpo-41561.uPnwrW.rst | 1 + 2 files changed, 2 insertions(+) create mode 100644 Misc/NEWS.d/next/Tests/2020-09-18-16-14-03.bpo-41561.uPnwrW.rst diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py index 5d496c6687614b..27cb884e072e05 100644 --- a/Lib/test/test_ssl.py +++ b/Lib/test/test_ssl.py @@ -3831,6 +3831,7 @@ def test_min_max_version_tlsv1_1(self): @requires_minimum_version @requires_tls_version('TLSv1_2') + @requires_tls_version('TLSv1') def test_min_max_version_mismatch(self): client_context, server_context, hostname = testing_context() # client 1.0, server 1.2 (mismatch) diff --git a/Misc/NEWS.d/next/Tests/2020-09-18-16-14-03.bpo-41561.uPnwrW.rst b/Misc/NEWS.d/next/Tests/2020-09-18-16-14-03.bpo-41561.uPnwrW.rst new file mode 100644 index 00000000000000..10bce825961c3c --- /dev/null +++ b/Misc/NEWS.d/next/Tests/2020-09-18-16-14-03.bpo-41561.uPnwrW.rst @@ -0,0 +1 @@ +test_ssl: skip test_min_max_version_mismatch when TLS 1.0 is not available From 994c68f586441cee755508e9357e6e03e2b7a887 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 18 Nov 2020 08:01:48 -0800 Subject: [PATCH 0708/1314] bpo-40998: Address compiler warnings found by ubsan (GH-20929) Signed-off-by: Christian Heimes Automerge-Triggered-By: GH:tiran (cherry picked from commit 07f2adedf0940b06d136208ec386d69b7d2d5b43) Co-authored-by: Christian Heimes --- .../next/Build/2020-06-17-09-05-02.bpo-40998.sgqmg9.rst | 2 ++ Objects/unicodeobject.c | 6 +++++- Parser/pegen/parse_string.c | 3 +++ Python/pylifecycle.c | 7 +++---- 4 files changed, 13 insertions(+), 5 deletions(-) create mode 100644 Misc/NEWS.d/next/Build/2020-06-17-09-05-02.bpo-40998.sgqmg9.rst diff --git a/Misc/NEWS.d/next/Build/2020-06-17-09-05-02.bpo-40998.sgqmg9.rst b/Misc/NEWS.d/next/Build/2020-06-17-09-05-02.bpo-40998.sgqmg9.rst new file mode 100644 index 00000000000000..c268e4fd0d9cbf --- /dev/null +++ b/Misc/NEWS.d/next/Build/2020-06-17-09-05-02.bpo-40998.sgqmg9.rst @@ -0,0 +1,2 @@ +Addressed three compiler warnings found by undefined behavior sanitizer +(ubsan). diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c index ea359039528b60..ffd13f7dd3892a 100644 --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -847,7 +847,11 @@ xmlcharrefreplace(_PyBytesWriter *writer, char *str, /* generate replacement */ for (i = collstart; i < collend; ++i) { - str += sprintf(str, "&#%d;", PyUnicode_READ(kind, data, i)); + size = sprintf(str, "&#%d;", PyUnicode_READ(kind, data, i)); + if (size < 0) { + return NULL; + } + str += size; } return str; } diff --git a/Parser/pegen/parse_string.c b/Parser/pegen/parse_string.c index 7b02bdde645e80..fb0c4aff9d3d00 100644 --- a/Parser/pegen/parse_string.c +++ b/Parser/pegen/parse_string.c @@ -74,6 +74,9 @@ decode_unicode_with_escapes(Parser *parser, const char *s, size_t len, Token *t) return NULL; } p = buf = PyBytes_AsString(u); + if (p == NULL) { + return NULL; + } end = s + len; while (s < end) { if (*s == '\\') { diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index 5c50d4d290f4db..60f091cbbea145 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -1353,7 +1353,6 @@ Py_FinalizeEx(void) /* Get current thread state and interpreter pointer */ PyThreadState *tstate = _PyRuntimeState_GetThreadState(runtime); - PyInterpreterState *interp = tstate->interp; // Wrap up existing "threading"-module-created, non-daemon threads. wait_for_thread_shutdown(tstate); @@ -1376,13 +1375,13 @@ Py_FinalizeEx(void) /* Copy the core config, PyInterpreterState_Delete() free the core config memory */ #ifdef Py_REF_DEBUG - int show_ref_count = interp->config.show_ref_count; + int show_ref_count = tstate->interp->config.show_ref_count; #endif #ifdef Py_TRACE_REFS - int dump_refs = interp->config.dump_refs; + int dump_refs = tstate->interp->config.dump_refs; #endif #ifdef WITH_PYMALLOC - int malloc_stats = interp->config.malloc_stats; + int malloc_stats = tstate->interp->config.malloc_stats; #endif /* Remaining daemon threads will automatically exit From c53c3f400050a7edc92ccb7285a6d7eeb4c37fd2 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Wed, 18 Nov 2020 17:11:09 +0100 Subject: [PATCH 0709/1314] bpo-42398: Fix "make regen-all" race condition (GH-23362) (GH-23367) Fix a race condition in "make regen-all" when make -jN option is used to run jobs in parallel. The clinic.py script now only use atomic write to write files. Moveover, generated files are now left unchanged if the content does not change, to not change the file modification time. The "make regen-all" command runs "make clinic" and "make regen-importlib" targets: * "make regen-importlib" builds object files (ex: Modules/_weakref.o) from source files (ex: Modules/_weakref.c) and clinic files (ex: Modules/clinic/_weakref.c.h) * "make clinic" always rewrites all clinic files (ex: Modules/clinic/_weakref.c.h) Since there is no dependency between "clinic" and "regen-importlib" Makefile targets, these two targets can be run in parallel. Moreover, half of clinic.py file writes are not atomic and so there is a race condition when "make regen-all" runs jobs in parallel using make -jN option (which can be passed in MAKEFLAGS environment variable). Fix clinic.py to make all file writes atomic: * Add write_file() function to ensure that all file writes are atomic: write into a temporary file and then use os.replace(). * Moreover, write_file() doesn't recreate or modify the file if the content does not change to avoid modifying the file modification file. * Update test_clinic to verify these assertions with a functional test. * Remove Clinic.force attribute which was no longer used, whereas Clinic.verify remains useful. (cherry picked from commit 8fba9523cf08029dc2e280d9f48fdd57ab178c9d) --- Lib/test/test_clinic.py | 26 ++++++--- .../2020-11-18-11-58-44.bpo-42398.Yt5wO8.rst | 4 ++ Tools/clinic/clinic.py | 54 ++++++++++++------- 3 files changed, 58 insertions(+), 26 deletions(-) create mode 100644 Misc/NEWS.d/next/Build/2020-11-18-11-58-44.bpo-42398.Yt5wO8.rst diff --git a/Lib/test/test_clinic.py b/Lib/test/test_clinic.py index 3d5dc4759d5018..9989b148afbd75 100644 --- a/Lib/test/test_clinic.py +++ b/Lib/test/test_clinic.py @@ -794,17 +794,29 @@ class ClinicExternalTest(TestCase): maxDiff = None def test_external(self): + # bpo-42398: Test that the destination file is left unchanged if the + # content does not change. Moreover, check also that the file + # modification time does not change in this case. source = support.findfile('clinic.test') with open(source, 'r', encoding='utf-8') as f: - original = f.read() - with support.temp_dir() as testdir: - testfile = os.path.join(testdir, 'clinic.test.c') + orig_contents = f.read() + + with support.temp_dir() as tmp_dir: + testfile = os.path.join(tmp_dir, 'clinic.test.c') with open(testfile, 'w', encoding='utf-8') as f: - f.write(original) - clinic.parse_file(testfile, force=True) + f.write(orig_contents) + old_mtime_ns = os.stat(testfile).st_mtime_ns + + clinic.parse_file(testfile) + with open(testfile, 'r', encoding='utf-8') as f: - result = f.read() - self.assertEqual(result, original) + new_contents = f.read() + new_mtime_ns = os.stat(testfile).st_mtime_ns + + self.assertEqual(new_contents, orig_contents) + # Don't change the file modification time + # if the content does not change + self.assertEqual(new_mtime_ns, old_mtime_ns) if __name__ == "__main__": diff --git a/Misc/NEWS.d/next/Build/2020-11-18-11-58-44.bpo-42398.Yt5wO8.rst b/Misc/NEWS.d/next/Build/2020-11-18-11-58-44.bpo-42398.Yt5wO8.rst new file mode 100644 index 00000000000000..9ab99d0e69dd1d --- /dev/null +++ b/Misc/NEWS.d/next/Build/2020-11-18-11-58-44.bpo-42398.Yt5wO8.rst @@ -0,0 +1,4 @@ +Fix a race condition in "make regen-all" when make -jN option is used to run +jobs in parallel. The clinic.py script now only use atomic write to write +files. Moveover, generated files are now left unchanged if the content does not +change, to not change the file modification time. diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py index b07ffdd928f154..34b58079281b6f 100755 --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -1777,6 +1777,30 @@ def dump(self): # The callable should not call builtins.print. return_converters = {} + +def write_file(filename, new_contents): + try: + with open(filename, 'r', encoding="utf-8") as fp: + old_contents = fp.read() + + if old_contents == new_contents: + # no change: avoid modifying the file modification time + return + except FileNotFoundError: + pass + + # Atomic write using a temporary file and os.replace() + filename_new = f"{filename}.new" + with open(filename_new, "w", encoding="utf-8") as fp: + fp.write(new_contents) + + try: + os.replace(filename_new, filename) + except: + os.unlink(filename_new) + raise + + clinic = None class Clinic: @@ -1823,7 +1847,7 @@ class Clinic: """ - def __init__(self, language, printer=None, *, force=False, verify=True, filename=None): + def __init__(self, language, printer=None, *, verify=True, filename=None): # maps strings to Parser objects. # (instantiated from the "parsers" global.) self.parsers = {} @@ -1832,7 +1856,6 @@ def __init__(self, language, printer=None, *, force=False, verify=True, filename fail("Custom printers are broken right now") self.printer = printer or BlockPrinter(language) self.verify = verify - self.force = force self.filename = filename self.modules = collections.OrderedDict() self.classes = collections.OrderedDict() @@ -1965,8 +1988,7 @@ def parse(self, input): block.input = 'preserve\n' printer_2 = BlockPrinter(self.language) printer_2.print_block(block) - with open(destination.filename, "wt") as f: - f.write(printer_2.f.getvalue()) + write_file(destination.filename, printer_2.f.getvalue()) continue text = printer.f.getvalue() @@ -2018,7 +2040,10 @@ def _module_and_class(self, fields): return module, cls -def parse_file(filename, *, force=False, verify=True, output=None, encoding='utf-8'): +def parse_file(filename, *, verify=True, output=None): + if not output: + output = filename + extension = os.path.splitext(filename)[1][1:] if not extension: fail("Can't extract file type for file " + repr(filename)) @@ -2028,7 +2053,7 @@ def parse_file(filename, *, force=False, verify=True, output=None, encoding='utf except KeyError: fail("Can't identify file type for file " + repr(filename)) - with open(filename, 'r', encoding=encoding) as f: + with open(filename, 'r', encoding="utf-8") as f: raw = f.read() # exit quickly if there are no clinic markers in the file @@ -2036,19 +2061,10 @@ def parse_file(filename, *, force=False, verify=True, output=None, encoding='utf if not find_start_re.search(raw): return - clinic = Clinic(language, force=force, verify=verify, filename=filename) + clinic = Clinic(language, verify=verify, filename=filename) cooked = clinic.parse(raw) - if (cooked == raw) and not force: - return - - directory = os.path.dirname(filename) or '.' - with tempfile.TemporaryDirectory(prefix="clinic", dir=directory) as tmpdir: - bytes = cooked.encode(encoding) - tmpfilename = os.path.join(tmpdir, os.path.basename(filename)) - with open(tmpfilename, "wb") as f: - f.write(bytes) - os.replace(tmpfilename, output or filename) + write_file(output, cooked) def compute_checksum(input, length=None): @@ -5087,7 +5103,7 @@ def main(argv): path = os.path.join(root, filename) if ns.verbose: print(path) - parse_file(path, force=ns.force, verify=not ns.force) + parse_file(path, verify=not ns.force) return if not ns.filename: @@ -5103,7 +5119,7 @@ def main(argv): for filename in ns.filename: if ns.verbose: print(filename) - parse_file(filename, output=ns.output, force=ns.force, verify=not ns.force) + parse_file(filename, output=ns.output, verify=not ns.force) if __name__ == "__main__": From 35bf8ea7bef7151a420a67638e88d6a1fd81d1a0 Mon Sep 17 00:00:00 2001 From: Christian Heimes Date: Wed, 18 Nov 2020 18:45:29 +0100 Subject: [PATCH 0710/1314] [3.9] bpo-40998: Fix a refleak in create_filter() (GH-23365) (GH-23369) (cherry picked from commit d1e38d4023aa29e7ed64d4f8eb9c1e4a3c86a2e5) --- Python/_warnings.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Python/_warnings.c b/Python/_warnings.c index 4d65bb30c8e5cd..91a78fe72b3bc5 100644 --- a/Python/_warnings.c +++ b/Python/_warnings.c @@ -69,11 +69,14 @@ create_filter(PyObject *category, _Py_Identifier *id, const char *modname) } } else { modname_obj = Py_None; + Py_INCREF(modname_obj); } /* This assumes the line number is zero for now. */ - return PyTuple_Pack(5, action_str, Py_None, - category, modname_obj, _PyLong_Zero); + PyObject *filter = PyTuple_Pack(5, action_str, Py_None, + category, modname_obj, _PyLong_Zero); + Py_DECREF(modname_obj); + return filter; } #endif From 37f6fe2c935a57cd1bd42c773aba255d8134cb61 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 18 Nov 2020 09:45:54 -0800 Subject: [PATCH 0711/1314] bpo-42336: Improve PCbuild batch files (GH-23275) (cherry picked from commit 2156d964a12285280c533af1c96eb273c58451e6) Co-authored-by: Steve Dower --- .azure-pipelines/ci.yml | 2 +- .azure-pipelines/pr.yml | 2 +- .github/workflows/build.yml | 4 ++-- PCbuild/build.bat | 4 ++-- PCbuild/env.bat | 21 ++++++++++++++++----- PCbuild/env.ps1 | 2 ++ PCbuild/idle.bat | 18 +++++++++++++++--- PCbuild/prepare_libffi.bat | 13 ++++++------- PCbuild/rt.bat | 18 +++++++++++++++--- 9 files changed, 60 insertions(+), 24 deletions(-) create mode 100644 PCbuild/env.ps1 diff --git a/.azure-pipelines/ci.yml b/.azure-pipelines/ci.yml index 531ed060fd3866..3feb85ae6561de 100644 --- a/.azure-pipelines/ci.yml +++ b/.azure-pipelines/ci.yml @@ -104,7 +104,7 @@ jobs: matrix: win32: arch: win32 - buildOpt: + buildOpt: '-p Win32' testRunTitle: '$(Build.SourceBranchName)-win32' testRunPlatform: win32 win64: diff --git a/.azure-pipelines/pr.yml b/.azure-pipelines/pr.yml index 1ffe0a97a2465f..2e94af35600cfc 100644 --- a/.azure-pipelines/pr.yml +++ b/.azure-pipelines/pr.yml @@ -104,7 +104,7 @@ jobs: matrix: win32: arch: win32 - buildOpt: + buildOpt: '-p Win32' testRunTitle: '$(System.PullRequest.TargetBranch)-win32' testRunPlatform: win32 win64: diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 9e63b68576303b..f66e042dac4998 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -59,7 +59,7 @@ jobs: - name: Display build info run: .\python.bat -m test.pythoninfo - name: Tests - run: .\PCbuild\rt.bat -q -uall -u-cpu -rwW --slowest --timeout=1200 -j0 + run: .\PCbuild\rt.bat -p Win32 -q -uall -u-cpu -rwW --slowest --timeout=1200 -j0 build_win_amd64: name: 'Windows (x64)' @@ -73,7 +73,7 @@ jobs: - name: Display build info run: .\python.bat -m test.pythoninfo - name: Tests - run: .\PCbuild\rt.bat -x64 -q -uall -u-cpu -rwW --slowest --timeout=1200 -j0 + run: .\PCbuild\rt.bat -p x64 -q -uall -u-cpu -rwW --slowest --timeout=1200 -j0 build_macos: name: 'macOS' diff --git a/PCbuild/build.bat b/PCbuild/build.bat index ba7154d8cb1e56..5a41ca57b12391 100644 --- a/PCbuild/build.bat +++ b/PCbuild/build.bat @@ -46,7 +46,7 @@ echo.Available arguments: echo. -c Release ^| Debug ^| PGInstrument ^| PGUpdate echo. Set the configuration (default: Release) echo. -p x64 ^| Win32 ^| ARM ^| ARM64 -echo. Set the platform (default: Win32) +echo. Set the platform (default: x64) echo. -t Build ^| Rebuild ^| Clean ^| CleanAll echo. Set the target manually echo. --pgo-job The job to use for PGO training; implies --pgo @@ -55,7 +55,7 @@ exit /b 127 :Run setlocal -set platf=Win32 +set platf=x64 set conf=Release set target=Build set dir=%~dp0 diff --git a/PCbuild/env.bat b/PCbuild/env.bat index 9d4c9d1c32f7a4..2820e304582cff 100644 --- a/PCbuild/env.bat +++ b/PCbuild/env.bat @@ -9,8 +9,19 @@ rem 'v110', 'v120' or 'v140') to the build script. echo Build environments: x86, amd64, x86_amd64 echo. -set VSTOOLS=%VS140COMNTOOLS% -if "%VSTOOLS%"=="" set VSTOOLS=%VS120COMNTOOLS% -if "%VSTOOLS%"=="" set VSTOOLS=%VS110COMNTOOLS% -if "%VSTOOLS%"=="" set VSTOOLS=%VS100COMNTOOLS% -call "%VSTOOLS%..\..\VC\vcvarsall.bat" %* +set _ARGS=%* +if NOT DEFINED _ARGS set _ARGS=amd64 + +if not exist "%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe" goto :skip_vswhere +set VSTOOLS= +for /F "tokens=*" %%i in ('"%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe" -property installationPath -latest -prerelease -products * -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64') DO @(set VSTOOLS=%%i\VC\Auxiliary\Build\vcvarsall.bat) +if not defined VSTOOLS goto :skip_vswhere +call "%VSTOOLS%" %_ARGS% +exit /B 0 + +:skip_vswhere +if not defined VSTOOLS set VSTOOLS=%VS140COMNTOOLS% +if not defined VSTOOLS set VSTOOLS=%VS120COMNTOOLS% +if not defined VSTOOLS set VSTOOLS=%VS110COMNTOOLS% +if not defined VSTOOLS set VSTOOLS=%VS100COMNTOOLS% +call "%VSTOOLS%..\..\VC\vcvarsall.bat" %_ARGS% diff --git a/PCbuild/env.ps1 b/PCbuild/env.ps1 new file mode 100644 index 00000000000000..19d7ada4c10798 --- /dev/null +++ b/PCbuild/env.ps1 @@ -0,0 +1,2 @@ +$pcbuild = $script:MyInvocation.MyCommand.Path | Split-Path -parent; +& cmd /K "$pcbuild\env.bat" $args diff --git a/PCbuild/idle.bat b/PCbuild/idle.bat index 1978b99f6ee19d..70f3817f09769c 100644 --- a/PCbuild/idle.bat +++ b/PCbuild/idle.bat @@ -4,12 +4,24 @@ rem Usage: idle [-d] rem -d Run Debug build (python_d.exe). Else release build. setlocal -set exe=win32\python +set PCBUILD=%~dp0 +set exedir=%PCBUILD%\amd64 +set exe=python PATH %PATH%;..\externals\tcltk\bin -if "%1"=="-d" (set exe=%exe%_d) & shift +:CheckOpts +if "%1"=="-d" (set exe=%exe%_d) & shift & goto :CheckOpts +if "%1"=="-p" (call :SetExeDir %2) & shift & shift & goto :CheckOpts -set cmd=%exe% ../Lib/idlelib/idle.py %1 %2 %3 %4 %5 %6 %7 %8 %9 +set cmd=%exedir%\%exe% %PCBUILD%\..\Lib\idlelib\idle.py %1 %2 %3 %4 %5 %6 %7 %8 %9 echo on %cmd% +exit /B %LASTERRORCODE% + +:SetExeDir +if /I %1 EQU Win32 (set exedir=%PCBUILD%\win32) +if /I %1 EQU x64 (set exedir=%PCBUILD%\amd64) +if /I %1 EQU ARM (set exedir=%PCBUILD%\arm32) +if /I %1 EQU ARM64 (set exedir=%PCBUILD%\arm64) +exit /B 0 diff --git a/PCbuild/prepare_libffi.bat b/PCbuild/prepare_libffi.bat index f41ba83379af96..922a47565c8da5 100644 --- a/PCbuild/prepare_libffi.bat +++ b/PCbuild/prepare_libffi.bat @@ -22,10 +22,10 @@ echo Based on https://github.com/libffi/libffi/blob/master/.appveyor.yml echo. echo. echo.Available flags: -echo. -x64 build for x64 -echo. -x86 build for x86 -echo. -arm32 build for arm32 -echo. -arm64 build for arm64 +echo. -x64 enable x64 build +echo. -x86 enable x86 build +echo. -arm32 enable arm32 build +echo. -arm64 enable arm64 build echo. -? this help echo. --install-cygwin install cygwin to c:\cygwin exit /b 127 @@ -44,6 +44,7 @@ set INSTALL_CYGWIN= if "%1"=="" goto :CheckOptsDone if /I "%1"=="-x64" (set BUILD_X64=1) & shift & goto :CheckOpts if /I "%1"=="-x86" (set BUILD_X86=1) & shift & goto :CheckOpts +if /I "%1"=="-win32" (set BUILD_X86=1) & shift & goto :CheckOpts if /I "%1"=="-arm32" (set BUILD_ARM32=1) & shift & goto :CheckOpts if /I "%1"=="-arm64" (set BUILD_ARM64=1) & shift & goto :CheckOpts if /I "%1"=="-pdb" (set BUILD_PDB=-g) & shift & goto :CheckOpts @@ -67,9 +68,7 @@ setlocal if NOT DEFINED SH if exist c:\cygwin\bin\sh.exe set SH=c:\cygwin\bin\sh.exe if NOT DEFINED VCVARSALL ( - if exist "C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" ( - set VCVARSALL="C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" - ) + for /F "tokens=*" %%i in ('"%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe" -property installationPath -latest -prerelease -products * -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64') DO @(set VCVARSALL="%%i\VC\Auxiliary\Build\vcvarsall.bat") ) if ^%VCVARSALL:~0,1% NEQ ^" SET VCVARSALL="%VCVARSALL%" diff --git a/PCbuild/rt.bat b/PCbuild/rt.bat index 59f757c0f5888a..29813c5a87fca7 100644 --- a/PCbuild/rt.bat +++ b/PCbuild/rt.bat @@ -6,8 +6,9 @@ rem -O Run python.exe or python_d.exe (see -d) with -O. rem -q "quick" -- normally the tests are run twice, the first time rem after deleting all the .pyc files reachable from Lib/. rem -q runs the tests just once, and without deleting .pyc files. -rem -x64 Run the 64-bit build of python (or python_d if -d was specified) -rem When omitted, uses %PREFIX% if set or the 32-bit build +rem -p or -win32, -x64, -arm32, -arm64 +rem Run the specified architecture of python (or python_d if -d +rem was specified). If omitted, uses %PREFIX% if set or 64-bit. rem All leading instances of these switches are shifted off, and rem whatever remains (up to 9 arguments) is passed to regrtest.py. rem For example, @@ -38,12 +39,14 @@ set exe= if "%1"=="-O" (set dashO=-O) & shift & goto CheckOpts if "%1"=="-q" (set qmode=yes) & shift & goto CheckOpts if "%1"=="-d" (set suffix=_d) & shift & goto CheckOpts +if "%1"=="-win32" (set prefix=%pcbuild%win32) & shift & goto CheckOpts if "%1"=="-x64" (set prefix=%pcbuild%amd64) & shift & goto CheckOpts if "%1"=="-arm64" (set prefix=%pcbuild%arm64) & shift & goto CheckOpts if "%1"=="-arm32" (set prefix=%pcbuild%arm32) & shift & goto CheckOpts +if "%1"=="-p" (call :SetPlatform %~2) & shift & shift & goto CheckOpts if NOT "%1"=="" (set regrtestargs=%regrtestargs% %1) & shift & goto CheckOpts -if not defined prefix set prefix=%pcbuild%win32 +if not defined prefix set prefix=%pcbuild%amd64 set exe=%prefix%\python%suffix%.exe set cmd="%exe%" %dashO% -u -Wd -E -bb -m test %regrtestargs% if defined qmode goto Qmode @@ -60,6 +63,15 @@ echo on echo About to run again without deleting .pyc first: pause +goto Qmode + +:SetPlatform +if /I %1 EQU Win32 (set prefix=%pcbuild%win32) & exit /B 0 +if /I %1 EQU x64 (set prefix=%pcbuild%amd64) & exit /B 0 +if /I %1 EQU ARM64 (set prefix=%pcbuild%arm64) & exit /B 0 +if /I %1 EQU ARM (set prefix=%pcbuild%arm32) & exit /B 0 +echo Invalid platform "%1" +exit /B 1 :Qmode echo on From f9fa920c30326050a7096c5cb3594465d1e75ff2 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 18 Nov 2020 14:37:37 -0800 Subject: [PATCH 0712/1314] [3.9] bpo-38320: Clarify that expectedFailure is satisfied by either failure or error of the test. (GH-22740) (GH-22783) (cherry picked from commit fa8748271a61177e9bf609921fa464cc6990478b) Co-authored-by: Irit Katriel --- Doc/library/unittest.rst | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/Doc/library/unittest.rst b/Doc/library/unittest.rst index 8a4fd25322e33f..523e0e6f6e0f35 100644 --- a/Doc/library/unittest.rst +++ b/Doc/library/unittest.rst @@ -593,8 +593,9 @@ The following decorators and exception implement test skipping and expected fail .. decorator:: expectedFailure - Mark the test as an expected failure. If the test fails it will be - considered a success. If the test passes, it will be considered a failure. + Mark the test as an expected failure or error. If the test fails or errors + it will be considered a success. If the test passes, it will be considered + a failure. .. exception:: SkipTest(reason) @@ -1946,7 +1947,7 @@ Loading and running tests A list containing 2-tuples of :class:`TestCase` instances and strings holding formatted tracebacks. Each tuple represents an expected failure - of the test case. + or error of the test case. .. attribute:: unexpectedSuccesses @@ -2072,8 +2073,8 @@ Loading and running tests .. method:: addExpectedFailure(test, err) - Called when the test case *test* fails, but was marked with the - :func:`expectedFailure` decorator. + Called when the test case *test* fails or errors, but was marked with + the :func:`expectedFailure` decorator. The default implementation appends a tuple ``(test, formatted_err)`` to the instance's :attr:`expectedFailures` attribute, where *formatted_err* From 36619e1bc49d2e5dbfc86a9f0a54f478fe4a8c2b Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 18 Nov 2020 15:23:49 -0800 Subject: [PATCH 0713/1314] [3.9] Minor grammar edits for the descriptor howto guide (GH-GH-23175) (GH-23176) (cherry picked from commit 803187796f06bdc47ae74ce3d28c443e8cc2a27f) Co-authored-by: Raymond Hettinger Automerge-Triggered-By: GH:JulienPalard From 87c87b5bd6f6a5924b485398f353308410f9d8c1 Mon Sep 17 00:00:00 2001 From: Pablo Galindo Date: Wed, 18 Nov 2020 23:44:30 +0000 Subject: [PATCH 0714/1314] [3.9] bpo-42381: Allow walrus in set literals and set comprehensions (GH-23332) (GH-23333) Currently walruses are not allowerd in set literals and set comprehensions: >>> {y := 4, 4**2, 3**3} File "", line 1 {y := 4, 4**2, 3**3} ^ SyntaxError: invalid syntax but they should be allowed as well per PEP 572. (cherry picked from commit b0aba1fcdc3da952698d99aec2334faa79a8b68c) Co-authored-by: Pablo Galindo --- Grammar/python.gram | 5 +- Lib/test/test_named_expressions.py | 60 +- .../2020-11-16-23-45-56.bpo-42381.G4AWxL.rst | 2 + Parser/pegen/parse.c | 2075 ++++++++--------- 4 files changed, 1016 insertions(+), 1126 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2020-11-16-23-45-56.bpo-42381.G4AWxL.rst diff --git a/Grammar/python.gram b/Grammar/python.gram index 257d2f5153263c..ce783971968dc5 100644 --- a/Grammar/python.gram +++ b/Grammar/python.gram @@ -301,7 +301,6 @@ block[asdl_seq*] (memo): | simple_stmt | invalid_block -expressions_list[asdl_seq*]: a=','.star_expression+ [','] { a } star_expressions[expr_ty]: | a=star_expression b=(',' c=star_expression { c })+ [','] { _Py_Tuple(CHECK(_PyPegen_seq_insert_in_front(p, a, b)), Load, EXTRA) } @@ -505,9 +504,9 @@ group[expr_ty]: genexp[expr_ty]: | '(' a=named_expression ~ b=for_if_clauses ')' { _Py_GeneratorExp(a, b, EXTRA) } | invalid_comprehension -set[expr_ty]: '{' a=expressions_list '}' { _Py_Set(a, EXTRA) } +set[expr_ty]: '{' a=star_named_expressions '}' { _Py_Set(a, EXTRA) } setcomp[expr_ty]: - | '{' a=expression ~ b=for_if_clauses '}' { _Py_SetComp(a, b, EXTRA) } + | '{' a=named_expression ~ b=for_if_clauses '}' { _Py_SetComp(a, b, EXTRA) } | invalid_comprehension dict[expr_ty]: | '{' a=[double_starred_kvpairs] '}' { diff --git a/Lib/test/test_named_expressions.py b/Lib/test/test_named_expressions.py index d614f3267fad37..2adcd4b5d64666 100644 --- a/Lib/test/test_named_expressions.py +++ b/Lib/test/test_named_expressions.py @@ -113,7 +113,7 @@ def test_named_expression_invalid_in_class_body(self): "assignment expression within a comprehension cannot be used in a class body"): exec(code, {}, {}) - def test_named_expression_invalid_rebinding_comprehension_iteration_variable(self): + def test_named_expression_invalid_rebinding_list_comprehension_iteration_variable(self): cases = [ ("Local reuse", 'i', "[i := 0 for i in range(5)]"), ("Nested reuse", 'j', "[[(j := 0) for i in range(5)] for j in range(5)]"), @@ -130,7 +130,7 @@ def test_named_expression_invalid_rebinding_comprehension_iteration_variable(sel with self.assertRaisesRegex(SyntaxError, msg): exec(code, {}, {}) - def test_named_expression_invalid_rebinding_comprehension_inner_loop(self): + def test_named_expression_invalid_rebinding_list_comprehension_inner_loop(self): cases = [ ("Inner reuse", 'j', "[i for i in range(5) if (j := 0) for j in range(5)]"), ("Inner unpacking reuse", 'j', "[i for i in range(5) if (j := 0) for j, k in [(0, 1)]]"), @@ -145,7 +145,7 @@ def test_named_expression_invalid_rebinding_comprehension_inner_loop(self): with self.assertRaisesRegex(SyntaxError, msg): exec(f"lambda: {code}", {}) # Function scope - def test_named_expression_invalid_comprehension_iterable_expression(self): + def test_named_expression_invalid_list_comprehension_iterable_expression(self): cases = [ ("Top level", "[i for i in (i := range(5))]"), ("Inside tuple", "[i for i in (2, 3, i := range(5))]"), @@ -167,6 +167,60 @@ def test_named_expression_invalid_comprehension_iterable_expression(self): with self.assertRaisesRegex(SyntaxError, msg): exec(f"lambda: {code}", {}) # Function scope + def test_named_expression_invalid_rebinding_set_comprehension_iteration_variable(self): + cases = [ + ("Local reuse", 'i', "{i := 0 for i in range(5)}"), + ("Nested reuse", 'j', "{{(j := 0) for i in range(5)} for j in range(5)}"), + ("Reuse inner loop target", 'j', "{(j := 0) for i in range(5) for j in range(5)}"), + ("Unpacking reuse", 'i', "{i := 0 for i, j in {(0, 1)}}"), + ("Reuse in loop condition", 'i', "{i+1 for i in range(5) if (i := 0)}"), + ("Unreachable reuse", 'i', "{False or (i:=0) for i in range(5)}"), + ("Unreachable nested reuse", 'i', + "{(i, j) for i in range(5) for j in range(5) if True or (i:=10)}"), + ] + for case, target, code in cases: + msg = f"assignment expression cannot rebind comprehension iteration variable '{target}'" + with self.subTest(case=case): + with self.assertRaisesRegex(SyntaxError, msg): + exec(code, {}, {}) + + def test_named_expression_invalid_rebinding_set_comprehension_inner_loop(self): + cases = [ + ("Inner reuse", 'j', "{i for i in range(5) if (j := 0) for j in range(5)}"), + ("Inner unpacking reuse", 'j', "{i for i in range(5) if (j := 0) for j, k in {(0, 1)}}"), + ] + for case, target, code in cases: + msg = f"comprehension inner loop cannot rebind assignment expression target '{target}'" + with self.subTest(case=case): + with self.assertRaisesRegex(SyntaxError, msg): + exec(code, {}) # Module scope + with self.assertRaisesRegex(SyntaxError, msg): + exec(code, {}, {}) # Class scope + with self.assertRaisesRegex(SyntaxError, msg): + exec(f"lambda: {code}", {}) # Function scope + + def test_named_expression_invalid_set_comprehension_iterable_expression(self): + cases = [ + ("Top level", "{i for i in (i := range(5))}"), + ("Inside tuple", "{i for i in (2, 3, i := range(5))}"), + ("Inside list", "{i for i in {2, 3, i := range(5)}}"), + ("Different name", "{i for i in (j := range(5))}"), + ("Lambda expression", "{i for i in (lambda:(j := range(5)))()}"), + ("Inner loop", "{i for i in range(5) for j in (i := range(5))}"), + ("Nested comprehension", "{i for i in {j for j in (k := range(5))}}"), + ("Nested comprehension condition", "{i for i in {j for j in range(5) if (j := True)}}"), + ("Nested comprehension body", "{i for i in {(j := True) for j in range(5)}}"), + ] + msg = "assignment expression cannot be used in a comprehension iterable expression" + for case, code in cases: + with self.subTest(case=case): + with self.assertRaisesRegex(SyntaxError, msg): + exec(code, {}) # Module scope + with self.assertRaisesRegex(SyntaxError, msg): + exec(code, {}, {}) # Class scope + with self.assertRaisesRegex(SyntaxError, msg): + exec(f"lambda: {code}", {}) # Function scope + class NamedExpressionAssignmentTest(unittest.TestCase): diff --git a/Misc/NEWS.d/next/Core and Builtins/2020-11-16-23-45-56.bpo-42381.G4AWxL.rst b/Misc/NEWS.d/next/Core and Builtins/2020-11-16-23-45-56.bpo-42381.G4AWxL.rst new file mode 100644 index 00000000000000..5bee5141f6cbcd --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2020-11-16-23-45-56.bpo-42381.G4AWxL.rst @@ -0,0 +1,2 @@ +Allow assignment expressions in set literals and set comprehensions as per +PEP 572. Patch by Pablo Galindo. diff --git a/Parser/pegen/parse.c b/Parser/pegen/parse.c index c78abfadd2bc91..0eb61db39a40a4 100644 --- a/Parser/pegen/parse.c +++ b/Parser/pegen/parse.c @@ -134,265 +134,262 @@ static KeywordToken *reserved_keywords[] = { #define class_def_type 1056 #define class_def_raw_type 1057 #define block_type 1058 -#define expressions_list_type 1059 -#define star_expressions_type 1060 -#define star_expression_type 1061 -#define star_named_expressions_type 1062 -#define star_named_expression_type 1063 -#define named_expression_type 1064 -#define annotated_rhs_type 1065 -#define expressions_type 1066 -#define expression_type 1067 -#define lambdef_type 1068 -#define lambda_params_type 1069 -#define lambda_parameters_type 1070 -#define lambda_slash_no_default_type 1071 -#define lambda_slash_with_default_type 1072 -#define lambda_star_etc_type 1073 -#define lambda_kwds_type 1074 -#define lambda_param_no_default_type 1075 -#define lambda_param_with_default_type 1076 -#define lambda_param_maybe_default_type 1077 -#define lambda_param_type 1078 -#define disjunction_type 1079 -#define conjunction_type 1080 -#define inversion_type 1081 -#define comparison_type 1082 -#define compare_op_bitwise_or_pair_type 1083 -#define eq_bitwise_or_type 1084 -#define noteq_bitwise_or_type 1085 -#define lte_bitwise_or_type 1086 -#define lt_bitwise_or_type 1087 -#define gte_bitwise_or_type 1088 -#define gt_bitwise_or_type 1089 -#define notin_bitwise_or_type 1090 -#define in_bitwise_or_type 1091 -#define isnot_bitwise_or_type 1092 -#define is_bitwise_or_type 1093 -#define bitwise_or_type 1094 // Left-recursive -#define bitwise_xor_type 1095 // Left-recursive -#define bitwise_and_type 1096 // Left-recursive -#define shift_expr_type 1097 // Left-recursive -#define sum_type 1098 // Left-recursive -#define term_type 1099 // Left-recursive -#define factor_type 1100 -#define power_type 1101 -#define await_primary_type 1102 -#define primary_type 1103 // Left-recursive -#define slices_type 1104 -#define slice_type 1105 -#define atom_type 1106 -#define strings_type 1107 -#define list_type 1108 -#define listcomp_type 1109 -#define tuple_type 1110 -#define group_type 1111 -#define genexp_type 1112 -#define set_type 1113 -#define setcomp_type 1114 -#define dict_type 1115 -#define dictcomp_type 1116 -#define double_starred_kvpairs_type 1117 -#define double_starred_kvpair_type 1118 -#define kvpair_type 1119 -#define for_if_clauses_type 1120 -#define for_if_clause_type 1121 -#define yield_expr_type 1122 -#define arguments_type 1123 -#define args_type 1124 -#define kwargs_type 1125 -#define starred_expression_type 1126 -#define kwarg_or_starred_type 1127 -#define kwarg_or_double_starred_type 1128 -#define star_targets_type 1129 -#define star_targets_seq_type 1130 -#define star_target_type 1131 -#define star_atom_type 1132 -#define single_target_type 1133 -#define single_subscript_attribute_target_type 1134 -#define del_targets_type 1135 -#define del_target_type 1136 -#define del_t_atom_type 1137 -#define targets_type 1138 -#define target_type 1139 -#define t_primary_type 1140 // Left-recursive -#define t_lookahead_type 1141 -#define t_atom_type 1142 -#define invalid_arguments_type 1143 -#define invalid_kwarg_type 1144 -#define invalid_named_expression_type 1145 -#define invalid_assignment_type 1146 -#define invalid_ann_assign_target_type 1147 -#define invalid_del_stmt_type 1148 -#define invalid_block_type 1149 -#define invalid_primary_type 1150 // Left-recursive -#define invalid_comprehension_type 1151 -#define invalid_dict_comprehension_type 1152 -#define invalid_parameters_type 1153 -#define invalid_lambda_parameters_type 1154 -#define invalid_star_etc_type 1155 -#define invalid_lambda_star_etc_type 1156 -#define invalid_double_type_comments_type 1157 -#define invalid_with_item_type 1158 -#define invalid_for_target_type 1159 -#define invalid_group_type 1160 -#define invalid_import_from_targets_type 1161 -#define _loop0_1_type 1162 -#define _loop0_2_type 1163 -#define _loop0_4_type 1164 -#define _gather_3_type 1165 -#define _loop0_6_type 1166 -#define _gather_5_type 1167 -#define _loop0_8_type 1168 -#define _gather_7_type 1169 -#define _loop0_10_type 1170 -#define _gather_9_type 1171 -#define _loop1_11_type 1172 -#define _loop0_13_type 1173 -#define _gather_12_type 1174 -#define _tmp_14_type 1175 -#define _tmp_15_type 1176 -#define _tmp_16_type 1177 -#define _tmp_17_type 1178 -#define _tmp_18_type 1179 -#define _tmp_19_type 1180 -#define _tmp_20_type 1181 -#define _tmp_21_type 1182 -#define _loop1_22_type 1183 -#define _tmp_23_type 1184 -#define _tmp_24_type 1185 -#define _loop0_26_type 1186 -#define _gather_25_type 1187 -#define _loop0_28_type 1188 -#define _gather_27_type 1189 -#define _tmp_29_type 1190 -#define _tmp_30_type 1191 -#define _loop0_31_type 1192 -#define _loop1_32_type 1193 -#define _loop0_34_type 1194 -#define _gather_33_type 1195 -#define _tmp_35_type 1196 -#define _loop0_37_type 1197 -#define _gather_36_type 1198 -#define _tmp_38_type 1199 -#define _loop0_40_type 1200 -#define _gather_39_type 1201 -#define _loop0_42_type 1202 -#define _gather_41_type 1203 -#define _loop0_44_type 1204 -#define _gather_43_type 1205 -#define _loop0_46_type 1206 -#define _gather_45_type 1207 -#define _tmp_47_type 1208 -#define _loop1_48_type 1209 -#define _tmp_49_type 1210 -#define _tmp_50_type 1211 -#define _tmp_51_type 1212 -#define _tmp_52_type 1213 -#define _tmp_53_type 1214 -#define _loop0_54_type 1215 -#define _loop0_55_type 1216 -#define _loop0_56_type 1217 -#define _loop1_57_type 1218 -#define _loop0_58_type 1219 -#define _loop1_59_type 1220 -#define _loop1_60_type 1221 -#define _loop1_61_type 1222 -#define _loop0_62_type 1223 -#define _loop1_63_type 1224 -#define _loop0_64_type 1225 -#define _loop1_65_type 1226 -#define _loop0_66_type 1227 -#define _loop1_67_type 1228 -#define _loop1_68_type 1229 -#define _tmp_69_type 1230 -#define _loop0_71_type 1231 -#define _gather_70_type 1232 -#define _loop1_72_type 1233 +#define star_expressions_type 1059 +#define star_expression_type 1060 +#define star_named_expressions_type 1061 +#define star_named_expression_type 1062 +#define named_expression_type 1063 +#define annotated_rhs_type 1064 +#define expressions_type 1065 +#define expression_type 1066 +#define lambdef_type 1067 +#define lambda_params_type 1068 +#define lambda_parameters_type 1069 +#define lambda_slash_no_default_type 1070 +#define lambda_slash_with_default_type 1071 +#define lambda_star_etc_type 1072 +#define lambda_kwds_type 1073 +#define lambda_param_no_default_type 1074 +#define lambda_param_with_default_type 1075 +#define lambda_param_maybe_default_type 1076 +#define lambda_param_type 1077 +#define disjunction_type 1078 +#define conjunction_type 1079 +#define inversion_type 1080 +#define comparison_type 1081 +#define compare_op_bitwise_or_pair_type 1082 +#define eq_bitwise_or_type 1083 +#define noteq_bitwise_or_type 1084 +#define lte_bitwise_or_type 1085 +#define lt_bitwise_or_type 1086 +#define gte_bitwise_or_type 1087 +#define gt_bitwise_or_type 1088 +#define notin_bitwise_or_type 1089 +#define in_bitwise_or_type 1090 +#define isnot_bitwise_or_type 1091 +#define is_bitwise_or_type 1092 +#define bitwise_or_type 1093 // Left-recursive +#define bitwise_xor_type 1094 // Left-recursive +#define bitwise_and_type 1095 // Left-recursive +#define shift_expr_type 1096 // Left-recursive +#define sum_type 1097 // Left-recursive +#define term_type 1098 // Left-recursive +#define factor_type 1099 +#define power_type 1100 +#define await_primary_type 1101 +#define primary_type 1102 // Left-recursive +#define slices_type 1103 +#define slice_type 1104 +#define atom_type 1105 +#define strings_type 1106 +#define list_type 1107 +#define listcomp_type 1108 +#define tuple_type 1109 +#define group_type 1110 +#define genexp_type 1111 +#define set_type 1112 +#define setcomp_type 1113 +#define dict_type 1114 +#define dictcomp_type 1115 +#define double_starred_kvpairs_type 1116 +#define double_starred_kvpair_type 1117 +#define kvpair_type 1118 +#define for_if_clauses_type 1119 +#define for_if_clause_type 1120 +#define yield_expr_type 1121 +#define arguments_type 1122 +#define args_type 1123 +#define kwargs_type 1124 +#define starred_expression_type 1125 +#define kwarg_or_starred_type 1126 +#define kwarg_or_double_starred_type 1127 +#define star_targets_type 1128 +#define star_targets_seq_type 1129 +#define star_target_type 1130 +#define star_atom_type 1131 +#define single_target_type 1132 +#define single_subscript_attribute_target_type 1133 +#define del_targets_type 1134 +#define del_target_type 1135 +#define del_t_atom_type 1136 +#define targets_type 1137 +#define target_type 1138 +#define t_primary_type 1139 // Left-recursive +#define t_lookahead_type 1140 +#define t_atom_type 1141 +#define invalid_arguments_type 1142 +#define invalid_kwarg_type 1143 +#define invalid_named_expression_type 1144 +#define invalid_assignment_type 1145 +#define invalid_ann_assign_target_type 1146 +#define invalid_del_stmt_type 1147 +#define invalid_block_type 1148 +#define invalid_primary_type 1149 // Left-recursive +#define invalid_comprehension_type 1150 +#define invalid_dict_comprehension_type 1151 +#define invalid_parameters_type 1152 +#define invalid_lambda_parameters_type 1153 +#define invalid_star_etc_type 1154 +#define invalid_lambda_star_etc_type 1155 +#define invalid_double_type_comments_type 1156 +#define invalid_with_item_type 1157 +#define invalid_for_target_type 1158 +#define invalid_group_type 1159 +#define invalid_import_from_targets_type 1160 +#define _loop0_1_type 1161 +#define _loop0_2_type 1162 +#define _loop0_4_type 1163 +#define _gather_3_type 1164 +#define _loop0_6_type 1165 +#define _gather_5_type 1166 +#define _loop0_8_type 1167 +#define _gather_7_type 1168 +#define _loop0_10_type 1169 +#define _gather_9_type 1170 +#define _loop1_11_type 1171 +#define _loop0_13_type 1172 +#define _gather_12_type 1173 +#define _tmp_14_type 1174 +#define _tmp_15_type 1175 +#define _tmp_16_type 1176 +#define _tmp_17_type 1177 +#define _tmp_18_type 1178 +#define _tmp_19_type 1179 +#define _tmp_20_type 1180 +#define _tmp_21_type 1181 +#define _loop1_22_type 1182 +#define _tmp_23_type 1183 +#define _tmp_24_type 1184 +#define _loop0_26_type 1185 +#define _gather_25_type 1186 +#define _loop0_28_type 1187 +#define _gather_27_type 1188 +#define _tmp_29_type 1189 +#define _tmp_30_type 1190 +#define _loop0_31_type 1191 +#define _loop1_32_type 1192 +#define _loop0_34_type 1193 +#define _gather_33_type 1194 +#define _tmp_35_type 1195 +#define _loop0_37_type 1196 +#define _gather_36_type 1197 +#define _tmp_38_type 1198 +#define _loop0_40_type 1199 +#define _gather_39_type 1200 +#define _loop0_42_type 1201 +#define _gather_41_type 1202 +#define _loop0_44_type 1203 +#define _gather_43_type 1204 +#define _loop0_46_type 1205 +#define _gather_45_type 1206 +#define _tmp_47_type 1207 +#define _loop1_48_type 1208 +#define _tmp_49_type 1209 +#define _tmp_50_type 1210 +#define _tmp_51_type 1211 +#define _tmp_52_type 1212 +#define _tmp_53_type 1213 +#define _loop0_54_type 1214 +#define _loop0_55_type 1215 +#define _loop0_56_type 1216 +#define _loop1_57_type 1217 +#define _loop0_58_type 1218 +#define _loop1_59_type 1219 +#define _loop1_60_type 1220 +#define _loop1_61_type 1221 +#define _loop0_62_type 1222 +#define _loop1_63_type 1223 +#define _loop0_64_type 1224 +#define _loop1_65_type 1225 +#define _loop0_66_type 1226 +#define _loop1_67_type 1227 +#define _loop1_68_type 1228 +#define _tmp_69_type 1229 +#define _loop1_70_type 1230 +#define _loop0_72_type 1231 +#define _gather_71_type 1232 +#define _loop1_73_type 1233 #define _loop0_74_type 1234 -#define _gather_73_type 1235 -#define _loop1_75_type 1236 -#define _loop0_76_type 1237 -#define _loop0_77_type 1238 -#define _loop0_78_type 1239 -#define _loop1_79_type 1240 -#define _loop0_80_type 1241 -#define _loop1_81_type 1242 -#define _loop1_82_type 1243 -#define _loop1_83_type 1244 -#define _loop0_84_type 1245 -#define _loop1_85_type 1246 -#define _loop0_86_type 1247 -#define _loop1_87_type 1248 -#define _loop0_88_type 1249 -#define _loop1_89_type 1250 -#define _loop1_90_type 1251 -#define _loop1_91_type 1252 -#define _loop1_92_type 1253 -#define _tmp_93_type 1254 -#define _loop0_95_type 1255 -#define _gather_94_type 1256 -#define _tmp_96_type 1257 -#define _tmp_97_type 1258 -#define _tmp_98_type 1259 -#define _tmp_99_type 1260 -#define _loop1_100_type 1261 -#define _tmp_101_type 1262 -#define _tmp_102_type 1263 +#define _loop0_75_type 1235 +#define _loop0_76_type 1236 +#define _loop1_77_type 1237 +#define _loop0_78_type 1238 +#define _loop1_79_type 1239 +#define _loop1_80_type 1240 +#define _loop1_81_type 1241 +#define _loop0_82_type 1242 +#define _loop1_83_type 1243 +#define _loop0_84_type 1244 +#define _loop1_85_type 1245 +#define _loop0_86_type 1246 +#define _loop1_87_type 1247 +#define _loop1_88_type 1248 +#define _loop1_89_type 1249 +#define _loop1_90_type 1250 +#define _tmp_91_type 1251 +#define _loop0_93_type 1252 +#define _gather_92_type 1253 +#define _tmp_94_type 1254 +#define _tmp_95_type 1255 +#define _tmp_96_type 1256 +#define _tmp_97_type 1257 +#define _loop1_98_type 1258 +#define _tmp_99_type 1259 +#define _tmp_100_type 1260 +#define _loop0_102_type 1261 +#define _gather_101_type 1262 +#define _loop1_103_type 1263 #define _loop0_104_type 1264 -#define _gather_103_type 1265 -#define _loop1_105_type 1266 -#define _loop0_106_type 1267 -#define _loop0_107_type 1268 -#define _loop0_109_type 1269 -#define _gather_108_type 1270 -#define _tmp_110_type 1271 -#define _loop0_112_type 1272 -#define _gather_111_type 1273 -#define _loop0_114_type 1274 -#define _gather_113_type 1275 -#define _loop0_116_type 1276 -#define _gather_115_type 1277 -#define _loop0_118_type 1278 -#define _gather_117_type 1279 -#define _loop0_119_type 1280 -#define _loop0_121_type 1281 -#define _gather_120_type 1282 -#define _tmp_122_type 1283 -#define _loop0_124_type 1284 -#define _gather_123_type 1285 +#define _loop0_105_type 1265 +#define _loop0_107_type 1266 +#define _gather_106_type 1267 +#define _tmp_108_type 1268 +#define _loop0_110_type 1269 +#define _gather_109_type 1270 +#define _loop0_112_type 1271 +#define _gather_111_type 1272 +#define _loop0_114_type 1273 +#define _gather_113_type 1274 +#define _loop0_116_type 1275 +#define _gather_115_type 1276 +#define _loop0_117_type 1277 +#define _loop0_119_type 1278 +#define _gather_118_type 1279 +#define _tmp_120_type 1280 +#define _loop0_122_type 1281 +#define _gather_121_type 1282 +#define _loop0_124_type 1283 +#define _gather_123_type 1284 +#define _tmp_125_type 1285 #define _loop0_126_type 1286 -#define _gather_125_type 1287 -#define _tmp_127_type 1288 -#define _loop0_128_type 1289 -#define _loop0_129_type 1290 -#define _loop0_130_type 1291 -#define _tmp_131_type 1292 -#define _tmp_132_type 1293 -#define _loop0_133_type 1294 -#define _tmp_134_type 1295 -#define _loop0_135_type 1296 -#define _tmp_136_type 1297 -#define _tmp_137_type 1298 -#define _tmp_138_type 1299 -#define _tmp_139_type 1300 -#define _tmp_140_type 1301 -#define _tmp_141_type 1302 -#define _tmp_142_type 1303 -#define _tmp_143_type 1304 -#define _tmp_144_type 1305 -#define _tmp_145_type 1306 -#define _tmp_146_type 1307 -#define _tmp_147_type 1308 -#define _tmp_148_type 1309 -#define _tmp_149_type 1310 -#define _tmp_150_type 1311 -#define _tmp_151_type 1312 -#define _tmp_152_type 1313 -#define _loop1_153_type 1314 -#define _loop1_154_type 1315 -#define _tmp_155_type 1316 -#define _tmp_156_type 1317 +#define _loop0_127_type 1287 +#define _loop0_128_type 1288 +#define _tmp_129_type 1289 +#define _tmp_130_type 1290 +#define _loop0_131_type 1291 +#define _tmp_132_type 1292 +#define _loop0_133_type 1293 +#define _tmp_134_type 1294 +#define _tmp_135_type 1295 +#define _tmp_136_type 1296 +#define _tmp_137_type 1297 +#define _tmp_138_type 1298 +#define _tmp_139_type 1299 +#define _tmp_140_type 1300 +#define _tmp_141_type 1301 +#define _tmp_142_type 1302 +#define _tmp_143_type 1303 +#define _tmp_144_type 1304 +#define _tmp_145_type 1305 +#define _tmp_146_type 1306 +#define _tmp_147_type 1307 +#define _tmp_148_type 1308 +#define _tmp_149_type 1309 +#define _tmp_150_type 1310 +#define _loop1_151_type 1311 +#define _loop1_152_type 1312 +#define _tmp_153_type 1313 +#define _tmp_154_type 1314 static mod_ty file_rule(Parser *p); static mod_ty interactive_rule(Parser *p); @@ -453,7 +450,6 @@ static asdl_seq* decorators_rule(Parser *p); static stmt_ty class_def_rule(Parser *p); static stmt_ty class_def_raw_rule(Parser *p); static asdl_seq* block_rule(Parser *p); -static asdl_seq* expressions_list_rule(Parser *p); static expr_ty star_expressions_rule(Parser *p); static expr_ty star_expression_rule(Parser *p); static asdl_seq* star_named_expressions_rule(Parser *p); @@ -625,72 +621,72 @@ static asdl_seq *_loop0_66_rule(Parser *p); static asdl_seq *_loop1_67_rule(Parser *p); static asdl_seq *_loop1_68_rule(Parser *p); static void *_tmp_69_rule(Parser *p); -static asdl_seq *_loop0_71_rule(Parser *p); -static asdl_seq *_gather_70_rule(Parser *p); -static asdl_seq *_loop1_72_rule(Parser *p); +static asdl_seq *_loop1_70_rule(Parser *p); +static asdl_seq *_loop0_72_rule(Parser *p); +static asdl_seq *_gather_71_rule(Parser *p); +static asdl_seq *_loop1_73_rule(Parser *p); static asdl_seq *_loop0_74_rule(Parser *p); -static asdl_seq *_gather_73_rule(Parser *p); -static asdl_seq *_loop1_75_rule(Parser *p); +static asdl_seq *_loop0_75_rule(Parser *p); static asdl_seq *_loop0_76_rule(Parser *p); -static asdl_seq *_loop0_77_rule(Parser *p); +static asdl_seq *_loop1_77_rule(Parser *p); static asdl_seq *_loop0_78_rule(Parser *p); static asdl_seq *_loop1_79_rule(Parser *p); -static asdl_seq *_loop0_80_rule(Parser *p); +static asdl_seq *_loop1_80_rule(Parser *p); static asdl_seq *_loop1_81_rule(Parser *p); -static asdl_seq *_loop1_82_rule(Parser *p); +static asdl_seq *_loop0_82_rule(Parser *p); static asdl_seq *_loop1_83_rule(Parser *p); static asdl_seq *_loop0_84_rule(Parser *p); static asdl_seq *_loop1_85_rule(Parser *p); static asdl_seq *_loop0_86_rule(Parser *p); static asdl_seq *_loop1_87_rule(Parser *p); -static asdl_seq *_loop0_88_rule(Parser *p); +static asdl_seq *_loop1_88_rule(Parser *p); static asdl_seq *_loop1_89_rule(Parser *p); static asdl_seq *_loop1_90_rule(Parser *p); -static asdl_seq *_loop1_91_rule(Parser *p); -static asdl_seq *_loop1_92_rule(Parser *p); -static void *_tmp_93_rule(Parser *p); -static asdl_seq *_loop0_95_rule(Parser *p); -static asdl_seq *_gather_94_rule(Parser *p); +static void *_tmp_91_rule(Parser *p); +static asdl_seq *_loop0_93_rule(Parser *p); +static asdl_seq *_gather_92_rule(Parser *p); +static void *_tmp_94_rule(Parser *p); +static void *_tmp_95_rule(Parser *p); static void *_tmp_96_rule(Parser *p); static void *_tmp_97_rule(Parser *p); -static void *_tmp_98_rule(Parser *p); +static asdl_seq *_loop1_98_rule(Parser *p); static void *_tmp_99_rule(Parser *p); -static asdl_seq *_loop1_100_rule(Parser *p); -static void *_tmp_101_rule(Parser *p); -static void *_tmp_102_rule(Parser *p); +static void *_tmp_100_rule(Parser *p); +static asdl_seq *_loop0_102_rule(Parser *p); +static asdl_seq *_gather_101_rule(Parser *p); +static asdl_seq *_loop1_103_rule(Parser *p); static asdl_seq *_loop0_104_rule(Parser *p); -static asdl_seq *_gather_103_rule(Parser *p); -static asdl_seq *_loop1_105_rule(Parser *p); -static asdl_seq *_loop0_106_rule(Parser *p); +static asdl_seq *_loop0_105_rule(Parser *p); static asdl_seq *_loop0_107_rule(Parser *p); -static asdl_seq *_loop0_109_rule(Parser *p); -static asdl_seq *_gather_108_rule(Parser *p); -static void *_tmp_110_rule(Parser *p); +static asdl_seq *_gather_106_rule(Parser *p); +static void *_tmp_108_rule(Parser *p); +static asdl_seq *_loop0_110_rule(Parser *p); +static asdl_seq *_gather_109_rule(Parser *p); static asdl_seq *_loop0_112_rule(Parser *p); static asdl_seq *_gather_111_rule(Parser *p); static asdl_seq *_loop0_114_rule(Parser *p); static asdl_seq *_gather_113_rule(Parser *p); static asdl_seq *_loop0_116_rule(Parser *p); static asdl_seq *_gather_115_rule(Parser *p); -static asdl_seq *_loop0_118_rule(Parser *p); -static asdl_seq *_gather_117_rule(Parser *p); +static asdl_seq *_loop0_117_rule(Parser *p); static asdl_seq *_loop0_119_rule(Parser *p); -static asdl_seq *_loop0_121_rule(Parser *p); -static asdl_seq *_gather_120_rule(Parser *p); -static void *_tmp_122_rule(Parser *p); +static asdl_seq *_gather_118_rule(Parser *p); +static void *_tmp_120_rule(Parser *p); +static asdl_seq *_loop0_122_rule(Parser *p); +static asdl_seq *_gather_121_rule(Parser *p); static asdl_seq *_loop0_124_rule(Parser *p); static asdl_seq *_gather_123_rule(Parser *p); +static void *_tmp_125_rule(Parser *p); static asdl_seq *_loop0_126_rule(Parser *p); -static asdl_seq *_gather_125_rule(Parser *p); -static void *_tmp_127_rule(Parser *p); +static asdl_seq *_loop0_127_rule(Parser *p); static asdl_seq *_loop0_128_rule(Parser *p); -static asdl_seq *_loop0_129_rule(Parser *p); -static asdl_seq *_loop0_130_rule(Parser *p); -static void *_tmp_131_rule(Parser *p); +static void *_tmp_129_rule(Parser *p); +static void *_tmp_130_rule(Parser *p); +static asdl_seq *_loop0_131_rule(Parser *p); static void *_tmp_132_rule(Parser *p); static asdl_seq *_loop0_133_rule(Parser *p); static void *_tmp_134_rule(Parser *p); -static asdl_seq *_loop0_135_rule(Parser *p); +static void *_tmp_135_rule(Parser *p); static void *_tmp_136_rule(Parser *p); static void *_tmp_137_rule(Parser *p); static void *_tmp_138_rule(Parser *p); @@ -706,12 +702,10 @@ static void *_tmp_147_rule(Parser *p); static void *_tmp_148_rule(Parser *p); static void *_tmp_149_rule(Parser *p); static void *_tmp_150_rule(Parser *p); -static void *_tmp_151_rule(Parser *p); -static void *_tmp_152_rule(Parser *p); -static asdl_seq *_loop1_153_rule(Parser *p); -static asdl_seq *_loop1_154_rule(Parser *p); -static void *_tmp_155_rule(Parser *p); -static void *_tmp_156_rule(Parser *p); +static asdl_seq *_loop1_151_rule(Parser *p); +static asdl_seq *_loop1_152_rule(Parser *p); +static void *_tmp_153_rule(Parser *p); +static void *_tmp_154_rule(Parser *p); // file: statements? $ @@ -6333,51 +6327,6 @@ block_rule(Parser *p) return _res; } -// expressions_list: ','.star_expression+ ','? -static asdl_seq* -expressions_list_rule(Parser *p) -{ - D(p->level++); - if (p->error_indicator) { - D(p->level--); - return NULL; - } - asdl_seq* _res = NULL; - int _mark = p->mark; - { // ','.star_expression+ ','? - if (p->error_indicator) { - D(p->level--); - return NULL; - } - D(fprintf(stderr, "%*c> expressions_list[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','.star_expression+ ','?")); - void *_opt_var; - UNUSED(_opt_var); // Silence compiler warnings - asdl_seq * a; - if ( - (a = _gather_70_rule(p)) // ','.star_expression+ - && - (_opt_var = _PyPegen_expect_token(p, 12), 1) // ','? - ) - { - D(fprintf(stderr, "%*c+ expressions_list[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','.star_expression+ ','?")); - _res = a; - if (_res == NULL && PyErr_Occurred()) { - p->error_indicator = 1; - D(p->level--); - return NULL; - } - goto done; - } - p->mark = _mark; - D(fprintf(stderr, "%*c%s expressions_list[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "','.star_expression+ ','?")); - } - _res = NULL; - done: - D(p->level--); - return _res; -} - // star_expressions: // | star_expression ((',' star_expression))+ ','? // | star_expression ',' @@ -6414,7 +6363,7 @@ star_expressions_rule(Parser *p) if ( (a = star_expression_rule(p)) // star_expression && - (b = _loop1_72_rule(p)) // ((',' star_expression))+ + (b = _loop1_70_rule(p)) // ((',' star_expression))+ && (_opt_var = _PyPegen_expect_token(p, 12), 1) // ','? ) @@ -6609,7 +6558,7 @@ star_named_expressions_rule(Parser *p) UNUSED(_opt_var); // Silence compiler warnings asdl_seq * a; if ( - (a = _gather_73_rule(p)) // ','.star_named_expression+ + (a = _gather_71_rule(p)) // ','.star_named_expression+ && (_opt_var = _PyPegen_expect_token(p, 12), 1) // ','? ) @@ -6914,7 +6863,7 @@ expressions_rule(Parser *p) if ( (a = expression_rule(p)) // expression && - (b = _loop1_75_rule(p)) // ((',' expression))+ + (b = _loop1_73_rule(p)) // ((',' expression))+ && (_opt_var = _PyPegen_expect_token(p, 12), 1) // ','? ) @@ -7268,9 +7217,9 @@ lambda_parameters_rule(Parser *p) if ( (a = lambda_slash_no_default_rule(p)) // lambda_slash_no_default && - (b = _loop0_76_rule(p)) // lambda_param_no_default* + (b = _loop0_74_rule(p)) // lambda_param_no_default* && - (c = _loop0_77_rule(p)) // lambda_param_with_default* + (c = _loop0_75_rule(p)) // lambda_param_with_default* && (d = lambda_star_etc_rule(p), 1) // lambda_star_etc? ) @@ -7300,7 +7249,7 @@ lambda_parameters_rule(Parser *p) if ( (a = lambda_slash_with_default_rule(p)) // lambda_slash_with_default && - (b = _loop0_78_rule(p)) // lambda_param_with_default* + (b = _loop0_76_rule(p)) // lambda_param_with_default* && (c = lambda_star_etc_rule(p), 1) // lambda_star_etc? ) @@ -7328,9 +7277,9 @@ lambda_parameters_rule(Parser *p) asdl_seq * b; void *c; if ( - (a = _loop1_79_rule(p)) // lambda_param_no_default+ + (a = _loop1_77_rule(p)) // lambda_param_no_default+ && - (b = _loop0_80_rule(p)) // lambda_param_with_default* + (b = _loop0_78_rule(p)) // lambda_param_with_default* && (c = lambda_star_etc_rule(p), 1) // lambda_star_etc? ) @@ -7357,7 +7306,7 @@ lambda_parameters_rule(Parser *p) asdl_seq * a; void *b; if ( - (a = _loop1_81_rule(p)) // lambda_param_with_default+ + (a = _loop1_79_rule(p)) // lambda_param_with_default+ && (b = lambda_star_etc_rule(p), 1) // lambda_star_etc? ) @@ -7428,7 +7377,7 @@ lambda_slash_no_default_rule(Parser *p) Token * _literal_1; asdl_seq * a; if ( - (a = _loop1_82_rule(p)) // lambda_param_no_default+ + (a = _loop1_80_rule(p)) // lambda_param_no_default+ && (_literal = _PyPegen_expect_token(p, 17)) // token='/' && @@ -7457,7 +7406,7 @@ lambda_slash_no_default_rule(Parser *p) Token * _literal; asdl_seq * a; if ( - (a = _loop1_83_rule(p)) // lambda_param_no_default+ + (a = _loop1_81_rule(p)) // lambda_param_no_default+ && (_literal = _PyPegen_expect_token(p, 17)) // token='/' && @@ -7507,9 +7456,9 @@ lambda_slash_with_default_rule(Parser *p) asdl_seq * a; asdl_seq * b; if ( - (a = _loop0_84_rule(p)) // lambda_param_no_default* + (a = _loop0_82_rule(p)) // lambda_param_no_default* && - (b = _loop1_85_rule(p)) // lambda_param_with_default+ + (b = _loop1_83_rule(p)) // lambda_param_with_default+ && (_literal = _PyPegen_expect_token(p, 17)) // token='/' && @@ -7539,9 +7488,9 @@ lambda_slash_with_default_rule(Parser *p) asdl_seq * a; asdl_seq * b; if ( - (a = _loop0_86_rule(p)) // lambda_param_no_default* + (a = _loop0_84_rule(p)) // lambda_param_no_default* && - (b = _loop1_87_rule(p)) // lambda_param_with_default+ + (b = _loop1_85_rule(p)) // lambda_param_with_default+ && (_literal = _PyPegen_expect_token(p, 17)) // token='/' && @@ -7597,7 +7546,7 @@ lambda_star_etc_rule(Parser *p) && (a = lambda_param_no_default_rule(p)) // lambda_param_no_default && - (b = _loop0_88_rule(p)) // lambda_param_maybe_default* + (b = _loop0_86_rule(p)) // lambda_param_maybe_default* && (c = lambda_kwds_rule(p), 1) // lambda_kwds? ) @@ -7630,7 +7579,7 @@ lambda_star_etc_rule(Parser *p) && (_literal_1 = _PyPegen_expect_token(p, 12)) // token=',' && - (b = _loop1_89_rule(p)) // lambda_param_maybe_default+ + (b = _loop1_87_rule(p)) // lambda_param_maybe_default+ && (c = lambda_kwds_rule(p), 1) // lambda_kwds? ) @@ -8057,7 +8006,7 @@ disjunction_rule(Parser *p) if ( (a = conjunction_rule(p)) // conjunction && - (b = _loop1_90_rule(p)) // (('or' conjunction))+ + (b = _loop1_88_rule(p)) // (('or' conjunction))+ ) { D(fprintf(stderr, "%*c+ disjunction[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "conjunction (('or' conjunction))+")); @@ -8143,7 +8092,7 @@ conjunction_rule(Parser *p) if ( (a = inversion_rule(p)) // inversion && - (b = _loop1_91_rule(p)) // (('and' inversion))+ + (b = _loop1_89_rule(p)) // (('and' inversion))+ ) { D(fprintf(stderr, "%*c+ conjunction[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "inversion (('and' inversion))+")); @@ -8311,7 +8260,7 @@ comparison_rule(Parser *p) if ( (a = bitwise_or_rule(p)) // bitwise_or && - (b = _loop1_92_rule(p)) // compare_op_bitwise_or_pair+ + (b = _loop1_90_rule(p)) // compare_op_bitwise_or_pair+ ) { D(fprintf(stderr, "%*c+ comparison[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "bitwise_or compare_op_bitwise_or_pair+")); @@ -8639,10 +8588,10 @@ noteq_bitwise_or_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> noteq_bitwise_or[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('!=') bitwise_or")); - void *_tmp_93_var; + void *_tmp_91_var; expr_ty a; if ( - (_tmp_93_var = _tmp_93_rule(p)) // '!=' + (_tmp_91_var = _tmp_91_rule(p)) // '!=' && (a = bitwise_or_rule(p)) // bitwise_or ) @@ -10605,7 +10554,7 @@ slices_rule(Parser *p) UNUSED(_opt_var); // Silence compiler warnings asdl_seq * a; if ( - (a = _gather_94_rule(p)) // ','.slice+ + (a = _gather_92_rule(p)) // ','.slice+ && (_opt_var = _PyPegen_expect_token(p, 12), 1) // ','? ) @@ -10675,7 +10624,7 @@ slice_rule(Parser *p) && (b = expression_rule(p), 1) // expression? && - (c = _tmp_96_rule(p), 1) // [':' expression?] + (c = _tmp_94_rule(p), 1) // [':' expression?] ) { D(fprintf(stderr, "%*c+ slice[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression? ':' expression? [':' expression?]")); @@ -10949,15 +10898,15 @@ atom_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> atom[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "&'(' (tuple | group | genexp)")); - void *_tmp_97_var; + void *_tmp_95_var; if ( _PyPegen_lookahead_with_int(1, _PyPegen_expect_token, p, 7) // token='(' && - (_tmp_97_var = _tmp_97_rule(p)) // tuple | group | genexp + (_tmp_95_var = _tmp_95_rule(p)) // tuple | group | genexp ) { D(fprintf(stderr, "%*c+ atom[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "&'(' (tuple | group | genexp)")); - _res = _tmp_97_var; + _res = _tmp_95_var; goto done; } p->mark = _mark; @@ -10970,15 +10919,15 @@ atom_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> atom[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "&'[' (list | listcomp)")); - void *_tmp_98_var; + void *_tmp_96_var; if ( _PyPegen_lookahead_with_int(1, _PyPegen_expect_token, p, 9) // token='[' && - (_tmp_98_var = _tmp_98_rule(p)) // list | listcomp + (_tmp_96_var = _tmp_96_rule(p)) // list | listcomp ) { D(fprintf(stderr, "%*c+ atom[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "&'[' (list | listcomp)")); - _res = _tmp_98_var; + _res = _tmp_96_var; goto done; } p->mark = _mark; @@ -10991,15 +10940,15 @@ atom_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> atom[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "&'{' (dict | set | dictcomp | setcomp)")); - void *_tmp_99_var; + void *_tmp_97_var; if ( _PyPegen_lookahead_with_int(1, _PyPegen_expect_token, p, 25) // token='{' && - (_tmp_99_var = _tmp_99_rule(p)) // dict | set | dictcomp | setcomp + (_tmp_97_var = _tmp_97_rule(p)) // dict | set | dictcomp | setcomp ) { D(fprintf(stderr, "%*c+ atom[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "&'{' (dict | set | dictcomp | setcomp)")); - _res = _tmp_99_var; + _res = _tmp_97_var; goto done; } p->mark = _mark; @@ -11068,7 +11017,7 @@ strings_rule(Parser *p) D(fprintf(stderr, "%*c> strings[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "STRING+")); asdl_seq * a; if ( - (a = _loop1_100_rule(p)) // STRING+ + (a = _loop1_98_rule(p)) // STRING+ ) { D(fprintf(stderr, "%*c+ strings[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "STRING+")); @@ -11282,7 +11231,7 @@ tuple_rule(Parser *p) if ( (_literal = _PyPegen_expect_token(p, 7)) // token='(' && - (a = _tmp_101_rule(p), 1) // [star_named_expression ',' star_named_expressions?] + (a = _tmp_99_rule(p), 1) // [star_named_expression ',' star_named_expressions?] && (_literal_1 = _PyPegen_expect_token(p, 8)) // token=')' ) @@ -11338,7 +11287,7 @@ group_rule(Parser *p) if ( (_literal = _PyPegen_expect_token(p, 7)) // token='(' && - (a = _tmp_102_rule(p)) // yield_expr | named_expression + (a = _tmp_100_rule(p)) // yield_expr | named_expression && (_literal_1 = _PyPegen_expect_token(p, 8)) // token=')' ) @@ -11475,7 +11424,7 @@ genexp_rule(Parser *p) return _res; } -// set: '{' expressions_list '}' +// set: '{' star_named_expressions '}' static expr_ty set_rule(Parser *p) { @@ -11495,24 +11444,24 @@ set_rule(Parser *p) UNUSED(_start_lineno); // Only used by EXTRA macro int _start_col_offset = p->tokens[_mark]->col_offset; UNUSED(_start_col_offset); // Only used by EXTRA macro - { // '{' expressions_list '}' + { // '{' star_named_expressions '}' if (p->error_indicator) { D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> set[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'{' expressions_list '}'")); + D(fprintf(stderr, "%*c> set[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'{' star_named_expressions '}'")); Token * _literal; Token * _literal_1; asdl_seq* a; if ( (_literal = _PyPegen_expect_token(p, 25)) // token='{' && - (a = expressions_list_rule(p)) // expressions_list + (a = star_named_expressions_rule(p)) // star_named_expressions && (_literal_1 = _PyPegen_expect_token(p, 26)) // token='}' ) { - D(fprintf(stderr, "%*c+ set[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'{' expressions_list '}'")); + D(fprintf(stderr, "%*c+ set[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'{' star_named_expressions '}'")); Token *_token = _PyPegen_get_last_nonnwhitespace_token(p); if (_token == NULL) { D(p->level--); @@ -11532,7 +11481,7 @@ set_rule(Parser *p) } p->mark = _mark; D(fprintf(stderr, "%*c%s set[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'{' expressions_list '}'")); + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'{' star_named_expressions '}'")); } _res = NULL; done: @@ -11540,7 +11489,7 @@ set_rule(Parser *p) return _res; } -// setcomp: '{' expression ~ for_if_clauses '}' | invalid_comprehension +// setcomp: '{' named_expression ~ for_if_clauses '}' | invalid_comprehension static expr_ty setcomp_rule(Parser *p) { @@ -11560,12 +11509,12 @@ setcomp_rule(Parser *p) UNUSED(_start_lineno); // Only used by EXTRA macro int _start_col_offset = p->tokens[_mark]->col_offset; UNUSED(_start_col_offset); // Only used by EXTRA macro - { // '{' expression ~ for_if_clauses '}' + { // '{' named_expression ~ for_if_clauses '}' if (p->error_indicator) { D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> setcomp[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'{' expression ~ for_if_clauses '}'")); + D(fprintf(stderr, "%*c> setcomp[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'{' named_expression ~ for_if_clauses '}'")); int _cut_var = 0; Token * _literal; Token * _literal_1; @@ -11574,7 +11523,7 @@ setcomp_rule(Parser *p) if ( (_literal = _PyPegen_expect_token(p, 25)) // token='{' && - (a = expression_rule(p)) // expression + (a = named_expression_rule(p)) // named_expression && (_cut_var = 1) && @@ -11583,7 +11532,7 @@ setcomp_rule(Parser *p) (_literal_1 = _PyPegen_expect_token(p, 26)) // token='}' ) { - D(fprintf(stderr, "%*c+ setcomp[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'{' expression ~ for_if_clauses '}'")); + D(fprintf(stderr, "%*c+ setcomp[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'{' named_expression ~ for_if_clauses '}'")); Token *_token = _PyPegen_get_last_nonnwhitespace_token(p); if (_token == NULL) { D(p->level--); @@ -11603,7 +11552,7 @@ setcomp_rule(Parser *p) } p->mark = _mark; D(fprintf(stderr, "%*c%s setcomp[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'{' expression ~ for_if_clauses '}'")); + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'{' named_expression ~ for_if_clauses '}'")); if (_cut_var) { D(p->level--); return NULL; @@ -11807,7 +11756,7 @@ double_starred_kvpairs_rule(Parser *p) UNUSED(_opt_var); // Silence compiler warnings asdl_seq * a; if ( - (a = _gather_103_rule(p)) // ','.double_starred_kvpair+ + (a = _gather_101_rule(p)) // ','.double_starred_kvpair+ && (_opt_var = _PyPegen_expect_token(p, 12), 1) // ','? ) @@ -11958,13 +11907,13 @@ for_if_clauses_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> for_if_clauses[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "for_if_clause+")); - asdl_seq * _loop1_105_var; + asdl_seq * _loop1_103_var; if ( - (_loop1_105_var = _loop1_105_rule(p)) // for_if_clause+ + (_loop1_103_var = _loop1_103_rule(p)) // for_if_clause+ ) { D(fprintf(stderr, "%*c+ for_if_clauses[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "for_if_clause+")); - _res = _loop1_105_var; + _res = _loop1_103_var; goto done; } p->mark = _mark; @@ -12017,7 +11966,7 @@ for_if_clause_rule(Parser *p) && (b = disjunction_rule(p)) // disjunction && - (c = _loop0_106_rule(p)) // (('if' disjunction))* + (c = _loop0_104_rule(p)) // (('if' disjunction))* ) { D(fprintf(stderr, "%*c+ for_if_clause[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "ASYNC 'for' star_targets 'in' ~ disjunction (('if' disjunction))*")); @@ -12060,7 +12009,7 @@ for_if_clause_rule(Parser *p) && (b = disjunction_rule(p)) // disjunction && - (c = _loop0_107_rule(p)) // (('if' disjunction))* + (c = _loop0_105_rule(p)) // (('if' disjunction))* ) { D(fprintf(stderr, "%*c+ for_if_clause[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'for' star_targets 'in' ~ disjunction (('if' disjunction))*")); @@ -12306,9 +12255,9 @@ args_rule(Parser *p) asdl_seq * a; void *b; if ( - (a = _gather_108_rule(p)) // ','.(starred_expression | named_expression !'=')+ + (a = _gather_106_rule(p)) // ','.(starred_expression | named_expression !'=')+ && - (b = _tmp_110_rule(p), 1) // [',' kwargs] + (b = _tmp_108_rule(p), 1) // [',' kwargs] ) { D(fprintf(stderr, "%*c+ args[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','.(starred_expression | named_expression !'=')+ [',' kwargs]")); @@ -12396,11 +12345,11 @@ kwargs_rule(Parser *p) asdl_seq * a; asdl_seq * b; if ( - (a = _gather_111_rule(p)) // ','.kwarg_or_starred+ + (a = _gather_109_rule(p)) // ','.kwarg_or_starred+ && (_literal = _PyPegen_expect_token(p, 12)) // token=',' && - (b = _gather_113_rule(p)) // ','.kwarg_or_double_starred+ + (b = _gather_111_rule(p)) // ','.kwarg_or_double_starred+ ) { D(fprintf(stderr, "%*c+ kwargs[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','.kwarg_or_starred+ ',' ','.kwarg_or_double_starred+")); @@ -12422,13 +12371,13 @@ kwargs_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> kwargs[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','.kwarg_or_starred+")); - asdl_seq * _gather_115_var; + asdl_seq * _gather_113_var; if ( - (_gather_115_var = _gather_115_rule(p)) // ','.kwarg_or_starred+ + (_gather_113_var = _gather_113_rule(p)) // ','.kwarg_or_starred+ ) { D(fprintf(stderr, "%*c+ kwargs[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','.kwarg_or_starred+")); - _res = _gather_115_var; + _res = _gather_113_var; goto done; } p->mark = _mark; @@ -12441,13 +12390,13 @@ kwargs_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> kwargs[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','.kwarg_or_double_starred+")); - asdl_seq * _gather_117_var; + asdl_seq * _gather_115_var; if ( - (_gather_117_var = _gather_117_rule(p)) // ','.kwarg_or_double_starred+ + (_gather_115_var = _gather_115_rule(p)) // ','.kwarg_or_double_starred+ ) { D(fprintf(stderr, "%*c+ kwargs[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','.kwarg_or_double_starred+")); - _res = _gather_117_var; + _res = _gather_115_var; goto done; } p->mark = _mark; @@ -12809,7 +12758,7 @@ star_targets_rule(Parser *p) if ( (a = star_target_rule(p)) // star_target && - (b = _loop0_119_rule(p)) // ((',' star_target))* + (b = _loop0_117_rule(p)) // ((',' star_target))* && (_opt_var = _PyPegen_expect_token(p, 12), 1) // ','? ) @@ -12863,7 +12812,7 @@ star_targets_seq_rule(Parser *p) UNUSED(_opt_var); // Silence compiler warnings asdl_seq * a; if ( - (a = _gather_120_rule(p)) // ','.star_target+ + (a = _gather_118_rule(p)) // ','.star_target+ && (_opt_var = _PyPegen_expect_token(p, 12), 1) // ','? ) @@ -12926,7 +12875,7 @@ star_target_rule(Parser *p) if ( (_literal = _PyPegen_expect_token(p, 16)) // token='*' && - (a = _tmp_122_rule(p)) // !'*' star_target + (a = _tmp_120_rule(p)) // !'*' star_target ) { D(fprintf(stderr, "%*c+ star_target[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'*' (!'*' star_target)")); @@ -13448,7 +13397,7 @@ del_targets_rule(Parser *p) UNUSED(_opt_var); // Silence compiler warnings asdl_seq * a; if ( - (a = _gather_123_rule(p)) // ','.del_target+ + (a = _gather_121_rule(p)) // ','.del_target+ && (_opt_var = _PyPegen_expect_token(p, 12), 1) // ','? ) @@ -13789,7 +13738,7 @@ targets_rule(Parser *p) UNUSED(_opt_var); // Silence compiler warnings asdl_seq * a; if ( - (a = _gather_125_rule(p)) // ','.target+ + (a = _gather_123_rule(p)) // ','.target+ && (_opt_var = _PyPegen_expect_token(p, 12), 1) // ','? ) @@ -14503,7 +14452,7 @@ invalid_arguments_rule(Parser *p) && (_literal = _PyPegen_expect_token(p, 12)) // token=',' && - (_opt_var = _tmp_127_rule(p), 1) // [args | expression for_if_clauses] + (_opt_var = _tmp_125_rule(p), 1) // [args | expression for_if_clauses] ) { D(fprintf(stderr, "%*c+ invalid_arguments[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression for_if_clauses ',' [args | expression for_if_clauses]")); @@ -14761,7 +14710,7 @@ invalid_assignment_rule(Parser *p) D(fprintf(stderr, "%*c> invalid_assignment[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_named_expression ',' star_named_expressions* ':' expression")); Token * _literal; Token * _literal_1; - asdl_seq * _loop0_128_var; + asdl_seq * _loop0_126_var; expr_ty a; expr_ty expression_var; if ( @@ -14769,7 +14718,7 @@ invalid_assignment_rule(Parser *p) && (_literal = _PyPegen_expect_token(p, 12)) // token=',' && - (_loop0_128_var = _loop0_128_rule(p)) // star_named_expressions* + (_loop0_126_var = _loop0_126_rule(p)) // star_named_expressions* && (_literal_1 = _PyPegen_expect_token(p, 11)) // token=':' && @@ -14826,10 +14775,10 @@ invalid_assignment_rule(Parser *p) } D(fprintf(stderr, "%*c> invalid_assignment[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "((star_targets '='))* star_expressions '='")); Token * _literal; - asdl_seq * _loop0_129_var; + asdl_seq * _loop0_127_var; expr_ty a; if ( - (_loop0_129_var = _loop0_129_rule(p)) // ((star_targets '='))* + (_loop0_127_var = _loop0_127_rule(p)) // ((star_targets '='))* && (a = star_expressions_rule(p)) // star_expressions && @@ -14856,10 +14805,10 @@ invalid_assignment_rule(Parser *p) } D(fprintf(stderr, "%*c> invalid_assignment[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "((star_targets '='))* yield_expr '='")); Token * _literal; - asdl_seq * _loop0_130_var; + asdl_seq * _loop0_128_var; expr_ty a; if ( - (_loop0_130_var = _loop0_130_rule(p)) // ((star_targets '='))* + (_loop0_128_var = _loop0_128_rule(p)) // ((star_targets '='))* && (a = yield_expr_rule(p)) // yield_expr && @@ -14885,7 +14834,7 @@ invalid_assignment_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> invalid_assignment[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_expressions augassign (yield_expr | star_expressions)")); - void *_tmp_131_var; + void *_tmp_129_var; expr_ty a; AugOperator* augassign_var; if ( @@ -14893,7 +14842,7 @@ invalid_assignment_rule(Parser *p) && (augassign_var = augassign_rule(p)) // augassign && - (_tmp_131_var = _tmp_131_rule(p)) // yield_expr | star_expressions + (_tmp_129_var = _tmp_129_rule(p)) // yield_expr | star_expressions ) { D(fprintf(stderr, "%*c+ invalid_assignment[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_expressions augassign (yield_expr | star_expressions)")); @@ -15149,11 +15098,11 @@ invalid_comprehension_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> invalid_comprehension[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('[' | '(' | '{') starred_expression for_if_clauses")); - void *_tmp_132_var; + void *_tmp_130_var; expr_ty a; asdl_seq* for_if_clauses_var; if ( - (_tmp_132_var = _tmp_132_rule(p)) // '[' | '(' | '{' + (_tmp_130_var = _tmp_130_rule(p)) // '[' | '(' | '{' && (a = starred_expression_rule(p)) // starred_expression && @@ -15250,13 +15199,13 @@ invalid_parameters_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> invalid_parameters[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_no_default* (slash_with_default | param_with_default+) param_no_default")); - asdl_seq * _loop0_133_var; - void *_tmp_134_var; + asdl_seq * _loop0_131_var; + void *_tmp_132_var; arg_ty param_no_default_var; if ( - (_loop0_133_var = _loop0_133_rule(p)) // param_no_default* + (_loop0_131_var = _loop0_131_rule(p)) // param_no_default* && - (_tmp_134_var = _tmp_134_rule(p)) // slash_with_default | param_with_default+ + (_tmp_132_var = _tmp_132_rule(p)) // slash_with_default | param_with_default+ && (param_no_default_var = param_no_default_rule(p)) // param_no_default ) @@ -15298,13 +15247,13 @@ invalid_lambda_parameters_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> invalid_lambda_parameters[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default* (lambda_slash_with_default | lambda_param_with_default+) lambda_param_no_default")); - asdl_seq * _loop0_135_var; - void *_tmp_136_var; + asdl_seq * _loop0_133_var; + void *_tmp_134_var; arg_ty lambda_param_no_default_var; if ( - (_loop0_135_var = _loop0_135_rule(p)) // lambda_param_no_default* + (_loop0_133_var = _loop0_133_rule(p)) // lambda_param_no_default* && - (_tmp_136_var = _tmp_136_rule(p)) // lambda_slash_with_default | lambda_param_with_default+ + (_tmp_134_var = _tmp_134_rule(p)) // lambda_slash_with_default | lambda_param_with_default+ && (lambda_param_no_default_var = lambda_param_no_default_rule(p)) // lambda_param_no_default ) @@ -15346,11 +15295,11 @@ invalid_star_etc_rule(Parser *p) } D(fprintf(stderr, "%*c> invalid_star_etc[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'*' (')' | ',' (')' | '**'))")); Token * _literal; - void *_tmp_137_var; + void *_tmp_135_var; if ( (_literal = _PyPegen_expect_token(p, 16)) // token='*' && - (_tmp_137_var = _tmp_137_rule(p)) // ')' | ',' (')' | '**') + (_tmp_135_var = _tmp_135_rule(p)) // ')' | ',' (')' | '**') ) { D(fprintf(stderr, "%*c+ invalid_star_etc[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'*' (')' | ',' (')' | '**'))")); @@ -15420,11 +15369,11 @@ invalid_lambda_star_etc_rule(Parser *p) } D(fprintf(stderr, "%*c> invalid_lambda_star_etc[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'*' (':' | ',' (':' | '**'))")); Token * _literal; - void *_tmp_138_var; + void *_tmp_136_var; if ( (_literal = _PyPegen_expect_token(p, 16)) // token='*' && - (_tmp_138_var = _tmp_138_rule(p)) // ':' | ',' (':' | '**') + (_tmp_136_var = _tmp_136_rule(p)) // ':' | ',' (':' | '**') ) { D(fprintf(stderr, "%*c+ invalid_lambda_star_etc[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'*' (':' | ',' (':' | '**'))")); @@ -16933,12 +16882,12 @@ _loop1_22_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> _loop1_22[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(star_targets '=')")); - void *_tmp_139_var; + void *_tmp_137_var; while ( - (_tmp_139_var = _tmp_139_rule(p)) // star_targets '=' + (_tmp_137_var = _tmp_137_rule(p)) // star_targets '=' ) { - _res = _tmp_139_var; + _res = _tmp_137_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -17441,12 +17390,12 @@ _loop0_31_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> _loop0_31[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('.' | '...')")); - void *_tmp_140_var; + void *_tmp_138_var; while ( - (_tmp_140_var = _tmp_140_rule(p)) // '.' | '...' + (_tmp_138_var = _tmp_138_rule(p)) // '.' | '...' ) { - _res = _tmp_140_var; + _res = _tmp_138_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -17507,12 +17456,12 @@ _loop1_32_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> _loop1_32[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('.' | '...')")); - void *_tmp_141_var; + void *_tmp_139_var; while ( - (_tmp_141_var = _tmp_141_rule(p)) // '.' | '...' + (_tmp_139_var = _tmp_139_rule(p)) // '.' | '...' ) { - _res = _tmp_141_var; + _res = _tmp_139_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -19669,12 +19618,12 @@ _loop1_68_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> _loop1_68[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('@' named_expression NEWLINE)")); - void *_tmp_142_var; + void *_tmp_140_var; while ( - (_tmp_142_var = _tmp_142_rule(p)) // '@' named_expression NEWLINE + (_tmp_140_var = _tmp_140_rule(p)) // '@' named_expression NEWLINE ) { - _res = _tmp_142_var; + _res = _tmp_140_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -19760,123 +19709,9 @@ _tmp_69_rule(Parser *p) return _res; } -// _loop0_71: ',' star_expression +// _loop1_70: (',' star_expression) static asdl_seq * -_loop0_71_rule(Parser *p) -{ - D(p->level++); - if (p->error_indicator) { - D(p->level--); - return NULL; - } - void *_res = NULL; - int _mark = p->mark; - int _start_mark = p->mark; - void **_children = PyMem_Malloc(sizeof(void *)); - if (!_children) { - p->error_indicator = 1; - PyErr_NoMemory(); - D(p->level--); - return NULL; - } - ssize_t _children_capacity = 1; - ssize_t _n = 0; - { // ',' star_expression - if (p->error_indicator) { - D(p->level--); - return NULL; - } - D(fprintf(stderr, "%*c> _loop0_71[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' star_expression")); - Token * _literal; - expr_ty elem; - while ( - (_literal = _PyPegen_expect_token(p, 12)) // token=',' - && - (elem = star_expression_rule(p)) // star_expression - ) - { - _res = elem; - if (_res == NULL && PyErr_Occurred()) { - p->error_indicator = 1; - PyMem_Free(_children); - D(p->level--); - return NULL; - } - if (_n == _children_capacity) { - _children_capacity *= 2; - void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); - if (!_new_children) { - p->error_indicator = 1; - PyErr_NoMemory(); - D(p->level--); - return NULL; - } - _children = _new_children; - } - _children[_n++] = _res; - _mark = p->mark; - } - p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_71[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' star_expression")); - } - asdl_seq *_seq = _Py_asdl_seq_new(_n, p->arena); - if (!_seq) { - PyMem_Free(_children); - p->error_indicator = 1; - PyErr_NoMemory(); - D(p->level--); - return NULL; - } - for (int i = 0; i < _n; i++) asdl_seq_SET(_seq, i, _children[i]); - PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_71_type, _seq); - D(p->level--); - return _seq; -} - -// _gather_70: star_expression _loop0_71 -static asdl_seq * -_gather_70_rule(Parser *p) -{ - D(p->level++); - if (p->error_indicator) { - D(p->level--); - return NULL; - } - asdl_seq * _res = NULL; - int _mark = p->mark; - { // star_expression _loop0_71 - if (p->error_indicator) { - D(p->level--); - return NULL; - } - D(fprintf(stderr, "%*c> _gather_70[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_expression _loop0_71")); - expr_ty elem; - asdl_seq * seq; - if ( - (elem = star_expression_rule(p)) // star_expression - && - (seq = _loop0_71_rule(p)) // _loop0_71 - ) - { - D(fprintf(stderr, "%*c+ _gather_70[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_expression _loop0_71")); - _res = _PyPegen_seq_insert_in_front(p, elem, seq); - goto done; - } - p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_70[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_expression _loop0_71")); - } - _res = NULL; - done: - D(p->level--); - return _res; -} - -// _loop1_72: (',' star_expression) -static asdl_seq * -_loop1_72_rule(Parser *p) +_loop1_70_rule(Parser *p) { D(p->level++); if (p->error_indicator) { @@ -19900,13 +19735,13 @@ _loop1_72_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _loop1_72[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(',' star_expression)")); - void *_tmp_143_var; + D(fprintf(stderr, "%*c> _loop1_70[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(',' star_expression)")); + void *_tmp_141_var; while ( - (_tmp_143_var = _tmp_143_rule(p)) // ',' star_expression + (_tmp_141_var = _tmp_141_rule(p)) // ',' star_expression ) { - _res = _tmp_143_var; + _res = _tmp_141_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -19922,7 +19757,7 @@ _loop1_72_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_72[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_70[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(',' star_expression)")); } if (_n == 0 || p->error_indicator) { @@ -19940,14 +19775,14 @@ _loop1_72_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop1_72_type, _seq); + _PyPegen_insert_memo(p, _start_mark, _loop1_70_type, _seq); D(p->level--); return _seq; } -// _loop0_74: ',' star_named_expression +// _loop0_72: ',' star_named_expression static asdl_seq * -_loop0_74_rule(Parser *p) +_loop0_72_rule(Parser *p) { D(p->level++); if (p->error_indicator) { @@ -19971,7 +19806,7 @@ _loop0_74_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _loop0_74[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' star_named_expression")); + D(fprintf(stderr, "%*c> _loop0_72[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' star_named_expression")); Token * _literal; expr_ty elem; while ( @@ -20002,7 +19837,7 @@ _loop0_74_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_74[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_72[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' star_named_expression")); } asdl_seq *_seq = _Py_asdl_seq_new(_n, p->arena); @@ -20015,14 +19850,14 @@ _loop0_74_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_74_type, _seq); + _PyPegen_insert_memo(p, _start_mark, _loop0_72_type, _seq); D(p->level--); return _seq; } -// _gather_73: star_named_expression _loop0_74 +// _gather_71: star_named_expression _loop0_72 static asdl_seq * -_gather_73_rule(Parser *p) +_gather_71_rule(Parser *p) { D(p->level++); if (p->error_indicator) { @@ -20031,27 +19866,27 @@ _gather_73_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // star_named_expression _loop0_74 + { // star_named_expression _loop0_72 if (p->error_indicator) { D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _gather_73[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_named_expression _loop0_74")); + D(fprintf(stderr, "%*c> _gather_71[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_named_expression _loop0_72")); expr_ty elem; asdl_seq * seq; if ( (elem = star_named_expression_rule(p)) // star_named_expression && - (seq = _loop0_74_rule(p)) // _loop0_74 + (seq = _loop0_72_rule(p)) // _loop0_72 ) { - D(fprintf(stderr, "%*c+ _gather_73[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_named_expression _loop0_74")); + D(fprintf(stderr, "%*c+ _gather_71[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_named_expression _loop0_72")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_73[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_named_expression _loop0_74")); + D(fprintf(stderr, "%*c%s _gather_71[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_named_expression _loop0_72")); } _res = NULL; done: @@ -20059,9 +19894,9 @@ _gather_73_rule(Parser *p) return _res; } -// _loop1_75: (',' expression) +// _loop1_73: (',' expression) static asdl_seq * -_loop1_75_rule(Parser *p) +_loop1_73_rule(Parser *p) { D(p->level++); if (p->error_indicator) { @@ -20085,13 +19920,13 @@ _loop1_75_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _loop1_75[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(',' expression)")); - void *_tmp_144_var; + D(fprintf(stderr, "%*c> _loop1_73[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(',' expression)")); + void *_tmp_142_var; while ( - (_tmp_144_var = _tmp_144_rule(p)) // ',' expression + (_tmp_142_var = _tmp_142_rule(p)) // ',' expression ) { - _res = _tmp_144_var; + _res = _tmp_142_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -20107,7 +19942,7 @@ _loop1_75_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_75[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_73[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(',' expression)")); } if (_n == 0 || p->error_indicator) { @@ -20125,14 +19960,14 @@ _loop1_75_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop1_75_type, _seq); + _PyPegen_insert_memo(p, _start_mark, _loop1_73_type, _seq); D(p->level--); return _seq; } -// _loop0_76: lambda_param_no_default +// _loop0_74: lambda_param_no_default static asdl_seq * -_loop0_76_rule(Parser *p) +_loop0_74_rule(Parser *p) { D(p->level++); if (p->error_indicator) { @@ -20156,7 +19991,7 @@ _loop0_76_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _loop0_76[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default")); + D(fprintf(stderr, "%*c> _loop0_74[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default")); arg_ty lambda_param_no_default_var; while ( (lambda_param_no_default_var = lambda_param_no_default_rule(p)) // lambda_param_no_default @@ -20178,7 +20013,7 @@ _loop0_76_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_76[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_74[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_no_default")); } asdl_seq *_seq = _Py_asdl_seq_new(_n, p->arena); @@ -20191,14 +20026,14 @@ _loop0_76_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_76_type, _seq); + _PyPegen_insert_memo(p, _start_mark, _loop0_74_type, _seq); D(p->level--); return _seq; } -// _loop0_77: lambda_param_with_default +// _loop0_75: lambda_param_with_default static asdl_seq * -_loop0_77_rule(Parser *p) +_loop0_75_rule(Parser *p) { D(p->level++); if (p->error_indicator) { @@ -20222,7 +20057,7 @@ _loop0_77_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _loop0_77[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_with_default")); + D(fprintf(stderr, "%*c> _loop0_75[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_with_default")); NameDefaultPair* lambda_param_with_default_var; while ( (lambda_param_with_default_var = lambda_param_with_default_rule(p)) // lambda_param_with_default @@ -20244,7 +20079,7 @@ _loop0_77_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_77[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_75[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_with_default")); } asdl_seq *_seq = _Py_asdl_seq_new(_n, p->arena); @@ -20257,14 +20092,14 @@ _loop0_77_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_77_type, _seq); + _PyPegen_insert_memo(p, _start_mark, _loop0_75_type, _seq); D(p->level--); return _seq; } -// _loop0_78: lambda_param_with_default +// _loop0_76: lambda_param_with_default static asdl_seq * -_loop0_78_rule(Parser *p) +_loop0_76_rule(Parser *p) { D(p->level++); if (p->error_indicator) { @@ -20288,7 +20123,7 @@ _loop0_78_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _loop0_78[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_with_default")); + D(fprintf(stderr, "%*c> _loop0_76[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_with_default")); NameDefaultPair* lambda_param_with_default_var; while ( (lambda_param_with_default_var = lambda_param_with_default_rule(p)) // lambda_param_with_default @@ -20310,7 +20145,7 @@ _loop0_78_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_78[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_76[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_with_default")); } asdl_seq *_seq = _Py_asdl_seq_new(_n, p->arena); @@ -20323,14 +20158,14 @@ _loop0_78_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_78_type, _seq); + _PyPegen_insert_memo(p, _start_mark, _loop0_76_type, _seq); D(p->level--); return _seq; } -// _loop1_79: lambda_param_no_default +// _loop1_77: lambda_param_no_default static asdl_seq * -_loop1_79_rule(Parser *p) +_loop1_77_rule(Parser *p) { D(p->level++); if (p->error_indicator) { @@ -20354,7 +20189,7 @@ _loop1_79_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _loop1_79[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default")); + D(fprintf(stderr, "%*c> _loop1_77[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default")); arg_ty lambda_param_no_default_var; while ( (lambda_param_no_default_var = lambda_param_no_default_rule(p)) // lambda_param_no_default @@ -20376,7 +20211,7 @@ _loop1_79_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_79[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_77[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_no_default")); } if (_n == 0 || p->error_indicator) { @@ -20394,14 +20229,14 @@ _loop1_79_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop1_79_type, _seq); + _PyPegen_insert_memo(p, _start_mark, _loop1_77_type, _seq); D(p->level--); return _seq; } -// _loop0_80: lambda_param_with_default +// _loop0_78: lambda_param_with_default static asdl_seq * -_loop0_80_rule(Parser *p) +_loop0_78_rule(Parser *p) { D(p->level++); if (p->error_indicator) { @@ -20425,7 +20260,7 @@ _loop0_80_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _loop0_80[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_with_default")); + D(fprintf(stderr, "%*c> _loop0_78[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_with_default")); NameDefaultPair* lambda_param_with_default_var; while ( (lambda_param_with_default_var = lambda_param_with_default_rule(p)) // lambda_param_with_default @@ -20447,7 +20282,7 @@ _loop0_80_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_80[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_78[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_with_default")); } asdl_seq *_seq = _Py_asdl_seq_new(_n, p->arena); @@ -20460,14 +20295,14 @@ _loop0_80_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_80_type, _seq); + _PyPegen_insert_memo(p, _start_mark, _loop0_78_type, _seq); D(p->level--); return _seq; } -// _loop1_81: lambda_param_with_default +// _loop1_79: lambda_param_with_default static asdl_seq * -_loop1_81_rule(Parser *p) +_loop1_79_rule(Parser *p) { D(p->level++); if (p->error_indicator) { @@ -20491,7 +20326,7 @@ _loop1_81_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _loop1_81[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_with_default")); + D(fprintf(stderr, "%*c> _loop1_79[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_with_default")); NameDefaultPair* lambda_param_with_default_var; while ( (lambda_param_with_default_var = lambda_param_with_default_rule(p)) // lambda_param_with_default @@ -20513,7 +20348,7 @@ _loop1_81_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_81[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_79[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_with_default")); } if (_n == 0 || p->error_indicator) { @@ -20531,14 +20366,14 @@ _loop1_81_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop1_81_type, _seq); + _PyPegen_insert_memo(p, _start_mark, _loop1_79_type, _seq); D(p->level--); return _seq; } -// _loop1_82: lambda_param_no_default +// _loop1_80: lambda_param_no_default static asdl_seq * -_loop1_82_rule(Parser *p) +_loop1_80_rule(Parser *p) { D(p->level++); if (p->error_indicator) { @@ -20562,7 +20397,7 @@ _loop1_82_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _loop1_82[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default")); + D(fprintf(stderr, "%*c> _loop1_80[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default")); arg_ty lambda_param_no_default_var; while ( (lambda_param_no_default_var = lambda_param_no_default_rule(p)) // lambda_param_no_default @@ -20584,7 +20419,7 @@ _loop1_82_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_82[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_80[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_no_default")); } if (_n == 0 || p->error_indicator) { @@ -20602,14 +20437,14 @@ _loop1_82_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop1_82_type, _seq); + _PyPegen_insert_memo(p, _start_mark, _loop1_80_type, _seq); D(p->level--); return _seq; } -// _loop1_83: lambda_param_no_default +// _loop1_81: lambda_param_no_default static asdl_seq * -_loop1_83_rule(Parser *p) +_loop1_81_rule(Parser *p) { D(p->level++); if (p->error_indicator) { @@ -20633,7 +20468,7 @@ _loop1_83_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _loop1_83[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default")); + D(fprintf(stderr, "%*c> _loop1_81[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default")); arg_ty lambda_param_no_default_var; while ( (lambda_param_no_default_var = lambda_param_no_default_rule(p)) // lambda_param_no_default @@ -20655,7 +20490,7 @@ _loop1_83_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_83[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_81[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_no_default")); } if (_n == 0 || p->error_indicator) { @@ -20673,14 +20508,14 @@ _loop1_83_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop1_83_type, _seq); + _PyPegen_insert_memo(p, _start_mark, _loop1_81_type, _seq); D(p->level--); return _seq; } -// _loop0_84: lambda_param_no_default +// _loop0_82: lambda_param_no_default static asdl_seq * -_loop0_84_rule(Parser *p) +_loop0_82_rule(Parser *p) { D(p->level++); if (p->error_indicator) { @@ -20704,7 +20539,7 @@ _loop0_84_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _loop0_84[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default")); + D(fprintf(stderr, "%*c> _loop0_82[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default")); arg_ty lambda_param_no_default_var; while ( (lambda_param_no_default_var = lambda_param_no_default_rule(p)) // lambda_param_no_default @@ -20726,7 +20561,7 @@ _loop0_84_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_84[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_82[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_no_default")); } asdl_seq *_seq = _Py_asdl_seq_new(_n, p->arena); @@ -20739,14 +20574,14 @@ _loop0_84_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_84_type, _seq); + _PyPegen_insert_memo(p, _start_mark, _loop0_82_type, _seq); D(p->level--); return _seq; } -// _loop1_85: lambda_param_with_default +// _loop1_83: lambda_param_with_default static asdl_seq * -_loop1_85_rule(Parser *p) +_loop1_83_rule(Parser *p) { D(p->level++); if (p->error_indicator) { @@ -20770,7 +20605,7 @@ _loop1_85_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _loop1_85[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_with_default")); + D(fprintf(stderr, "%*c> _loop1_83[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_with_default")); NameDefaultPair* lambda_param_with_default_var; while ( (lambda_param_with_default_var = lambda_param_with_default_rule(p)) // lambda_param_with_default @@ -20792,7 +20627,7 @@ _loop1_85_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_85[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_83[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_with_default")); } if (_n == 0 || p->error_indicator) { @@ -20810,14 +20645,14 @@ _loop1_85_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop1_85_type, _seq); + _PyPegen_insert_memo(p, _start_mark, _loop1_83_type, _seq); D(p->level--); return _seq; } -// _loop0_86: lambda_param_no_default +// _loop0_84: lambda_param_no_default static asdl_seq * -_loop0_86_rule(Parser *p) +_loop0_84_rule(Parser *p) { D(p->level++); if (p->error_indicator) { @@ -20841,7 +20676,7 @@ _loop0_86_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _loop0_86[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default")); + D(fprintf(stderr, "%*c> _loop0_84[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default")); arg_ty lambda_param_no_default_var; while ( (lambda_param_no_default_var = lambda_param_no_default_rule(p)) // lambda_param_no_default @@ -20863,7 +20698,7 @@ _loop0_86_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_86[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_84[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_no_default")); } asdl_seq *_seq = _Py_asdl_seq_new(_n, p->arena); @@ -20876,14 +20711,14 @@ _loop0_86_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_86_type, _seq); + _PyPegen_insert_memo(p, _start_mark, _loop0_84_type, _seq); D(p->level--); return _seq; } -// _loop1_87: lambda_param_with_default +// _loop1_85: lambda_param_with_default static asdl_seq * -_loop1_87_rule(Parser *p) +_loop1_85_rule(Parser *p) { D(p->level++); if (p->error_indicator) { @@ -20907,7 +20742,7 @@ _loop1_87_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _loop1_87[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_with_default")); + D(fprintf(stderr, "%*c> _loop1_85[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_with_default")); NameDefaultPair* lambda_param_with_default_var; while ( (lambda_param_with_default_var = lambda_param_with_default_rule(p)) // lambda_param_with_default @@ -20929,7 +20764,7 @@ _loop1_87_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_87[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_85[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_with_default")); } if (_n == 0 || p->error_indicator) { @@ -20947,14 +20782,14 @@ _loop1_87_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop1_87_type, _seq); + _PyPegen_insert_memo(p, _start_mark, _loop1_85_type, _seq); D(p->level--); return _seq; } -// _loop0_88: lambda_param_maybe_default +// _loop0_86: lambda_param_maybe_default static asdl_seq * -_loop0_88_rule(Parser *p) +_loop0_86_rule(Parser *p) { D(p->level++); if (p->error_indicator) { @@ -20978,7 +20813,7 @@ _loop0_88_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _loop0_88[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_maybe_default")); + D(fprintf(stderr, "%*c> _loop0_86[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_maybe_default")); NameDefaultPair* lambda_param_maybe_default_var; while ( (lambda_param_maybe_default_var = lambda_param_maybe_default_rule(p)) // lambda_param_maybe_default @@ -21000,7 +20835,7 @@ _loop0_88_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_88[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_86[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_maybe_default")); } asdl_seq *_seq = _Py_asdl_seq_new(_n, p->arena); @@ -21013,14 +20848,14 @@ _loop0_88_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_88_type, _seq); + _PyPegen_insert_memo(p, _start_mark, _loop0_86_type, _seq); D(p->level--); return _seq; } -// _loop1_89: lambda_param_maybe_default +// _loop1_87: lambda_param_maybe_default static asdl_seq * -_loop1_89_rule(Parser *p) +_loop1_87_rule(Parser *p) { D(p->level++); if (p->error_indicator) { @@ -21044,7 +20879,7 @@ _loop1_89_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _loop1_89[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_maybe_default")); + D(fprintf(stderr, "%*c> _loop1_87[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_maybe_default")); NameDefaultPair* lambda_param_maybe_default_var; while ( (lambda_param_maybe_default_var = lambda_param_maybe_default_rule(p)) // lambda_param_maybe_default @@ -21066,7 +20901,7 @@ _loop1_89_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_89[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_87[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_maybe_default")); } if (_n == 0 || p->error_indicator) { @@ -21084,14 +20919,14 @@ _loop1_89_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop1_89_type, _seq); + _PyPegen_insert_memo(p, _start_mark, _loop1_87_type, _seq); D(p->level--); return _seq; } -// _loop1_90: ('or' conjunction) +// _loop1_88: ('or' conjunction) static asdl_seq * -_loop1_90_rule(Parser *p) +_loop1_88_rule(Parser *p) { D(p->level++); if (p->error_indicator) { @@ -21115,13 +20950,13 @@ _loop1_90_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _loop1_90[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('or' conjunction)")); - void *_tmp_145_var; + D(fprintf(stderr, "%*c> _loop1_88[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('or' conjunction)")); + void *_tmp_143_var; while ( - (_tmp_145_var = _tmp_145_rule(p)) // 'or' conjunction + (_tmp_143_var = _tmp_143_rule(p)) // 'or' conjunction ) { - _res = _tmp_145_var; + _res = _tmp_143_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -21137,7 +20972,7 @@ _loop1_90_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_90[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_88[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "('or' conjunction)")); } if (_n == 0 || p->error_indicator) { @@ -21155,14 +20990,14 @@ _loop1_90_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop1_90_type, _seq); + _PyPegen_insert_memo(p, _start_mark, _loop1_88_type, _seq); D(p->level--); return _seq; } -// _loop1_91: ('and' inversion) +// _loop1_89: ('and' inversion) static asdl_seq * -_loop1_91_rule(Parser *p) +_loop1_89_rule(Parser *p) { D(p->level++); if (p->error_indicator) { @@ -21186,13 +21021,13 @@ _loop1_91_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _loop1_91[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('and' inversion)")); - void *_tmp_146_var; + D(fprintf(stderr, "%*c> _loop1_89[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('and' inversion)")); + void *_tmp_144_var; while ( - (_tmp_146_var = _tmp_146_rule(p)) // 'and' inversion + (_tmp_144_var = _tmp_144_rule(p)) // 'and' inversion ) { - _res = _tmp_146_var; + _res = _tmp_144_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -21208,7 +21043,7 @@ _loop1_91_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_91[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_89[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "('and' inversion)")); } if (_n == 0 || p->error_indicator) { @@ -21226,14 +21061,14 @@ _loop1_91_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop1_91_type, _seq); + _PyPegen_insert_memo(p, _start_mark, _loop1_89_type, _seq); D(p->level--); return _seq; } -// _loop1_92: compare_op_bitwise_or_pair +// _loop1_90: compare_op_bitwise_or_pair static asdl_seq * -_loop1_92_rule(Parser *p) +_loop1_90_rule(Parser *p) { D(p->level++); if (p->error_indicator) { @@ -21257,7 +21092,7 @@ _loop1_92_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _loop1_92[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "compare_op_bitwise_or_pair")); + D(fprintf(stderr, "%*c> _loop1_90[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "compare_op_bitwise_or_pair")); CmpopExprPair* compare_op_bitwise_or_pair_var; while ( (compare_op_bitwise_or_pair_var = compare_op_bitwise_or_pair_rule(p)) // compare_op_bitwise_or_pair @@ -21279,7 +21114,7 @@ _loop1_92_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_92[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_90[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "compare_op_bitwise_or_pair")); } if (_n == 0 || p->error_indicator) { @@ -21297,14 +21132,14 @@ _loop1_92_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop1_92_type, _seq); + _PyPegen_insert_memo(p, _start_mark, _loop1_90_type, _seq); D(p->level--); return _seq; } -// _tmp_93: '!=' +// _tmp_91: '!=' static void * -_tmp_93_rule(Parser *p) +_tmp_91_rule(Parser *p) { D(p->level++); if (p->error_indicator) { @@ -21318,13 +21153,13 @@ _tmp_93_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _tmp_93[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'!='")); + D(fprintf(stderr, "%*c> _tmp_91[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'!='")); Token * tok; if ( (tok = _PyPegen_expect_token(p, 28)) // token='!=' ) { - D(fprintf(stderr, "%*c+ _tmp_93[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'!='")); + D(fprintf(stderr, "%*c+ _tmp_91[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'!='")); _res = _PyPegen_check_barry_as_flufl ( p , tok ) ? NULL : tok; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -21334,7 +21169,7 @@ _tmp_93_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_93[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_91[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'!='")); } _res = NULL; @@ -21343,9 +21178,9 @@ _tmp_93_rule(Parser *p) return _res; } -// _loop0_95: ',' slice +// _loop0_93: ',' slice static asdl_seq * -_loop0_95_rule(Parser *p) +_loop0_93_rule(Parser *p) { D(p->level++); if (p->error_indicator) { @@ -21369,7 +21204,7 @@ _loop0_95_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _loop0_95[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' slice")); + D(fprintf(stderr, "%*c> _loop0_93[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' slice")); Token * _literal; expr_ty elem; while ( @@ -21400,7 +21235,7 @@ _loop0_95_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_95[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_93[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' slice")); } asdl_seq *_seq = _Py_asdl_seq_new(_n, p->arena); @@ -21413,14 +21248,14 @@ _loop0_95_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_95_type, _seq); + _PyPegen_insert_memo(p, _start_mark, _loop0_93_type, _seq); D(p->level--); return _seq; } -// _gather_94: slice _loop0_95 +// _gather_92: slice _loop0_93 static asdl_seq * -_gather_94_rule(Parser *p) +_gather_92_rule(Parser *p) { D(p->level++); if (p->error_indicator) { @@ -21429,27 +21264,27 @@ _gather_94_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // slice _loop0_95 + { // slice _loop0_93 if (p->error_indicator) { D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _gather_94[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "slice _loop0_95")); + D(fprintf(stderr, "%*c> _gather_92[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "slice _loop0_93")); expr_ty elem; asdl_seq * seq; if ( (elem = slice_rule(p)) // slice && - (seq = _loop0_95_rule(p)) // _loop0_95 + (seq = _loop0_93_rule(p)) // _loop0_93 ) { - D(fprintf(stderr, "%*c+ _gather_94[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "slice _loop0_95")); + D(fprintf(stderr, "%*c+ _gather_92[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "slice _loop0_93")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_94[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "slice _loop0_95")); + D(fprintf(stderr, "%*c%s _gather_92[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "slice _loop0_93")); } _res = NULL; done: @@ -21457,9 +21292,9 @@ _gather_94_rule(Parser *p) return _res; } -// _tmp_96: ':' expression? +// _tmp_94: ':' expression? static void * -_tmp_96_rule(Parser *p) +_tmp_94_rule(Parser *p) { D(p->level++); if (p->error_indicator) { @@ -21473,7 +21308,7 @@ _tmp_96_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _tmp_96[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':' expression?")); + D(fprintf(stderr, "%*c> _tmp_94[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':' expression?")); Token * _literal; void *d; if ( @@ -21482,7 +21317,7 @@ _tmp_96_rule(Parser *p) (d = expression_rule(p), 1) // expression? ) { - D(fprintf(stderr, "%*c+ _tmp_96[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':' expression?")); + D(fprintf(stderr, "%*c+ _tmp_94[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':' expression?")); _res = d; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -21492,7 +21327,7 @@ _tmp_96_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_96[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_94[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "':' expression?")); } _res = NULL; @@ -21501,9 +21336,9 @@ _tmp_96_rule(Parser *p) return _res; } -// _tmp_97: tuple | group | genexp +// _tmp_95: tuple | group | genexp static void * -_tmp_97_rule(Parser *p) +_tmp_95_rule(Parser *p) { D(p->level++); if (p->error_indicator) { @@ -21517,18 +21352,18 @@ _tmp_97_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _tmp_97[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "tuple")); + D(fprintf(stderr, "%*c> _tmp_95[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "tuple")); expr_ty tuple_var; if ( (tuple_var = tuple_rule(p)) // tuple ) { - D(fprintf(stderr, "%*c+ _tmp_97[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "tuple")); + D(fprintf(stderr, "%*c+ _tmp_95[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "tuple")); _res = tuple_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_97[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_95[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "tuple")); } { // group @@ -21536,18 +21371,18 @@ _tmp_97_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _tmp_97[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "group")); + D(fprintf(stderr, "%*c> _tmp_95[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "group")); expr_ty group_var; if ( (group_var = group_rule(p)) // group ) { - D(fprintf(stderr, "%*c+ _tmp_97[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "group")); + D(fprintf(stderr, "%*c+ _tmp_95[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "group")); _res = group_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_97[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_95[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "group")); } { // genexp @@ -21555,18 +21390,18 @@ _tmp_97_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _tmp_97[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "genexp")); + D(fprintf(stderr, "%*c> _tmp_95[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "genexp")); expr_ty genexp_var; if ( (genexp_var = genexp_rule(p)) // genexp ) { - D(fprintf(stderr, "%*c+ _tmp_97[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "genexp")); + D(fprintf(stderr, "%*c+ _tmp_95[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "genexp")); _res = genexp_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_97[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_95[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "genexp")); } _res = NULL; @@ -21575,9 +21410,9 @@ _tmp_97_rule(Parser *p) return _res; } -// _tmp_98: list | listcomp +// _tmp_96: list | listcomp static void * -_tmp_98_rule(Parser *p) +_tmp_96_rule(Parser *p) { D(p->level++); if (p->error_indicator) { @@ -21591,18 +21426,18 @@ _tmp_98_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _tmp_98[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "list")); + D(fprintf(stderr, "%*c> _tmp_96[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "list")); expr_ty list_var; if ( (list_var = list_rule(p)) // list ) { - D(fprintf(stderr, "%*c+ _tmp_98[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "list")); + D(fprintf(stderr, "%*c+ _tmp_96[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "list")); _res = list_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_98[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_96[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "list")); } { // listcomp @@ -21610,18 +21445,18 @@ _tmp_98_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _tmp_98[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "listcomp")); + D(fprintf(stderr, "%*c> _tmp_96[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "listcomp")); expr_ty listcomp_var; if ( (listcomp_var = listcomp_rule(p)) // listcomp ) { - D(fprintf(stderr, "%*c+ _tmp_98[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "listcomp")); + D(fprintf(stderr, "%*c+ _tmp_96[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "listcomp")); _res = listcomp_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_98[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_96[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "listcomp")); } _res = NULL; @@ -21630,9 +21465,9 @@ _tmp_98_rule(Parser *p) return _res; } -// _tmp_99: dict | set | dictcomp | setcomp +// _tmp_97: dict | set | dictcomp | setcomp static void * -_tmp_99_rule(Parser *p) +_tmp_97_rule(Parser *p) { D(p->level++); if (p->error_indicator) { @@ -21646,18 +21481,18 @@ _tmp_99_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _tmp_99[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "dict")); + D(fprintf(stderr, "%*c> _tmp_97[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "dict")); expr_ty dict_var; if ( (dict_var = dict_rule(p)) // dict ) { - D(fprintf(stderr, "%*c+ _tmp_99[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "dict")); + D(fprintf(stderr, "%*c+ _tmp_97[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "dict")); _res = dict_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_99[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_97[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "dict")); } { // set @@ -21665,18 +21500,18 @@ _tmp_99_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _tmp_99[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "set")); + D(fprintf(stderr, "%*c> _tmp_97[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "set")); expr_ty set_var; if ( (set_var = set_rule(p)) // set ) { - D(fprintf(stderr, "%*c+ _tmp_99[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "set")); + D(fprintf(stderr, "%*c+ _tmp_97[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "set")); _res = set_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_99[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_97[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "set")); } { // dictcomp @@ -21684,18 +21519,18 @@ _tmp_99_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _tmp_99[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "dictcomp")); + D(fprintf(stderr, "%*c> _tmp_97[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "dictcomp")); expr_ty dictcomp_var; if ( (dictcomp_var = dictcomp_rule(p)) // dictcomp ) { - D(fprintf(stderr, "%*c+ _tmp_99[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "dictcomp")); + D(fprintf(stderr, "%*c+ _tmp_97[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "dictcomp")); _res = dictcomp_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_99[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_97[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "dictcomp")); } { // setcomp @@ -21703,18 +21538,18 @@ _tmp_99_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _tmp_99[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "setcomp")); + D(fprintf(stderr, "%*c> _tmp_97[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "setcomp")); expr_ty setcomp_var; if ( (setcomp_var = setcomp_rule(p)) // setcomp ) { - D(fprintf(stderr, "%*c+ _tmp_99[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "setcomp")); + D(fprintf(stderr, "%*c+ _tmp_97[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "setcomp")); _res = setcomp_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_99[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_97[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "setcomp")); } _res = NULL; @@ -21723,9 +21558,9 @@ _tmp_99_rule(Parser *p) return _res; } -// _loop1_100: STRING +// _loop1_98: STRING static asdl_seq * -_loop1_100_rule(Parser *p) +_loop1_98_rule(Parser *p) { D(p->level++); if (p->error_indicator) { @@ -21749,7 +21584,7 @@ _loop1_100_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _loop1_100[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "STRING")); + D(fprintf(stderr, "%*c> _loop1_98[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "STRING")); expr_ty string_var; while ( (string_var = _PyPegen_string_token(p)) // STRING @@ -21771,7 +21606,7 @@ _loop1_100_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_100[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_98[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "STRING")); } if (_n == 0 || p->error_indicator) { @@ -21789,14 +21624,14 @@ _loop1_100_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop1_100_type, _seq); + _PyPegen_insert_memo(p, _start_mark, _loop1_98_type, _seq); D(p->level--); return _seq; } -// _tmp_101: star_named_expression ',' star_named_expressions? +// _tmp_99: star_named_expression ',' star_named_expressions? static void * -_tmp_101_rule(Parser *p) +_tmp_99_rule(Parser *p) { D(p->level++); if (p->error_indicator) { @@ -21810,7 +21645,7 @@ _tmp_101_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _tmp_101[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_named_expression ',' star_named_expressions?")); + D(fprintf(stderr, "%*c> _tmp_99[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_named_expression ',' star_named_expressions?")); Token * _literal; expr_ty y; void *z; @@ -21822,7 +21657,7 @@ _tmp_101_rule(Parser *p) (z = star_named_expressions_rule(p), 1) // star_named_expressions? ) { - D(fprintf(stderr, "%*c+ _tmp_101[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_named_expression ',' star_named_expressions?")); + D(fprintf(stderr, "%*c+ _tmp_99[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_named_expression ',' star_named_expressions?")); _res = _PyPegen_seq_insert_in_front ( p , y , z ); if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -21832,7 +21667,7 @@ _tmp_101_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_101[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_99[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_named_expression ',' star_named_expressions?")); } _res = NULL; @@ -21841,9 +21676,9 @@ _tmp_101_rule(Parser *p) return _res; } -// _tmp_102: yield_expr | named_expression +// _tmp_100: yield_expr | named_expression static void * -_tmp_102_rule(Parser *p) +_tmp_100_rule(Parser *p) { D(p->level++); if (p->error_indicator) { @@ -21857,18 +21692,18 @@ _tmp_102_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _tmp_102[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "yield_expr")); + D(fprintf(stderr, "%*c> _tmp_100[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "yield_expr")); expr_ty yield_expr_var; if ( (yield_expr_var = yield_expr_rule(p)) // yield_expr ) { - D(fprintf(stderr, "%*c+ _tmp_102[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "yield_expr")); + D(fprintf(stderr, "%*c+ _tmp_100[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "yield_expr")); _res = yield_expr_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_102[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_100[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "yield_expr")); } { // named_expression @@ -21876,18 +21711,18 @@ _tmp_102_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _tmp_102[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "named_expression")); + D(fprintf(stderr, "%*c> _tmp_100[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "named_expression")); expr_ty named_expression_var; if ( (named_expression_var = named_expression_rule(p)) // named_expression ) { - D(fprintf(stderr, "%*c+ _tmp_102[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "named_expression")); + D(fprintf(stderr, "%*c+ _tmp_100[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "named_expression")); _res = named_expression_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_102[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_100[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "named_expression")); } _res = NULL; @@ -21896,9 +21731,9 @@ _tmp_102_rule(Parser *p) return _res; } -// _loop0_104: ',' double_starred_kvpair +// _loop0_102: ',' double_starred_kvpair static asdl_seq * -_loop0_104_rule(Parser *p) +_loop0_102_rule(Parser *p) { D(p->level++); if (p->error_indicator) { @@ -21922,7 +21757,7 @@ _loop0_104_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _loop0_104[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' double_starred_kvpair")); + D(fprintf(stderr, "%*c> _loop0_102[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' double_starred_kvpair")); Token * _literal; KeyValuePair* elem; while ( @@ -21953,7 +21788,7 @@ _loop0_104_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_104[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_102[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' double_starred_kvpair")); } asdl_seq *_seq = _Py_asdl_seq_new(_n, p->arena); @@ -21966,14 +21801,14 @@ _loop0_104_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_104_type, _seq); + _PyPegen_insert_memo(p, _start_mark, _loop0_102_type, _seq); D(p->level--); return _seq; } -// _gather_103: double_starred_kvpair _loop0_104 +// _gather_101: double_starred_kvpair _loop0_102 static asdl_seq * -_gather_103_rule(Parser *p) +_gather_101_rule(Parser *p) { D(p->level++); if (p->error_indicator) { @@ -21982,27 +21817,27 @@ _gather_103_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // double_starred_kvpair _loop0_104 + { // double_starred_kvpair _loop0_102 if (p->error_indicator) { D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _gather_103[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "double_starred_kvpair _loop0_104")); + D(fprintf(stderr, "%*c> _gather_101[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "double_starred_kvpair _loop0_102")); KeyValuePair* elem; asdl_seq * seq; if ( (elem = double_starred_kvpair_rule(p)) // double_starred_kvpair && - (seq = _loop0_104_rule(p)) // _loop0_104 + (seq = _loop0_102_rule(p)) // _loop0_102 ) { - D(fprintf(stderr, "%*c+ _gather_103[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "double_starred_kvpair _loop0_104")); + D(fprintf(stderr, "%*c+ _gather_101[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "double_starred_kvpair _loop0_102")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_103[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "double_starred_kvpair _loop0_104")); + D(fprintf(stderr, "%*c%s _gather_101[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "double_starred_kvpair _loop0_102")); } _res = NULL; done: @@ -22010,9 +21845,9 @@ _gather_103_rule(Parser *p) return _res; } -// _loop1_105: for_if_clause +// _loop1_103: for_if_clause static asdl_seq * -_loop1_105_rule(Parser *p) +_loop1_103_rule(Parser *p) { D(p->level++); if (p->error_indicator) { @@ -22036,7 +21871,7 @@ _loop1_105_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _loop1_105[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "for_if_clause")); + D(fprintf(stderr, "%*c> _loop1_103[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "for_if_clause")); comprehension_ty for_if_clause_var; while ( (for_if_clause_var = for_if_clause_rule(p)) // for_if_clause @@ -22058,7 +21893,7 @@ _loop1_105_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_105[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_103[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "for_if_clause")); } if (_n == 0 || p->error_indicator) { @@ -22076,14 +21911,14 @@ _loop1_105_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop1_105_type, _seq); + _PyPegen_insert_memo(p, _start_mark, _loop1_103_type, _seq); D(p->level--); return _seq; } -// _loop0_106: ('if' disjunction) +// _loop0_104: ('if' disjunction) static asdl_seq * -_loop0_106_rule(Parser *p) +_loop0_104_rule(Parser *p) { D(p->level++); if (p->error_indicator) { @@ -22107,13 +21942,13 @@ _loop0_106_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _loop0_106[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('if' disjunction)")); - void *_tmp_147_var; + D(fprintf(stderr, "%*c> _loop0_104[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('if' disjunction)")); + void *_tmp_145_var; while ( - (_tmp_147_var = _tmp_147_rule(p)) // 'if' disjunction + (_tmp_145_var = _tmp_145_rule(p)) // 'if' disjunction ) { - _res = _tmp_147_var; + _res = _tmp_145_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -22129,7 +21964,7 @@ _loop0_106_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_106[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_104[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "('if' disjunction)")); } asdl_seq *_seq = _Py_asdl_seq_new(_n, p->arena); @@ -22142,14 +21977,14 @@ _loop0_106_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_106_type, _seq); + _PyPegen_insert_memo(p, _start_mark, _loop0_104_type, _seq); D(p->level--); return _seq; } -// _loop0_107: ('if' disjunction) +// _loop0_105: ('if' disjunction) static asdl_seq * -_loop0_107_rule(Parser *p) +_loop0_105_rule(Parser *p) { D(p->level++); if (p->error_indicator) { @@ -22173,13 +22008,13 @@ _loop0_107_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _loop0_107[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('if' disjunction)")); - void *_tmp_148_var; + D(fprintf(stderr, "%*c> _loop0_105[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('if' disjunction)")); + void *_tmp_146_var; while ( - (_tmp_148_var = _tmp_148_rule(p)) // 'if' disjunction + (_tmp_146_var = _tmp_146_rule(p)) // 'if' disjunction ) { - _res = _tmp_148_var; + _res = _tmp_146_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -22195,7 +22030,7 @@ _loop0_107_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_107[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_105[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "('if' disjunction)")); } asdl_seq *_seq = _Py_asdl_seq_new(_n, p->arena); @@ -22208,14 +22043,14 @@ _loop0_107_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_107_type, _seq); + _PyPegen_insert_memo(p, _start_mark, _loop0_105_type, _seq); D(p->level--); return _seq; } -// _loop0_109: ',' (starred_expression | named_expression !'=') +// _loop0_107: ',' (starred_expression | named_expression !'=') static asdl_seq * -_loop0_109_rule(Parser *p) +_loop0_107_rule(Parser *p) { D(p->level++); if (p->error_indicator) { @@ -22239,13 +22074,13 @@ _loop0_109_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _loop0_109[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (starred_expression | named_expression !'=')")); + D(fprintf(stderr, "%*c> _loop0_107[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (starred_expression | named_expression !'=')")); Token * _literal; void *elem; while ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' && - (elem = _tmp_149_rule(p)) // starred_expression | named_expression !'=' + (elem = _tmp_147_rule(p)) // starred_expression | named_expression !'=' ) { _res = elem; @@ -22270,7 +22105,7 @@ _loop0_109_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_109[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_107[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' (starred_expression | named_expression !'=')")); } asdl_seq *_seq = _Py_asdl_seq_new(_n, p->arena); @@ -22283,14 +22118,14 @@ _loop0_109_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_109_type, _seq); + _PyPegen_insert_memo(p, _start_mark, _loop0_107_type, _seq); D(p->level--); return _seq; } -// _gather_108: (starred_expression | named_expression !'=') _loop0_109 +// _gather_106: (starred_expression | named_expression !'=') _loop0_107 static asdl_seq * -_gather_108_rule(Parser *p) +_gather_106_rule(Parser *p) { D(p->level++); if (p->error_indicator) { @@ -22299,27 +22134,27 @@ _gather_108_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // (starred_expression | named_expression !'=') _loop0_109 + { // (starred_expression | named_expression !'=') _loop0_107 if (p->error_indicator) { D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _gather_108[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(starred_expression | named_expression !'=') _loop0_109")); + D(fprintf(stderr, "%*c> _gather_106[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(starred_expression | named_expression !'=') _loop0_107")); void *elem; asdl_seq * seq; if ( - (elem = _tmp_149_rule(p)) // starred_expression | named_expression !'=' + (elem = _tmp_147_rule(p)) // starred_expression | named_expression !'=' && - (seq = _loop0_109_rule(p)) // _loop0_109 + (seq = _loop0_107_rule(p)) // _loop0_107 ) { - D(fprintf(stderr, "%*c+ _gather_108[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(starred_expression | named_expression !'=') _loop0_109")); + D(fprintf(stderr, "%*c+ _gather_106[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(starred_expression | named_expression !'=') _loop0_107")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_108[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(starred_expression | named_expression !'=') _loop0_109")); + D(fprintf(stderr, "%*c%s _gather_106[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(starred_expression | named_expression !'=') _loop0_107")); } _res = NULL; done: @@ -22327,9 +22162,9 @@ _gather_108_rule(Parser *p) return _res; } -// _tmp_110: ',' kwargs +// _tmp_108: ',' kwargs static void * -_tmp_110_rule(Parser *p) +_tmp_108_rule(Parser *p) { D(p->level++); if (p->error_indicator) { @@ -22343,7 +22178,7 @@ _tmp_110_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _tmp_110[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' kwargs")); + D(fprintf(stderr, "%*c> _tmp_108[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' kwargs")); Token * _literal; asdl_seq* k; if ( @@ -22352,7 +22187,7 @@ _tmp_110_rule(Parser *p) (k = kwargs_rule(p)) // kwargs ) { - D(fprintf(stderr, "%*c+ _tmp_110[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' kwargs")); + D(fprintf(stderr, "%*c+ _tmp_108[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' kwargs")); _res = k; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -22362,7 +22197,7 @@ _tmp_110_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_110[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_108[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' kwargs")); } _res = NULL; @@ -22371,9 +22206,9 @@ _tmp_110_rule(Parser *p) return _res; } -// _loop0_112: ',' kwarg_or_starred +// _loop0_110: ',' kwarg_or_starred static asdl_seq * -_loop0_112_rule(Parser *p) +_loop0_110_rule(Parser *p) { D(p->level++); if (p->error_indicator) { @@ -22397,7 +22232,7 @@ _loop0_112_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _loop0_112[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' kwarg_or_starred")); + D(fprintf(stderr, "%*c> _loop0_110[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' kwarg_or_starred")); Token * _literal; KeywordOrStarred* elem; while ( @@ -22428,7 +22263,7 @@ _loop0_112_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_112[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_110[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' kwarg_or_starred")); } asdl_seq *_seq = _Py_asdl_seq_new(_n, p->arena); @@ -22441,14 +22276,14 @@ _loop0_112_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_112_type, _seq); + _PyPegen_insert_memo(p, _start_mark, _loop0_110_type, _seq); D(p->level--); return _seq; } -// _gather_111: kwarg_or_starred _loop0_112 +// _gather_109: kwarg_or_starred _loop0_110 static asdl_seq * -_gather_111_rule(Parser *p) +_gather_109_rule(Parser *p) { D(p->level++); if (p->error_indicator) { @@ -22457,27 +22292,27 @@ _gather_111_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // kwarg_or_starred _loop0_112 + { // kwarg_or_starred _loop0_110 if (p->error_indicator) { D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _gather_111[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "kwarg_or_starred _loop0_112")); + D(fprintf(stderr, "%*c> _gather_109[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "kwarg_or_starred _loop0_110")); KeywordOrStarred* elem; asdl_seq * seq; if ( (elem = kwarg_or_starred_rule(p)) // kwarg_or_starred && - (seq = _loop0_112_rule(p)) // _loop0_112 + (seq = _loop0_110_rule(p)) // _loop0_110 ) { - D(fprintf(stderr, "%*c+ _gather_111[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "kwarg_or_starred _loop0_112")); + D(fprintf(stderr, "%*c+ _gather_109[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "kwarg_or_starred _loop0_110")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_111[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "kwarg_or_starred _loop0_112")); + D(fprintf(stderr, "%*c%s _gather_109[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "kwarg_or_starred _loop0_110")); } _res = NULL; done: @@ -22485,9 +22320,9 @@ _gather_111_rule(Parser *p) return _res; } -// _loop0_114: ',' kwarg_or_double_starred +// _loop0_112: ',' kwarg_or_double_starred static asdl_seq * -_loop0_114_rule(Parser *p) +_loop0_112_rule(Parser *p) { D(p->level++); if (p->error_indicator) { @@ -22511,7 +22346,7 @@ _loop0_114_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _loop0_114[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' kwarg_or_double_starred")); + D(fprintf(stderr, "%*c> _loop0_112[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' kwarg_or_double_starred")); Token * _literal; KeywordOrStarred* elem; while ( @@ -22542,7 +22377,7 @@ _loop0_114_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_114[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_112[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' kwarg_or_double_starred")); } asdl_seq *_seq = _Py_asdl_seq_new(_n, p->arena); @@ -22555,14 +22390,14 @@ _loop0_114_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_114_type, _seq); + _PyPegen_insert_memo(p, _start_mark, _loop0_112_type, _seq); D(p->level--); return _seq; } -// _gather_113: kwarg_or_double_starred _loop0_114 +// _gather_111: kwarg_or_double_starred _loop0_112 static asdl_seq * -_gather_113_rule(Parser *p) +_gather_111_rule(Parser *p) { D(p->level++); if (p->error_indicator) { @@ -22571,27 +22406,27 @@ _gather_113_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // kwarg_or_double_starred _loop0_114 + { // kwarg_or_double_starred _loop0_112 if (p->error_indicator) { D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _gather_113[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "kwarg_or_double_starred _loop0_114")); + D(fprintf(stderr, "%*c> _gather_111[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "kwarg_or_double_starred _loop0_112")); KeywordOrStarred* elem; asdl_seq * seq; if ( (elem = kwarg_or_double_starred_rule(p)) // kwarg_or_double_starred && - (seq = _loop0_114_rule(p)) // _loop0_114 + (seq = _loop0_112_rule(p)) // _loop0_112 ) { - D(fprintf(stderr, "%*c+ _gather_113[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "kwarg_or_double_starred _loop0_114")); + D(fprintf(stderr, "%*c+ _gather_111[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "kwarg_or_double_starred _loop0_112")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_113[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "kwarg_or_double_starred _loop0_114")); + D(fprintf(stderr, "%*c%s _gather_111[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "kwarg_or_double_starred _loop0_112")); } _res = NULL; done: @@ -22599,9 +22434,9 @@ _gather_113_rule(Parser *p) return _res; } -// _loop0_116: ',' kwarg_or_starred +// _loop0_114: ',' kwarg_or_starred static asdl_seq * -_loop0_116_rule(Parser *p) +_loop0_114_rule(Parser *p) { D(p->level++); if (p->error_indicator) { @@ -22625,7 +22460,7 @@ _loop0_116_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _loop0_116[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' kwarg_or_starred")); + D(fprintf(stderr, "%*c> _loop0_114[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' kwarg_or_starred")); Token * _literal; KeywordOrStarred* elem; while ( @@ -22656,7 +22491,7 @@ _loop0_116_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_116[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_114[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' kwarg_or_starred")); } asdl_seq *_seq = _Py_asdl_seq_new(_n, p->arena); @@ -22669,14 +22504,14 @@ _loop0_116_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_116_type, _seq); + _PyPegen_insert_memo(p, _start_mark, _loop0_114_type, _seq); D(p->level--); return _seq; } -// _gather_115: kwarg_or_starred _loop0_116 +// _gather_113: kwarg_or_starred _loop0_114 static asdl_seq * -_gather_115_rule(Parser *p) +_gather_113_rule(Parser *p) { D(p->level++); if (p->error_indicator) { @@ -22685,27 +22520,27 @@ _gather_115_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // kwarg_or_starred _loop0_116 + { // kwarg_or_starred _loop0_114 if (p->error_indicator) { D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _gather_115[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "kwarg_or_starred _loop0_116")); + D(fprintf(stderr, "%*c> _gather_113[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "kwarg_or_starred _loop0_114")); KeywordOrStarred* elem; asdl_seq * seq; if ( (elem = kwarg_or_starred_rule(p)) // kwarg_or_starred && - (seq = _loop0_116_rule(p)) // _loop0_116 + (seq = _loop0_114_rule(p)) // _loop0_114 ) { - D(fprintf(stderr, "%*c+ _gather_115[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "kwarg_or_starred _loop0_116")); + D(fprintf(stderr, "%*c+ _gather_113[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "kwarg_or_starred _loop0_114")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_115[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "kwarg_or_starred _loop0_116")); + D(fprintf(stderr, "%*c%s _gather_113[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "kwarg_or_starred _loop0_114")); } _res = NULL; done: @@ -22713,9 +22548,9 @@ _gather_115_rule(Parser *p) return _res; } -// _loop0_118: ',' kwarg_or_double_starred +// _loop0_116: ',' kwarg_or_double_starred static asdl_seq * -_loop0_118_rule(Parser *p) +_loop0_116_rule(Parser *p) { D(p->level++); if (p->error_indicator) { @@ -22739,7 +22574,7 @@ _loop0_118_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _loop0_118[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' kwarg_or_double_starred")); + D(fprintf(stderr, "%*c> _loop0_116[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' kwarg_or_double_starred")); Token * _literal; KeywordOrStarred* elem; while ( @@ -22770,7 +22605,7 @@ _loop0_118_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_118[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_116[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' kwarg_or_double_starred")); } asdl_seq *_seq = _Py_asdl_seq_new(_n, p->arena); @@ -22783,14 +22618,14 @@ _loop0_118_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_118_type, _seq); + _PyPegen_insert_memo(p, _start_mark, _loop0_116_type, _seq); D(p->level--); return _seq; } -// _gather_117: kwarg_or_double_starred _loop0_118 +// _gather_115: kwarg_or_double_starred _loop0_116 static asdl_seq * -_gather_117_rule(Parser *p) +_gather_115_rule(Parser *p) { D(p->level++); if (p->error_indicator) { @@ -22799,27 +22634,27 @@ _gather_117_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // kwarg_or_double_starred _loop0_118 + { // kwarg_or_double_starred _loop0_116 if (p->error_indicator) { D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _gather_117[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "kwarg_or_double_starred _loop0_118")); + D(fprintf(stderr, "%*c> _gather_115[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "kwarg_or_double_starred _loop0_116")); KeywordOrStarred* elem; asdl_seq * seq; if ( (elem = kwarg_or_double_starred_rule(p)) // kwarg_or_double_starred && - (seq = _loop0_118_rule(p)) // _loop0_118 + (seq = _loop0_116_rule(p)) // _loop0_116 ) { - D(fprintf(stderr, "%*c+ _gather_117[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "kwarg_or_double_starred _loop0_118")); + D(fprintf(stderr, "%*c+ _gather_115[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "kwarg_or_double_starred _loop0_116")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_117[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "kwarg_or_double_starred _loop0_118")); + D(fprintf(stderr, "%*c%s _gather_115[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "kwarg_or_double_starred _loop0_116")); } _res = NULL; done: @@ -22827,9 +22662,9 @@ _gather_117_rule(Parser *p) return _res; } -// _loop0_119: (',' star_target) +// _loop0_117: (',' star_target) static asdl_seq * -_loop0_119_rule(Parser *p) +_loop0_117_rule(Parser *p) { D(p->level++); if (p->error_indicator) { @@ -22853,13 +22688,13 @@ _loop0_119_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _loop0_119[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(',' star_target)")); - void *_tmp_150_var; + D(fprintf(stderr, "%*c> _loop0_117[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(',' star_target)")); + void *_tmp_148_var; while ( - (_tmp_150_var = _tmp_150_rule(p)) // ',' star_target + (_tmp_148_var = _tmp_148_rule(p)) // ',' star_target ) { - _res = _tmp_150_var; + _res = _tmp_148_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -22875,7 +22710,7 @@ _loop0_119_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_119[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_117[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(',' star_target)")); } asdl_seq *_seq = _Py_asdl_seq_new(_n, p->arena); @@ -22888,14 +22723,14 @@ _loop0_119_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_119_type, _seq); + _PyPegen_insert_memo(p, _start_mark, _loop0_117_type, _seq); D(p->level--); return _seq; } -// _loop0_121: ',' star_target +// _loop0_119: ',' star_target static asdl_seq * -_loop0_121_rule(Parser *p) +_loop0_119_rule(Parser *p) { D(p->level++); if (p->error_indicator) { @@ -22919,7 +22754,7 @@ _loop0_121_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _loop0_121[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' star_target")); + D(fprintf(stderr, "%*c> _loop0_119[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' star_target")); Token * _literal; expr_ty elem; while ( @@ -22950,7 +22785,7 @@ _loop0_121_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_121[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_119[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' star_target")); } asdl_seq *_seq = _Py_asdl_seq_new(_n, p->arena); @@ -22963,14 +22798,14 @@ _loop0_121_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_121_type, _seq); + _PyPegen_insert_memo(p, _start_mark, _loop0_119_type, _seq); D(p->level--); return _seq; } -// _gather_120: star_target _loop0_121 +// _gather_118: star_target _loop0_119 static asdl_seq * -_gather_120_rule(Parser *p) +_gather_118_rule(Parser *p) { D(p->level++); if (p->error_indicator) { @@ -22979,27 +22814,27 @@ _gather_120_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // star_target _loop0_121 + { // star_target _loop0_119 if (p->error_indicator) { D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _gather_120[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_target _loop0_121")); + D(fprintf(stderr, "%*c> _gather_118[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_target _loop0_119")); expr_ty elem; asdl_seq * seq; if ( (elem = star_target_rule(p)) // star_target && - (seq = _loop0_121_rule(p)) // _loop0_121 + (seq = _loop0_119_rule(p)) // _loop0_119 ) { - D(fprintf(stderr, "%*c+ _gather_120[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_target _loop0_121")); + D(fprintf(stderr, "%*c+ _gather_118[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_target _loop0_119")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_120[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_target _loop0_121")); + D(fprintf(stderr, "%*c%s _gather_118[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_target _loop0_119")); } _res = NULL; done: @@ -23007,9 +22842,9 @@ _gather_120_rule(Parser *p) return _res; } -// _tmp_122: !'*' star_target +// _tmp_120: !'*' star_target static void * -_tmp_122_rule(Parser *p) +_tmp_120_rule(Parser *p) { D(p->level++); if (p->error_indicator) { @@ -23023,7 +22858,7 @@ _tmp_122_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _tmp_122[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "!'*' star_target")); + D(fprintf(stderr, "%*c> _tmp_120[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "!'*' star_target")); expr_ty star_target_var; if ( _PyPegen_lookahead_with_int(0, _PyPegen_expect_token, p, 16) // token='*' @@ -23031,12 +22866,12 @@ _tmp_122_rule(Parser *p) (star_target_var = star_target_rule(p)) // star_target ) { - D(fprintf(stderr, "%*c+ _tmp_122[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "!'*' star_target")); + D(fprintf(stderr, "%*c+ _tmp_120[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "!'*' star_target")); _res = star_target_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_122[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_120[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "!'*' star_target")); } _res = NULL; @@ -23045,9 +22880,9 @@ _tmp_122_rule(Parser *p) return _res; } -// _loop0_124: ',' del_target +// _loop0_122: ',' del_target static asdl_seq * -_loop0_124_rule(Parser *p) +_loop0_122_rule(Parser *p) { D(p->level++); if (p->error_indicator) { @@ -23071,7 +22906,7 @@ _loop0_124_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _loop0_124[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' del_target")); + D(fprintf(stderr, "%*c> _loop0_122[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' del_target")); Token * _literal; expr_ty elem; while ( @@ -23102,7 +22937,7 @@ _loop0_124_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_124[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_122[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' del_target")); } asdl_seq *_seq = _Py_asdl_seq_new(_n, p->arena); @@ -23115,14 +22950,14 @@ _loop0_124_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_124_type, _seq); + _PyPegen_insert_memo(p, _start_mark, _loop0_122_type, _seq); D(p->level--); return _seq; } -// _gather_123: del_target _loop0_124 +// _gather_121: del_target _loop0_122 static asdl_seq * -_gather_123_rule(Parser *p) +_gather_121_rule(Parser *p) { D(p->level++); if (p->error_indicator) { @@ -23131,27 +22966,27 @@ _gather_123_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // del_target _loop0_124 + { // del_target _loop0_122 if (p->error_indicator) { D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _gather_123[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "del_target _loop0_124")); + D(fprintf(stderr, "%*c> _gather_121[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "del_target _loop0_122")); expr_ty elem; asdl_seq * seq; if ( (elem = del_target_rule(p)) // del_target && - (seq = _loop0_124_rule(p)) // _loop0_124 + (seq = _loop0_122_rule(p)) // _loop0_122 ) { - D(fprintf(stderr, "%*c+ _gather_123[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "del_target _loop0_124")); + D(fprintf(stderr, "%*c+ _gather_121[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "del_target _loop0_122")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_123[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "del_target _loop0_124")); + D(fprintf(stderr, "%*c%s _gather_121[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "del_target _loop0_122")); } _res = NULL; done: @@ -23159,9 +22994,9 @@ _gather_123_rule(Parser *p) return _res; } -// _loop0_126: ',' target +// _loop0_124: ',' target static asdl_seq * -_loop0_126_rule(Parser *p) +_loop0_124_rule(Parser *p) { D(p->level++); if (p->error_indicator) { @@ -23185,7 +23020,7 @@ _loop0_126_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _loop0_126[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' target")); + D(fprintf(stderr, "%*c> _loop0_124[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' target")); Token * _literal; expr_ty elem; while ( @@ -23216,7 +23051,7 @@ _loop0_126_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_126[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_124[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' target")); } asdl_seq *_seq = _Py_asdl_seq_new(_n, p->arena); @@ -23229,14 +23064,14 @@ _loop0_126_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_126_type, _seq); + _PyPegen_insert_memo(p, _start_mark, _loop0_124_type, _seq); D(p->level--); return _seq; } -// _gather_125: target _loop0_126 +// _gather_123: target _loop0_124 static asdl_seq * -_gather_125_rule(Parser *p) +_gather_123_rule(Parser *p) { D(p->level++); if (p->error_indicator) { @@ -23245,27 +23080,27 @@ _gather_125_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // target _loop0_126 + { // target _loop0_124 if (p->error_indicator) { D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _gather_125[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "target _loop0_126")); + D(fprintf(stderr, "%*c> _gather_123[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "target _loop0_124")); expr_ty elem; asdl_seq * seq; if ( (elem = target_rule(p)) // target && - (seq = _loop0_126_rule(p)) // _loop0_126 + (seq = _loop0_124_rule(p)) // _loop0_124 ) { - D(fprintf(stderr, "%*c+ _gather_125[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "target _loop0_126")); + D(fprintf(stderr, "%*c+ _gather_123[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "target _loop0_124")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_125[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "target _loop0_126")); + D(fprintf(stderr, "%*c%s _gather_123[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "target _loop0_124")); } _res = NULL; done: @@ -23273,9 +23108,9 @@ _gather_125_rule(Parser *p) return _res; } -// _tmp_127: args | expression for_if_clauses +// _tmp_125: args | expression for_if_clauses static void * -_tmp_127_rule(Parser *p) +_tmp_125_rule(Parser *p) { D(p->level++); if (p->error_indicator) { @@ -23289,18 +23124,18 @@ _tmp_127_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _tmp_127[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "args")); + D(fprintf(stderr, "%*c> _tmp_125[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "args")); expr_ty args_var; if ( (args_var = args_rule(p)) // args ) { - D(fprintf(stderr, "%*c+ _tmp_127[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "args")); + D(fprintf(stderr, "%*c+ _tmp_125[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "args")); _res = args_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_127[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_125[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "args")); } { // expression for_if_clauses @@ -23308,7 +23143,7 @@ _tmp_127_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _tmp_127[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression for_if_clauses")); + D(fprintf(stderr, "%*c> _tmp_125[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression for_if_clauses")); expr_ty expression_var; asdl_seq* for_if_clauses_var; if ( @@ -23317,12 +23152,12 @@ _tmp_127_rule(Parser *p) (for_if_clauses_var = for_if_clauses_rule(p)) // for_if_clauses ) { - D(fprintf(stderr, "%*c+ _tmp_127[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression for_if_clauses")); + D(fprintf(stderr, "%*c+ _tmp_125[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression for_if_clauses")); _res = _PyPegen_dummy_name(p, expression_var, for_if_clauses_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_127[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_125[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "expression for_if_clauses")); } _res = NULL; @@ -23331,9 +23166,9 @@ _tmp_127_rule(Parser *p) return _res; } -// _loop0_128: star_named_expressions +// _loop0_126: star_named_expressions static asdl_seq * -_loop0_128_rule(Parser *p) +_loop0_126_rule(Parser *p) { D(p->level++); if (p->error_indicator) { @@ -23357,7 +23192,7 @@ _loop0_128_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _loop0_128[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_named_expressions")); + D(fprintf(stderr, "%*c> _loop0_126[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_named_expressions")); asdl_seq* star_named_expressions_var; while ( (star_named_expressions_var = star_named_expressions_rule(p)) // star_named_expressions @@ -23379,7 +23214,7 @@ _loop0_128_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_128[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_126[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_named_expressions")); } asdl_seq *_seq = _Py_asdl_seq_new(_n, p->arena); @@ -23392,14 +23227,14 @@ _loop0_128_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_128_type, _seq); + _PyPegen_insert_memo(p, _start_mark, _loop0_126_type, _seq); D(p->level--); return _seq; } -// _loop0_129: (star_targets '=') +// _loop0_127: (star_targets '=') static asdl_seq * -_loop0_129_rule(Parser *p) +_loop0_127_rule(Parser *p) { D(p->level++); if (p->error_indicator) { @@ -23423,13 +23258,13 @@ _loop0_129_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _loop0_129[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(star_targets '=')")); - void *_tmp_151_var; + D(fprintf(stderr, "%*c> _loop0_127[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(star_targets '=')")); + void *_tmp_149_var; while ( - (_tmp_151_var = _tmp_151_rule(p)) // star_targets '=' + (_tmp_149_var = _tmp_149_rule(p)) // star_targets '=' ) { - _res = _tmp_151_var; + _res = _tmp_149_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -23445,7 +23280,7 @@ _loop0_129_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_129[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_127[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(star_targets '=')")); } asdl_seq *_seq = _Py_asdl_seq_new(_n, p->arena); @@ -23458,14 +23293,14 @@ _loop0_129_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_129_type, _seq); + _PyPegen_insert_memo(p, _start_mark, _loop0_127_type, _seq); D(p->level--); return _seq; } -// _loop0_130: (star_targets '=') +// _loop0_128: (star_targets '=') static asdl_seq * -_loop0_130_rule(Parser *p) +_loop0_128_rule(Parser *p) { D(p->level++); if (p->error_indicator) { @@ -23489,13 +23324,13 @@ _loop0_130_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _loop0_130[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(star_targets '=')")); - void *_tmp_152_var; + D(fprintf(stderr, "%*c> _loop0_128[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(star_targets '=')")); + void *_tmp_150_var; while ( - (_tmp_152_var = _tmp_152_rule(p)) // star_targets '=' + (_tmp_150_var = _tmp_150_rule(p)) // star_targets '=' ) { - _res = _tmp_152_var; + _res = _tmp_150_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -23511,7 +23346,7 @@ _loop0_130_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_130[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_128[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(star_targets '=')")); } asdl_seq *_seq = _Py_asdl_seq_new(_n, p->arena); @@ -23524,14 +23359,14 @@ _loop0_130_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_130_type, _seq); + _PyPegen_insert_memo(p, _start_mark, _loop0_128_type, _seq); D(p->level--); return _seq; } -// _tmp_131: yield_expr | star_expressions +// _tmp_129: yield_expr | star_expressions static void * -_tmp_131_rule(Parser *p) +_tmp_129_rule(Parser *p) { D(p->level++); if (p->error_indicator) { @@ -23545,18 +23380,18 @@ _tmp_131_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _tmp_131[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "yield_expr")); + D(fprintf(stderr, "%*c> _tmp_129[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "yield_expr")); expr_ty yield_expr_var; if ( (yield_expr_var = yield_expr_rule(p)) // yield_expr ) { - D(fprintf(stderr, "%*c+ _tmp_131[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "yield_expr")); + D(fprintf(stderr, "%*c+ _tmp_129[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "yield_expr")); _res = yield_expr_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_131[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_129[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "yield_expr")); } { // star_expressions @@ -23564,18 +23399,18 @@ _tmp_131_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _tmp_131[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_expressions")); + D(fprintf(stderr, "%*c> _tmp_129[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_expressions")); expr_ty star_expressions_var; if ( (star_expressions_var = star_expressions_rule(p)) // star_expressions ) { - D(fprintf(stderr, "%*c+ _tmp_131[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_expressions")); + D(fprintf(stderr, "%*c+ _tmp_129[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_expressions")); _res = star_expressions_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_131[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_129[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_expressions")); } _res = NULL; @@ -23584,9 +23419,9 @@ _tmp_131_rule(Parser *p) return _res; } -// _tmp_132: '[' | '(' | '{' +// _tmp_130: '[' | '(' | '{' static void * -_tmp_132_rule(Parser *p) +_tmp_130_rule(Parser *p) { D(p->level++); if (p->error_indicator) { @@ -23600,18 +23435,18 @@ _tmp_132_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _tmp_132[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'['")); + D(fprintf(stderr, "%*c> _tmp_130[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'['")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 9)) // token='[' ) { - D(fprintf(stderr, "%*c+ _tmp_132[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'['")); + D(fprintf(stderr, "%*c+ _tmp_130[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'['")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_132[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_130[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'['")); } { // '(' @@ -23619,18 +23454,18 @@ _tmp_132_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _tmp_132[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'('")); + D(fprintf(stderr, "%*c> _tmp_130[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'('")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 7)) // token='(' ) { - D(fprintf(stderr, "%*c+ _tmp_132[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'('")); + D(fprintf(stderr, "%*c+ _tmp_130[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'('")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_132[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_130[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'('")); } { // '{' @@ -23638,18 +23473,18 @@ _tmp_132_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _tmp_132[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'{'")); + D(fprintf(stderr, "%*c> _tmp_130[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'{'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 25)) // token='{' ) { - D(fprintf(stderr, "%*c+ _tmp_132[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'{'")); + D(fprintf(stderr, "%*c+ _tmp_130[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'{'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_132[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_130[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'{'")); } _res = NULL; @@ -23658,9 +23493,9 @@ _tmp_132_rule(Parser *p) return _res; } -// _loop0_133: param_no_default +// _loop0_131: param_no_default static asdl_seq * -_loop0_133_rule(Parser *p) +_loop0_131_rule(Parser *p) { D(p->level++); if (p->error_indicator) { @@ -23684,7 +23519,7 @@ _loop0_133_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _loop0_133[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_no_default")); + D(fprintf(stderr, "%*c> _loop0_131[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_no_default")); arg_ty param_no_default_var; while ( (param_no_default_var = param_no_default_rule(p)) // param_no_default @@ -23706,7 +23541,7 @@ _loop0_133_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_133[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_131[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "param_no_default")); } asdl_seq *_seq = _Py_asdl_seq_new(_n, p->arena); @@ -23719,14 +23554,14 @@ _loop0_133_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_133_type, _seq); + _PyPegen_insert_memo(p, _start_mark, _loop0_131_type, _seq); D(p->level--); return _seq; } -// _tmp_134: slash_with_default | param_with_default+ +// _tmp_132: slash_with_default | param_with_default+ static void * -_tmp_134_rule(Parser *p) +_tmp_132_rule(Parser *p) { D(p->level++); if (p->error_indicator) { @@ -23740,18 +23575,18 @@ _tmp_134_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _tmp_134[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "slash_with_default")); + D(fprintf(stderr, "%*c> _tmp_132[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "slash_with_default")); SlashWithDefault* slash_with_default_var; if ( (slash_with_default_var = slash_with_default_rule(p)) // slash_with_default ) { - D(fprintf(stderr, "%*c+ _tmp_134[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "slash_with_default")); + D(fprintf(stderr, "%*c+ _tmp_132[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "slash_with_default")); _res = slash_with_default_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_134[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_132[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "slash_with_default")); } { // param_with_default+ @@ -23759,18 +23594,18 @@ _tmp_134_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _tmp_134[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_with_default+")); - asdl_seq * _loop1_153_var; + D(fprintf(stderr, "%*c> _tmp_132[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_with_default+")); + asdl_seq * _loop1_151_var; if ( - (_loop1_153_var = _loop1_153_rule(p)) // param_with_default+ + (_loop1_151_var = _loop1_151_rule(p)) // param_with_default+ ) { - D(fprintf(stderr, "%*c+ _tmp_134[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "param_with_default+")); - _res = _loop1_153_var; + D(fprintf(stderr, "%*c+ _tmp_132[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "param_with_default+")); + _res = _loop1_151_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_134[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_132[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "param_with_default+")); } _res = NULL; @@ -23779,9 +23614,9 @@ _tmp_134_rule(Parser *p) return _res; } -// _loop0_135: lambda_param_no_default +// _loop0_133: lambda_param_no_default static asdl_seq * -_loop0_135_rule(Parser *p) +_loop0_133_rule(Parser *p) { D(p->level++); if (p->error_indicator) { @@ -23805,7 +23640,7 @@ _loop0_135_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _loop0_135[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default")); + D(fprintf(stderr, "%*c> _loop0_133[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default")); arg_ty lambda_param_no_default_var; while ( (lambda_param_no_default_var = lambda_param_no_default_rule(p)) // lambda_param_no_default @@ -23827,7 +23662,7 @@ _loop0_135_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_135[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_133[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_no_default")); } asdl_seq *_seq = _Py_asdl_seq_new(_n, p->arena); @@ -23840,14 +23675,14 @@ _loop0_135_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_135_type, _seq); + _PyPegen_insert_memo(p, _start_mark, _loop0_133_type, _seq); D(p->level--); return _seq; } -// _tmp_136: lambda_slash_with_default | lambda_param_with_default+ +// _tmp_134: lambda_slash_with_default | lambda_param_with_default+ static void * -_tmp_136_rule(Parser *p) +_tmp_134_rule(Parser *p) { D(p->level++); if (p->error_indicator) { @@ -23861,18 +23696,18 @@ _tmp_136_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _tmp_136[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_slash_with_default")); + D(fprintf(stderr, "%*c> _tmp_134[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_slash_with_default")); SlashWithDefault* lambda_slash_with_default_var; if ( (lambda_slash_with_default_var = lambda_slash_with_default_rule(p)) // lambda_slash_with_default ) { - D(fprintf(stderr, "%*c+ _tmp_136[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "lambda_slash_with_default")); + D(fprintf(stderr, "%*c+ _tmp_134[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "lambda_slash_with_default")); _res = lambda_slash_with_default_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_136[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_134[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_slash_with_default")); } { // lambda_param_with_default+ @@ -23880,18 +23715,18 @@ _tmp_136_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _tmp_136[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_with_default+")); - asdl_seq * _loop1_154_var; + D(fprintf(stderr, "%*c> _tmp_134[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_with_default+")); + asdl_seq * _loop1_152_var; if ( - (_loop1_154_var = _loop1_154_rule(p)) // lambda_param_with_default+ + (_loop1_152_var = _loop1_152_rule(p)) // lambda_param_with_default+ ) { - D(fprintf(stderr, "%*c+ _tmp_136[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "lambda_param_with_default+")); - _res = _loop1_154_var; + D(fprintf(stderr, "%*c+ _tmp_134[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "lambda_param_with_default+")); + _res = _loop1_152_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_136[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_134[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_with_default+")); } _res = NULL; @@ -23900,9 +23735,9 @@ _tmp_136_rule(Parser *p) return _res; } -// _tmp_137: ')' | ',' (')' | '**') +// _tmp_135: ')' | ',' (')' | '**') static void * -_tmp_137_rule(Parser *p) +_tmp_135_rule(Parser *p) { D(p->level++); if (p->error_indicator) { @@ -23916,18 +23751,18 @@ _tmp_137_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _tmp_137[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "')'")); + D(fprintf(stderr, "%*c> _tmp_135[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "')'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 8)) // token=')' ) { - D(fprintf(stderr, "%*c+ _tmp_137[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "')'")); + D(fprintf(stderr, "%*c+ _tmp_135[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "')'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_137[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_135[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "')'")); } { // ',' (')' | '**') @@ -23935,21 +23770,21 @@ _tmp_137_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _tmp_137[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (')' | '**')")); + D(fprintf(stderr, "%*c> _tmp_135[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (')' | '**')")); Token * _literal; - void *_tmp_155_var; + void *_tmp_153_var; if ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' && - (_tmp_155_var = _tmp_155_rule(p)) // ')' | '**' + (_tmp_153_var = _tmp_153_rule(p)) // ')' | '**' ) { - D(fprintf(stderr, "%*c+ _tmp_137[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' (')' | '**')")); - _res = _PyPegen_dummy_name(p, _literal, _tmp_155_var); + D(fprintf(stderr, "%*c+ _tmp_135[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' (')' | '**')")); + _res = _PyPegen_dummy_name(p, _literal, _tmp_153_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_137[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_135[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' (')' | '**')")); } _res = NULL; @@ -23958,9 +23793,9 @@ _tmp_137_rule(Parser *p) return _res; } -// _tmp_138: ':' | ',' (':' | '**') +// _tmp_136: ':' | ',' (':' | '**') static void * -_tmp_138_rule(Parser *p) +_tmp_136_rule(Parser *p) { D(p->level++); if (p->error_indicator) { @@ -23974,18 +23809,18 @@ _tmp_138_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _tmp_138[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); + D(fprintf(stderr, "%*c> _tmp_136[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 11)) // token=':' ) { - D(fprintf(stderr, "%*c+ _tmp_138[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); + D(fprintf(stderr, "%*c+ _tmp_136[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_138[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_136[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "':'")); } { // ',' (':' | '**') @@ -23993,21 +23828,21 @@ _tmp_138_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _tmp_138[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (':' | '**')")); + D(fprintf(stderr, "%*c> _tmp_136[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (':' | '**')")); Token * _literal; - void *_tmp_156_var; + void *_tmp_154_var; if ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' && - (_tmp_156_var = _tmp_156_rule(p)) // ':' | '**' + (_tmp_154_var = _tmp_154_rule(p)) // ':' | '**' ) { - D(fprintf(stderr, "%*c+ _tmp_138[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' (':' | '**')")); - _res = _PyPegen_dummy_name(p, _literal, _tmp_156_var); + D(fprintf(stderr, "%*c+ _tmp_136[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' (':' | '**')")); + _res = _PyPegen_dummy_name(p, _literal, _tmp_154_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_138[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_136[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' (':' | '**')")); } _res = NULL; @@ -24016,9 +23851,9 @@ _tmp_138_rule(Parser *p) return _res; } -// _tmp_139: star_targets '=' +// _tmp_137: star_targets '=' static void * -_tmp_139_rule(Parser *p) +_tmp_137_rule(Parser *p) { D(p->level++); if (p->error_indicator) { @@ -24032,7 +23867,7 @@ _tmp_139_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _tmp_139[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_targets '='")); + D(fprintf(stderr, "%*c> _tmp_137[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_targets '='")); Token * _literal; expr_ty z; if ( @@ -24041,7 +23876,7 @@ _tmp_139_rule(Parser *p) (_literal = _PyPegen_expect_token(p, 22)) // token='=' ) { - D(fprintf(stderr, "%*c+ _tmp_139[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_targets '='")); + D(fprintf(stderr, "%*c+ _tmp_137[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_targets '='")); _res = z; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -24051,7 +23886,7 @@ _tmp_139_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_139[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_137[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_targets '='")); } _res = NULL; @@ -24060,9 +23895,9 @@ _tmp_139_rule(Parser *p) return _res; } -// _tmp_140: '.' | '...' +// _tmp_138: '.' | '...' static void * -_tmp_140_rule(Parser *p) +_tmp_138_rule(Parser *p) { D(p->level++); if (p->error_indicator) { @@ -24076,18 +23911,18 @@ _tmp_140_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _tmp_140[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'.'")); + D(fprintf(stderr, "%*c> _tmp_138[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'.'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 23)) // token='.' ) { - D(fprintf(stderr, "%*c+ _tmp_140[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'.'")); + D(fprintf(stderr, "%*c+ _tmp_138[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'.'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_140[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_138[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'.'")); } { // '...' @@ -24095,18 +23930,18 @@ _tmp_140_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _tmp_140[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'...'")); + D(fprintf(stderr, "%*c> _tmp_138[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'...'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 52)) // token='...' ) { - D(fprintf(stderr, "%*c+ _tmp_140[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'...'")); + D(fprintf(stderr, "%*c+ _tmp_138[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'...'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_140[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_138[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'...'")); } _res = NULL; @@ -24115,9 +23950,9 @@ _tmp_140_rule(Parser *p) return _res; } -// _tmp_141: '.' | '...' +// _tmp_139: '.' | '...' static void * -_tmp_141_rule(Parser *p) +_tmp_139_rule(Parser *p) { D(p->level++); if (p->error_indicator) { @@ -24131,18 +23966,18 @@ _tmp_141_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _tmp_141[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'.'")); + D(fprintf(stderr, "%*c> _tmp_139[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'.'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 23)) // token='.' ) { - D(fprintf(stderr, "%*c+ _tmp_141[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'.'")); + D(fprintf(stderr, "%*c+ _tmp_139[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'.'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_141[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_139[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'.'")); } { // '...' @@ -24150,18 +23985,18 @@ _tmp_141_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _tmp_141[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'...'")); + D(fprintf(stderr, "%*c> _tmp_139[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'...'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 52)) // token='...' ) { - D(fprintf(stderr, "%*c+ _tmp_141[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'...'")); + D(fprintf(stderr, "%*c+ _tmp_139[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'...'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_141[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_139[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'...'")); } _res = NULL; @@ -24170,9 +24005,9 @@ _tmp_141_rule(Parser *p) return _res; } -// _tmp_142: '@' named_expression NEWLINE +// _tmp_140: '@' named_expression NEWLINE static void * -_tmp_142_rule(Parser *p) +_tmp_140_rule(Parser *p) { D(p->level++); if (p->error_indicator) { @@ -24186,7 +24021,7 @@ _tmp_142_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _tmp_142[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'@' named_expression NEWLINE")); + D(fprintf(stderr, "%*c> _tmp_140[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'@' named_expression NEWLINE")); Token * _literal; expr_ty f; Token * newline_var; @@ -24198,7 +24033,7 @@ _tmp_142_rule(Parser *p) (newline_var = _PyPegen_expect_token(p, NEWLINE)) // token='NEWLINE' ) { - D(fprintf(stderr, "%*c+ _tmp_142[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'@' named_expression NEWLINE")); + D(fprintf(stderr, "%*c+ _tmp_140[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'@' named_expression NEWLINE")); _res = f; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -24208,7 +24043,7 @@ _tmp_142_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_142[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_140[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'@' named_expression NEWLINE")); } _res = NULL; @@ -24217,9 +24052,9 @@ _tmp_142_rule(Parser *p) return _res; } -// _tmp_143: ',' star_expression +// _tmp_141: ',' star_expression static void * -_tmp_143_rule(Parser *p) +_tmp_141_rule(Parser *p) { D(p->level++); if (p->error_indicator) { @@ -24233,7 +24068,7 @@ _tmp_143_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _tmp_143[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' star_expression")); + D(fprintf(stderr, "%*c> _tmp_141[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' star_expression")); Token * _literal; expr_ty c; if ( @@ -24242,7 +24077,7 @@ _tmp_143_rule(Parser *p) (c = star_expression_rule(p)) // star_expression ) { - D(fprintf(stderr, "%*c+ _tmp_143[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' star_expression")); + D(fprintf(stderr, "%*c+ _tmp_141[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' star_expression")); _res = c; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -24252,7 +24087,7 @@ _tmp_143_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_143[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_141[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' star_expression")); } _res = NULL; @@ -24261,9 +24096,9 @@ _tmp_143_rule(Parser *p) return _res; } -// _tmp_144: ',' expression +// _tmp_142: ',' expression static void * -_tmp_144_rule(Parser *p) +_tmp_142_rule(Parser *p) { D(p->level++); if (p->error_indicator) { @@ -24277,7 +24112,7 @@ _tmp_144_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _tmp_144[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' expression")); + D(fprintf(stderr, "%*c> _tmp_142[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' expression")); Token * _literal; expr_ty c; if ( @@ -24286,7 +24121,7 @@ _tmp_144_rule(Parser *p) (c = expression_rule(p)) // expression ) { - D(fprintf(stderr, "%*c+ _tmp_144[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' expression")); + D(fprintf(stderr, "%*c+ _tmp_142[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' expression")); _res = c; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -24296,7 +24131,7 @@ _tmp_144_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_144[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_142[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' expression")); } _res = NULL; @@ -24305,9 +24140,9 @@ _tmp_144_rule(Parser *p) return _res; } -// _tmp_145: 'or' conjunction +// _tmp_143: 'or' conjunction static void * -_tmp_145_rule(Parser *p) +_tmp_143_rule(Parser *p) { D(p->level++); if (p->error_indicator) { @@ -24321,7 +24156,7 @@ _tmp_145_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _tmp_145[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'or' conjunction")); + D(fprintf(stderr, "%*c> _tmp_143[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'or' conjunction")); Token * _keyword; expr_ty c; if ( @@ -24330,7 +24165,7 @@ _tmp_145_rule(Parser *p) (c = conjunction_rule(p)) // conjunction ) { - D(fprintf(stderr, "%*c+ _tmp_145[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'or' conjunction")); + D(fprintf(stderr, "%*c+ _tmp_143[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'or' conjunction")); _res = c; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -24340,7 +24175,7 @@ _tmp_145_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_145[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_143[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'or' conjunction")); } _res = NULL; @@ -24349,9 +24184,9 @@ _tmp_145_rule(Parser *p) return _res; } -// _tmp_146: 'and' inversion +// _tmp_144: 'and' inversion static void * -_tmp_146_rule(Parser *p) +_tmp_144_rule(Parser *p) { D(p->level++); if (p->error_indicator) { @@ -24365,7 +24200,7 @@ _tmp_146_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _tmp_146[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'and' inversion")); + D(fprintf(stderr, "%*c> _tmp_144[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'and' inversion")); Token * _keyword; expr_ty c; if ( @@ -24374,7 +24209,7 @@ _tmp_146_rule(Parser *p) (c = inversion_rule(p)) // inversion ) { - D(fprintf(stderr, "%*c+ _tmp_146[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'and' inversion")); + D(fprintf(stderr, "%*c+ _tmp_144[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'and' inversion")); _res = c; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -24384,7 +24219,7 @@ _tmp_146_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_146[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_144[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'and' inversion")); } _res = NULL; @@ -24393,9 +24228,9 @@ _tmp_146_rule(Parser *p) return _res; } -// _tmp_147: 'if' disjunction +// _tmp_145: 'if' disjunction static void * -_tmp_147_rule(Parser *p) +_tmp_145_rule(Parser *p) { D(p->level++); if (p->error_indicator) { @@ -24409,7 +24244,7 @@ _tmp_147_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _tmp_147[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'if' disjunction")); + D(fprintf(stderr, "%*c> _tmp_145[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'if' disjunction")); Token * _keyword; expr_ty z; if ( @@ -24418,7 +24253,7 @@ _tmp_147_rule(Parser *p) (z = disjunction_rule(p)) // disjunction ) { - D(fprintf(stderr, "%*c+ _tmp_147[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'if' disjunction")); + D(fprintf(stderr, "%*c+ _tmp_145[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'if' disjunction")); _res = z; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -24428,7 +24263,7 @@ _tmp_147_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_147[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_145[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'if' disjunction")); } _res = NULL; @@ -24437,9 +24272,9 @@ _tmp_147_rule(Parser *p) return _res; } -// _tmp_148: 'if' disjunction +// _tmp_146: 'if' disjunction static void * -_tmp_148_rule(Parser *p) +_tmp_146_rule(Parser *p) { D(p->level++); if (p->error_indicator) { @@ -24453,7 +24288,7 @@ _tmp_148_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _tmp_148[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'if' disjunction")); + D(fprintf(stderr, "%*c> _tmp_146[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'if' disjunction")); Token * _keyword; expr_ty z; if ( @@ -24462,7 +24297,7 @@ _tmp_148_rule(Parser *p) (z = disjunction_rule(p)) // disjunction ) { - D(fprintf(stderr, "%*c+ _tmp_148[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'if' disjunction")); + D(fprintf(stderr, "%*c+ _tmp_146[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'if' disjunction")); _res = z; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -24472,7 +24307,7 @@ _tmp_148_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_148[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_146[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'if' disjunction")); } _res = NULL; @@ -24481,9 +24316,9 @@ _tmp_148_rule(Parser *p) return _res; } -// _tmp_149: starred_expression | named_expression !'=' +// _tmp_147: starred_expression | named_expression !'=' static void * -_tmp_149_rule(Parser *p) +_tmp_147_rule(Parser *p) { D(p->level++); if (p->error_indicator) { @@ -24497,18 +24332,18 @@ _tmp_149_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _tmp_149[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "starred_expression")); + D(fprintf(stderr, "%*c> _tmp_147[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "starred_expression")); expr_ty starred_expression_var; if ( (starred_expression_var = starred_expression_rule(p)) // starred_expression ) { - D(fprintf(stderr, "%*c+ _tmp_149[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "starred_expression")); + D(fprintf(stderr, "%*c+ _tmp_147[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "starred_expression")); _res = starred_expression_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_149[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_147[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "starred_expression")); } { // named_expression !'=' @@ -24516,7 +24351,7 @@ _tmp_149_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _tmp_149[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "named_expression !'='")); + D(fprintf(stderr, "%*c> _tmp_147[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "named_expression !'='")); expr_ty named_expression_var; if ( (named_expression_var = named_expression_rule(p)) // named_expression @@ -24524,12 +24359,12 @@ _tmp_149_rule(Parser *p) _PyPegen_lookahead_with_int(0, _PyPegen_expect_token, p, 22) // token='=' ) { - D(fprintf(stderr, "%*c+ _tmp_149[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "named_expression !'='")); + D(fprintf(stderr, "%*c+ _tmp_147[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "named_expression !'='")); _res = named_expression_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_149[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_147[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "named_expression !'='")); } _res = NULL; @@ -24538,9 +24373,9 @@ _tmp_149_rule(Parser *p) return _res; } -// _tmp_150: ',' star_target +// _tmp_148: ',' star_target static void * -_tmp_150_rule(Parser *p) +_tmp_148_rule(Parser *p) { D(p->level++); if (p->error_indicator) { @@ -24554,7 +24389,7 @@ _tmp_150_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _tmp_150[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' star_target")); + D(fprintf(stderr, "%*c> _tmp_148[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' star_target")); Token * _literal; expr_ty c; if ( @@ -24563,7 +24398,7 @@ _tmp_150_rule(Parser *p) (c = star_target_rule(p)) // star_target ) { - D(fprintf(stderr, "%*c+ _tmp_150[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' star_target")); + D(fprintf(stderr, "%*c+ _tmp_148[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' star_target")); _res = c; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -24573,7 +24408,7 @@ _tmp_150_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_150[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_148[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' star_target")); } _res = NULL; @@ -24582,9 +24417,9 @@ _tmp_150_rule(Parser *p) return _res; } -// _tmp_151: star_targets '=' +// _tmp_149: star_targets '=' static void * -_tmp_151_rule(Parser *p) +_tmp_149_rule(Parser *p) { D(p->level++); if (p->error_indicator) { @@ -24598,7 +24433,7 @@ _tmp_151_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _tmp_151[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_targets '='")); + D(fprintf(stderr, "%*c> _tmp_149[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_targets '='")); Token * _literal; expr_ty star_targets_var; if ( @@ -24607,12 +24442,12 @@ _tmp_151_rule(Parser *p) (_literal = _PyPegen_expect_token(p, 22)) // token='=' ) { - D(fprintf(stderr, "%*c+ _tmp_151[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_targets '='")); + D(fprintf(stderr, "%*c+ _tmp_149[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_targets '='")); _res = _PyPegen_dummy_name(p, star_targets_var, _literal); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_151[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_149[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_targets '='")); } _res = NULL; @@ -24621,9 +24456,9 @@ _tmp_151_rule(Parser *p) return _res; } -// _tmp_152: star_targets '=' +// _tmp_150: star_targets '=' static void * -_tmp_152_rule(Parser *p) +_tmp_150_rule(Parser *p) { D(p->level++); if (p->error_indicator) { @@ -24637,7 +24472,7 @@ _tmp_152_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _tmp_152[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_targets '='")); + D(fprintf(stderr, "%*c> _tmp_150[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_targets '='")); Token * _literal; expr_ty star_targets_var; if ( @@ -24646,12 +24481,12 @@ _tmp_152_rule(Parser *p) (_literal = _PyPegen_expect_token(p, 22)) // token='=' ) { - D(fprintf(stderr, "%*c+ _tmp_152[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_targets '='")); + D(fprintf(stderr, "%*c+ _tmp_150[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_targets '='")); _res = _PyPegen_dummy_name(p, star_targets_var, _literal); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_152[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_150[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_targets '='")); } _res = NULL; @@ -24660,9 +24495,9 @@ _tmp_152_rule(Parser *p) return _res; } -// _loop1_153: param_with_default +// _loop1_151: param_with_default static asdl_seq * -_loop1_153_rule(Parser *p) +_loop1_151_rule(Parser *p) { D(p->level++); if (p->error_indicator) { @@ -24686,7 +24521,7 @@ _loop1_153_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _loop1_153[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_with_default")); + D(fprintf(stderr, "%*c> _loop1_151[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_with_default")); NameDefaultPair* param_with_default_var; while ( (param_with_default_var = param_with_default_rule(p)) // param_with_default @@ -24708,7 +24543,7 @@ _loop1_153_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_153[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_151[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "param_with_default")); } if (_n == 0 || p->error_indicator) { @@ -24726,14 +24561,14 @@ _loop1_153_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop1_153_type, _seq); + _PyPegen_insert_memo(p, _start_mark, _loop1_151_type, _seq); D(p->level--); return _seq; } -// _loop1_154: lambda_param_with_default +// _loop1_152: lambda_param_with_default static asdl_seq * -_loop1_154_rule(Parser *p) +_loop1_152_rule(Parser *p) { D(p->level++); if (p->error_indicator) { @@ -24757,7 +24592,7 @@ _loop1_154_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _loop1_154[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_with_default")); + D(fprintf(stderr, "%*c> _loop1_152[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_with_default")); NameDefaultPair* lambda_param_with_default_var; while ( (lambda_param_with_default_var = lambda_param_with_default_rule(p)) // lambda_param_with_default @@ -24779,7 +24614,7 @@ _loop1_154_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_154[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_152[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_with_default")); } if (_n == 0 || p->error_indicator) { @@ -24797,14 +24632,14 @@ _loop1_154_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop1_154_type, _seq); + _PyPegen_insert_memo(p, _start_mark, _loop1_152_type, _seq); D(p->level--); return _seq; } -// _tmp_155: ')' | '**' +// _tmp_153: ')' | '**' static void * -_tmp_155_rule(Parser *p) +_tmp_153_rule(Parser *p) { D(p->level++); if (p->error_indicator) { @@ -24818,18 +24653,18 @@ _tmp_155_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _tmp_155[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "')'")); + D(fprintf(stderr, "%*c> _tmp_153[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "')'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 8)) // token=')' ) { - D(fprintf(stderr, "%*c+ _tmp_155[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "')'")); + D(fprintf(stderr, "%*c+ _tmp_153[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "')'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_155[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_153[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "')'")); } { // '**' @@ -24837,18 +24672,18 @@ _tmp_155_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _tmp_155[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'**'")); + D(fprintf(stderr, "%*c> _tmp_153[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'**'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 35)) // token='**' ) { - D(fprintf(stderr, "%*c+ _tmp_155[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'**'")); + D(fprintf(stderr, "%*c+ _tmp_153[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'**'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_155[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_153[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'**'")); } _res = NULL; @@ -24857,9 +24692,9 @@ _tmp_155_rule(Parser *p) return _res; } -// _tmp_156: ':' | '**' +// _tmp_154: ':' | '**' static void * -_tmp_156_rule(Parser *p) +_tmp_154_rule(Parser *p) { D(p->level++); if (p->error_indicator) { @@ -24873,18 +24708,18 @@ _tmp_156_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _tmp_156[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); + D(fprintf(stderr, "%*c> _tmp_154[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 11)) // token=':' ) { - D(fprintf(stderr, "%*c+ _tmp_156[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); + D(fprintf(stderr, "%*c+ _tmp_154[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_156[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_154[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "':'")); } { // '**' @@ -24892,18 +24727,18 @@ _tmp_156_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _tmp_156[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'**'")); + D(fprintf(stderr, "%*c> _tmp_154[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'**'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 35)) // token='**' ) { - D(fprintf(stderr, "%*c+ _tmp_156[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'**'")); + D(fprintf(stderr, "%*c+ _tmp_154[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'**'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_156[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_154[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'**'")); } _res = NULL; From 2acd9d0c6ccf0b4360e3b63beddb97996bcb9bb1 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 19 Nov 2020 08:51:01 -0800 Subject: [PATCH 0715/1314] bpo-42345: Fix hash implementation of typing.Literal (GH-23383) Fix hash implementation of `typing.Literal`. Update docs regarding `typing.Litaral` caching. Base implementation was done in PR GH-23294. (cherry picked from commit 1b54077ff6f5c1379e097e9f8e8648da9826d6ec) Co-authored-by: Yurii Karabas <1998uriyyo@gmail.com> --- Doc/library/typing.rst | 6 +++--- Lib/test/test_typing.py | 5 +++++ Lib/typing.py | 2 +- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst index 324abdeb5eb5bb..42a89ce8fb4c65 100644 --- a/Doc/library/typing.rst +++ b/Doc/library/typing.rst @@ -1687,9 +1687,9 @@ Introspection helpers For a typing object of the form ``X[Y, Z, ...]`` these functions return ``X`` and ``(Y, Z, ...)``. If ``X`` is a generic alias for a builtin or :mod:`collections` class, it gets normalized to the original class. - If ``X`` is a :class:`Union` contained in another generic type, - the order of ``(Y, Z, ...)`` may be different from the order of - the original arguments ``[Y, Z, ...]`` due to type caching. + If ``X`` is a :class:`Union` or :class:`Literal` contained in another + generic type, the order of ``(Y, Z, ...)`` may be different from the order + of the original arguments ``[Y, Z, ...]`` due to type caching. For unsupported objects return ``None`` and ``()`` correspondingly. Examples:: diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index 9d82eec3f53761..13cf20eee09ab1 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -573,6 +573,11 @@ def test_equal(self): self.assertEqual(Literal[1, 2], Literal[2, 1]) self.assertEqual(Literal[1, 2, 3], Literal[1, 2, 3, 3]) + def test_hash(self): + self.assertEqual(hash(Literal[1]), hash(Literal[1])) + self.assertEqual(hash(Literal[1, 2]), hash(Literal[2, 1])) + self.assertEqual(hash(Literal[1, 2, 3]), hash(Literal[1, 2, 3, 3])) + def test_args(self): self.assertEqual(Literal[1, 2, 3].__args__, (1, 2, 3)) self.assertEqual(Literal[1, 2, 3, 3].__args__, (1, 2, 3)) diff --git a/Lib/typing.py b/Lib/typing.py index 14952ec6cc6954..f5316ab8a5f538 100644 --- a/Lib/typing.py +++ b/Lib/typing.py @@ -932,7 +932,7 @@ def __eq__(self, other): return set(_value_and_type_iter(self.__args__)) == set(_value_and_type_iter(other.__args__)) def __hash__(self): - return hash(tuple(_value_and_type_iter(self.__args__))) + return hash(frozenset(_value_and_type_iter(self.__args__))) class Generic: From 1051ca4d974ebb6448f58b661aa28f8aff325ed3 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 19 Nov 2020 09:59:10 -0800 Subject: [PATCH 0716/1314] bpo-42345: Add whatsnew and versionchanged for typing.Literal in 3.9 (GH-23386) * Whatsnew entry in 3.9 same as the one in 3.10. * versionchanged for typing.Literal docs Needs backport to 3.9. (cherry picked from commit e1dc0db8c7cb8c4d7343e051ba85146b375bb8e0) Co-authored-by: kj <28750310+Fidget-Spinner@users.noreply.github.com> --- Doc/library/typing.rst | 6 ++++++ Doc/whatsnew/3.9.rst | 29 +++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst index 42a89ce8fb4c65..28c607e149139e 100644 --- a/Doc/library/typing.rst +++ b/Doc/library/typing.rst @@ -655,6 +655,12 @@ These can be used as types in annotations using ``[]``, each having a unique syn .. versionadded:: 3.8 + .. versionchanged:: 3.9.1 + ``Literal`` now de-duplicates parameters. Equality comparison of + ``Literal`` objects are no longer order dependent. ``Literal`` objects + will now raise a :exc:`TypeError` exception during equality comparisons + if one of their parameters are not :term:`immutable`. + .. data:: ClassVar Special type construct to mark class variables. diff --git a/Doc/whatsnew/3.9.rst b/Doc/whatsnew/3.9.rst index a601b16f1c6059..b89faf101d0435 100644 --- a/Doc/whatsnew/3.9.rst +++ b/Doc/whatsnew/3.9.rst @@ -1454,3 +1454,32 @@ Removed ``PyNullImporter_Type``, ``PyCmpWrapper_Type``, ``PySortWrapper_Type``, ``PyNoArgsFunction``. (Contributed by Pablo Galindo Salgado in :issue:`39372`.) + +Notable changes in Python 3.9.1 +=============================== + +typing +------ + +The behavior of :class:`typing.Literal` was changed to conform with :pep:`586` +and to match the behavior of static type checkers specified in the PEP. + +1. ``Literal`` now de-duplicates parameters. +2. Equality comparisons between ``Literal`` objects are now order independent. +3. ``Literal`` comparisons now respect types. For example, + ``Literal[0] == Literal[False]`` previously evaluated to ``True``. It is + now ``False``. To support this change, the internally used type cache now + supports differentiating types. +4. ``Literal`` objects will now raise a :exc:`TypeError` exception during + equality comparisons if one of their parameters are not :term:`immutable`. + Note that declaring ``Literal`` with mutable parameters will not throw + an error:: + + >>> from typing import Literal + >>> Literal[{0}] + >>> Literal[{0}] == Literal[{False}] + Traceback (most recent call last): + File "", line 1, in + TypeError: unhashable type: 'set' + +(Contributed by Yurii Karabas in :issue:`42345`.) \ No newline at end of file From 4dd2112a1d26e03b605bed0f89e3678041ad1490 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 19 Nov 2020 23:28:21 -0800 Subject: [PATCH 0717/1314] bpo-42416: Use inspect.getdoc for IDLE calltips (GH-23416) Inspect.getdoc(ob) sometimes gets docstrings when ob.__doc__ is None. (cherry picked from commit 7ddbaa7a1b3e61847ee99658be6a7268a049e302) Co-authored-by: Terry Jan Reedy --- Lib/idlelib/NEWS.txt | 3 +++ Lib/idlelib/calltip.py | 6 ++---- Lib/idlelib/idle_test/test_calltip.py | 9 +++++++-- .../next/IDLE/2020-11-20-01-30-27.bpo-42415.CyD-va.rst | 1 + 4 files changed, 13 insertions(+), 6 deletions(-) create mode 100644 Misc/NEWS.d/next/IDLE/2020-11-20-01-30-27.bpo-42415.CyD-va.rst diff --git a/Lib/idlelib/NEWS.txt b/Lib/idlelib/NEWS.txt index a7f74814d72516..6eacde95d908da 100644 --- a/Lib/idlelib/NEWS.txt +++ b/Lib/idlelib/NEWS.txt @@ -3,6 +3,9 @@ Released on 2020-12-07? ====================================== +bpo-42416: Get docstrings for IDLE calltips more often +by using inspect.getdoc. + bpo-33987: Mostly finish using ttk widgets, mainly for editor, settings, and searches. Some patches by Mark Roseman. diff --git a/Lib/idlelib/calltip.py b/Lib/idlelib/calltip.py index 549e224015cccb..40bc5a0ad798fe 100644 --- a/Lib/idlelib/calltip.py +++ b/Lib/idlelib/calltip.py @@ -165,6 +165,7 @@ def get_argspec(ob): ob_call = ob.__call__ except BaseException: # Buggy user object could raise anything. return '' # No popup for non-callables. + # For Get_argspecTest.test_buggy_getattr_class, CallA() & CallB(). fob = ob_call if isinstance(ob_call, types.MethodType) else ob # Initialize argspec and wrap it to get lines. @@ -185,10 +186,7 @@ def get_argspec(ob): if len(argspec) > _MAX_COLS else [argspec] if argspec else []) # Augment lines from docstring, if any, and join to get argspec. - if isinstance(ob_call, types.MethodType): - doc = ob_call.__doc__ - else: - doc = getattr(ob, "__doc__", "") + doc = inspect.getdoc(ob) if doc: for line in doc.split('\n', _MAX_LINES)[:_MAX_LINES]: line = line.strip() diff --git a/Lib/idlelib/idle_test/test_calltip.py b/Lib/idlelib/idle_test/test_calltip.py index 489b6899baf424..a76829f3656c80 100644 --- a/Lib/idlelib/idle_test/test_calltip.py +++ b/Lib/idlelib/idle_test/test_calltip.py @@ -99,7 +99,12 @@ def test_signature_wrap(self): (width=70, initial_indent='', subsequent_indent='', expand_tabs=True, replace_whitespace=True, fix_sentence_endings=False, break_long_words=True, drop_whitespace=True, break_on_hyphens=True, tabsize=8, *, max_lines=None, - placeholder=' [...]')''') + placeholder=' [...]') +Object for wrapping/filling text. The public interface consists of +the wrap() and fill() methods; the other methods are just there for +subclasses to override in order to tweak the default behaviour. +If you want to completely replace the main wrapping algorithm, +you\'ll probably have to override _wrap_chunks().''') def test_properly_formated(self): @@ -241,7 +246,7 @@ class Type(type): # Type() requires 3 type args, returns class. __class__ = property({}.__getitem__, {}.__setitem__) class Object(metaclass=Type): __slots__ = '__class__' - for meth, mtip in ((Type, default_tip), (Object, default_tip), + for meth, mtip in ((Type, get_spec(type)), (Object, default_tip), (Object(), '')): with self.subTest(meth=meth, mtip=mtip): self.assertEqual(get_spec(meth), mtip) diff --git a/Misc/NEWS.d/next/IDLE/2020-11-20-01-30-27.bpo-42415.CyD-va.rst b/Misc/NEWS.d/next/IDLE/2020-11-20-01-30-27.bpo-42415.CyD-va.rst new file mode 100644 index 00000000000000..b61032c1e48e2a --- /dev/null +++ b/Misc/NEWS.d/next/IDLE/2020-11-20-01-30-27.bpo-42415.CyD-va.rst @@ -0,0 +1 @@ +Get docstrings for IDLE calltips more often by using inspect.getdoc. From f552f4b2d635ae031e154374ba3a609c63d09d2b Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 20 Nov 2020 13:19:49 -0800 Subject: [PATCH 0718/1314] bpo-42360: Add advice to help avoid pickling issues. (GH-23305) (GH-23429) --- Doc/library/collections.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Doc/library/collections.rst b/Doc/library/collections.rst index 549ac1bccadf5d..2ffdb49dbe6da8 100644 --- a/Doc/library/collections.rst +++ b/Doc/library/collections.rst @@ -849,6 +849,9 @@ they add the ability to access fields by name instead of position index. Named tuple instances do not have per-instance dictionaries, so they are lightweight and require no more memory than regular tuples. + To support pickling, the named tuple class should be assigned to a variable + that matches *typename*. + .. versionchanged:: 3.1 Added support for *rename*. From 3763cc1dbdb930f67b443ceed7c44e4feb883b42 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 20 Nov 2020 13:46:49 -0800 Subject: [PATCH 0719/1314] bpo-28002: Roundtrip f-strings with ast.unparse better (GH-19612) (GH-23430) By attempting to avoid backslashes in f-string expressions. We also now proactively raise errors for some backslashes we can't avoid while unparsing FormattedValues Co-authored-by: hauntsaninja <> Co-authored-by: Shantanu Co-authored-by: Batuhan Taskaya (cherry picked from commit a993e901ebe60c38d46ecb31f771d0b4a206828c) Co-authored-by: Shantanu <12621235+hauntsaninja@users.noreply.github.com> Co-authored-by: Shantanu <12621235+hauntsaninja@users.noreply.github.com> --- Lib/ast.py | 110 ++++++++++++++++++++++++++++++--------- Lib/test/test_unparse.py | 42 ++++++++++----- 2 files changed, 115 insertions(+), 37 deletions(-) diff --git a/Lib/ast.py b/Lib/ast.py index d860917f4d03ae..ecd4895f7570c9 100644 --- a/Lib/ast.py +++ b/Lib/ast.py @@ -662,17 +662,23 @@ def next(self): except ValueError: return self + +_SINGLE_QUOTES = ("'", '"') +_MULTI_QUOTES = ('"""', "'''") +_ALL_QUOTES = (*_SINGLE_QUOTES, *_MULTI_QUOTES) + class _Unparser(NodeVisitor): """Methods in this class recursively traverse an AST and output source code for the abstract syntax; original formatting is disregarded.""" - def __init__(self): + def __init__(self, *, _avoid_backslashes=False): self._source = [] self._buffer = [] self._precedences = {} self._type_ignores = {} self._indent = 0 + self._avoid_backslashes = _avoid_backslashes def interleave(self, inter, f, seq): """Call f on each item in seq, calling inter() in between.""" @@ -1067,15 +1073,85 @@ def visit_AsyncWith(self, node): with self.block(extra=self.get_type_comment(node)): self.traverse(node.body) + def _str_literal_helper( + self, string, *, quote_types=_ALL_QUOTES, escape_special_whitespace=False + ): + """Helper for writing string literals, minimizing escapes. + Returns the tuple (string literal to write, possible quote types). + """ + def escape_char(c): + # \n and \t are non-printable, but we only escape them if + # escape_special_whitespace is True + if not escape_special_whitespace and c in "\n\t": + return c + # Always escape backslashes and other non-printable characters + if c == "\\" or not c.isprintable(): + return c.encode("unicode_escape").decode("ascii") + return c + + escaped_string = "".join(map(escape_char, string)) + possible_quotes = quote_types + if "\n" in escaped_string: + possible_quotes = [q for q in possible_quotes if q in _MULTI_QUOTES] + possible_quotes = [q for q in possible_quotes if q not in escaped_string] + if not possible_quotes: + # If there aren't any possible_quotes, fallback to using repr + # on the original string. Try to use a quote from quote_types, + # e.g., so that we use triple quotes for docstrings. + string = repr(string) + quote = next((q for q in quote_types if string[0] in q), string[0]) + return string[1:-1], [quote] + if escaped_string: + # Sort so that we prefer '''"''' over """\"""" + possible_quotes.sort(key=lambda q: q[0] == escaped_string[-1]) + # If we're using triple quotes and we'd need to escape a final + # quote, escape it + if possible_quotes[0][0] == escaped_string[-1]: + assert len(possible_quotes[0]) == 3 + escaped_string = escaped_string[:-1] + "\\" + escaped_string[-1] + return escaped_string, possible_quotes + + def _write_str_avoiding_backslashes(self, string, *, quote_types=_ALL_QUOTES): + """Write string literal value with a best effort attempt to avoid backslashes.""" + string, quote_types = self._str_literal_helper(string, quote_types=quote_types) + quote_type = quote_types[0] + self.write(f"{quote_type}{string}{quote_type}") + def visit_JoinedStr(self, node): self.write("f") - self._fstring_JoinedStr(node, self.buffer_writer) - self.write(repr(self.buffer)) + if self._avoid_backslashes: + self._fstring_JoinedStr(node, self.buffer_writer) + self._write_str_avoiding_backslashes(self.buffer) + return + + # If we don't need to avoid backslashes globally (i.e., we only need + # to avoid them inside FormattedValues), it's cosmetically preferred + # to use escaped whitespace. That is, it's preferred to use backslashes + # for cases like: f"{x}\n". To accomplish this, we keep track of what + # in our buffer corresponds to FormattedValues and what corresponds to + # Constant parts of the f-string, and allow escapes accordingly. + buffer = [] + for value in node.values: + meth = getattr(self, "_fstring_" + type(value).__name__) + meth(value, self.buffer_writer) + buffer.append((self.buffer, isinstance(value, Constant))) + new_buffer = [] + quote_types = _ALL_QUOTES + for value, is_constant in buffer: + # Repeatedly narrow down the list of possible quote_types + value, quote_types = self._str_literal_helper( + value, quote_types=quote_types, + escape_special_whitespace=is_constant + ) + new_buffer.append(value) + value = "".join(new_buffer) + quote_type = quote_types[0] + self.write(f"{quote_type}{value}{quote_type}") def visit_FormattedValue(self, node): self.write("f") self._fstring_FormattedValue(node, self.buffer_writer) - self.write(repr(self.buffer)) + self._write_str_avoiding_backslashes(self.buffer) def _fstring_JoinedStr(self, node, write): for value in node.values: @@ -1090,11 +1166,13 @@ def _fstring_Constant(self, node, write): def _fstring_FormattedValue(self, node, write): write("{") - unparser = type(self)() + unparser = type(self)(_avoid_backslashes=True) unparser.set_precedence(_Precedence.TEST.next(), node.value) expr = unparser.visit(node.value) if expr.startswith("{"): write(" ") # Separate pair of opening brackets as "{ {" + if "\\" in expr: + raise ValueError("Unable to avoid backslash in f-string expression part") write(expr) if node.conversion != -1: conversion = chr(node.conversion) @@ -1111,33 +1189,17 @@ def visit_Name(self, node): self.write(node.id) def _write_docstring(self, node): - def esc_char(c): - if c in ("\n", "\t"): - # In the AST form, we don't know the author's intentation - # about how this should be displayed. We'll only escape - # \n and \t, because they are more likely to be unescaped - # in the source - return c - return c.encode('unicode_escape').decode('ascii') - self.fill() if node.kind == "u": self.write("u") - - value = node.value - if value: - # Preserve quotes in the docstring by escaping them - value = "".join(map(esc_char, value)) - if value[-1] == '"': - value = value.replace('"', '\\"', -1) - value = value.replace('"""', '""\\"') - - self.write(f'"""{value}"""') + self._write_str_avoiding_backslashes(node.value, quote_types=_MULTI_QUOTES) def _write_constant(self, value): if isinstance(value, (float, complex)): # Substitute overflowing decimal literal for AST infinities. self.write(repr(value).replace("inf", _INFSTR)) + elif self._avoid_backslashes and isinstance(value, str): + self._write_str_avoiding_backslashes(value) else: self.write(repr(value)) diff --git a/Lib/test/test_unparse.py b/Lib/test/test_unparse.py index 532aa3a6390414..c7c8613ea2793f 100644 --- a/Lib/test/test_unparse.py +++ b/Lib/test/test_unparse.py @@ -152,6 +152,18 @@ def test_fstrings(self): # See issue 25180 self.check_ast_roundtrip(r"""f'{f"{0}"*3}'""") self.check_ast_roundtrip(r"""f'{f"{y}"*3}'""") + self.check_ast_roundtrip("""f''""") + self.check_ast_roundtrip('''f"""'end' "quote\\""""''') + + def test_fstrings_complicated(self): + # See issue 28002 + self.check_ast_roundtrip("""f'''{"'"}'''""") + self.check_ast_roundtrip('''f\'\'\'-{f"""*{f"+{f'.{x}.'}+"}*"""}-\'\'\'''') + self.check_ast_roundtrip('''f\'\'\'-{f"""*{f"+{f'.{x}.'}+"}*"""}-'single quote\\'\'\'\'''') + self.check_ast_roundtrip('f"""{\'\'\'\n\'\'\'}"""') + self.check_ast_roundtrip('f"""{g(\'\'\'\n\'\'\')}"""') + self.check_ast_roundtrip('''f"a\\r\\nb"''') + self.check_ast_roundtrip('''f"\\u2028{'x'}"''') def test_strings(self): self.check_ast_roundtrip("u'foo'") @@ -311,6 +323,9 @@ def test_invalid_fstring_conversion(self): ) ) + def test_invalid_fstring_backslash(self): + self.check_invalid(ast.FormattedValue(value=ast.Constant(value="\\\\"))) + def test_invalid_set(self): self.check_invalid(ast.Set(elts=[])) @@ -330,8 +345,8 @@ def test_docstrings(self): '\r\\r\t\\t\n\\n', '""">>> content = \"\"\"blabla\"\"\" <<<"""', r'foo\n\x00', - 'ðŸâ›Žð©¸½Ã¼Ã©ÅŸ^\N{LONG RIGHTWARDS SQUIGGLE ARROW}' - + "' \\'\\'\\'\"\"\" \"\"\\'\\' \\'", + 'ðŸâ›Žð©¸½Ã¼Ã©ÅŸ^\\\\X\\\\BB\N{LONG RIGHTWARDS SQUIGGLE ARROW}' ) for docstring in docstrings: # check as Module docstrings for easy testing @@ -416,7 +431,6 @@ def test_simple_expressions_parens(self): self.check_src_roundtrip("call((yield x))") self.check_src_roundtrip("return x + (yield x)") - def test_class_bases_and_keywords(self): self.check_src_roundtrip("class X:\n pass") self.check_src_roundtrip("class X(A):\n pass") @@ -429,6 +443,13 @@ def test_class_bases_and_keywords(self): self.check_src_roundtrip("class X(*args):\n pass") self.check_src_roundtrip("class X(*args, **kwargs):\n pass") + def test_fstrings(self): + self.check_src_roundtrip('''f\'\'\'-{f"""*{f"+{f'.{x}.'}+"}*"""}-\'\'\'''') + self.check_src_roundtrip('''f"\\u2028{'x'}"''') + self.check_src_roundtrip(r"f'{x}\n'") + self.check_src_roundtrip('''f''\'{"""\n"""}\\n''\'''') + self.check_src_roundtrip('''f''\'{f"""{x}\n"""}\\n''\'''') + def test_docstrings(self): docstrings = ( '"""simple doc string"""', @@ -443,6 +464,10 @@ def test_docstrings(self): '""""""', '"""\'\'\'"""', '"""\'\'\'\'\'\'"""', + '"""ðŸâ›Žð©¸½Ã¼Ã©ÅŸ^\\\\X\\\\BB⟿"""', + '"""end in single \'quote\'"""', + "'''end in double \"quote\"'''", + '"""almost end in double "quote"."""', ) for prefix in docstring_prefixes: @@ -483,9 +508,8 @@ class DirectoryTestCase(ASTTestCase): lib_dir = pathlib.Path(__file__).parent / ".." test_directories = (lib_dir, lib_dir / "test") - skip_files = {"test_fstring.py"} run_always_files = {"test_grammar.py", "test_syntax.py", "test_compile.py", - "test_ast.py", "test_asdl_parser.py"} + "test_ast.py", "test_asdl_parser.py", "test_fstring.py"} _files_to_test = None @@ -525,14 +549,6 @@ def test_files(self): if test.support.verbose: print(f"Testing {item.absolute()}") - # Some f-strings are not correctly round-tripped by - # Tools/parser/unparse.py. See issue 28002 for details. - # We need to skip files that contain such f-strings. - if item.name in self.skip_files: - if test.support.verbose: - print(f"Skipping {item.absolute()}: see issue 28002") - continue - with self.subTest(filename=item): source = read_pyfile(item) self.check_ast_roundtrip(source) From c963da269d3778b65a64ff1bd91f8772c210f305 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 20 Nov 2020 19:01:05 -0800 Subject: [PATCH 0720/1314] bpo-42407: Use possessive appostrophe in multiprocessing doc (GH-23400) (cherry picked from commit 6edf06b24a9335a2b0d44634a95e4f5ba0d586d9) Co-authored-by: ArioA --- Doc/library/multiprocessing.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/multiprocessing.rst b/Doc/library/multiprocessing.rst index c9992ee08b9654..046ed39caff5c9 100644 --- a/Doc/library/multiprocessing.rst +++ b/Doc/library/multiprocessing.rst @@ -98,7 +98,7 @@ to start a process. These *start methods* are *spawn* The parent process starts a fresh python interpreter process. The child process will only inherit those resources necessary to run - the process objects :meth:`~Process.run` method. In particular, + the process object's :meth:`~Process.run` method. In particular, unnecessary file descriptors and handles from the parent process will not be inherited. Starting a process using this method is rather slow compared to using *fork* or *forkserver*. From ed0201805c036e4bc26670ec7ccffefb8e219f78 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 20 Nov 2020 20:34:55 -0800 Subject: [PATCH 0721/1314] bpo-42419: Correct 'deprecatations' is What's New 3.9 (GH-23421) (GH-23435) (cherry picked from commit aa3a3521cef3998d4f9e7f7ff721163b6e3e5f39) Co-authored-by: Quentin Hibon --- Doc/whatsnew/3.9.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/whatsnew/3.9.rst b/Doc/whatsnew/3.9.rst index b89faf101d0435..a638e544cb38fe 100644 --- a/Doc/whatsnew/3.9.rst +++ b/Doc/whatsnew/3.9.rst @@ -135,8 +135,8 @@ More generally, try to run your tests in the :ref:`Python Development Mode ` which helps to prepare your code to make it compatible with the next Python version. -Note: a number of pre-existing deprecatations were removed in this version -of Python as well. Consult the :ref:`removed-in-python-39` section. +Note: a number of pre-existing deprecations were removed in this version of +Python as well. Consult the :ref:`removed-in-python-39` section. New Features From c1bbca5b004b3f74d240ef8a76ff445cc1a27efb Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 21 Nov 2020 01:18:41 -0800 Subject: [PATCH 0722/1314] bpo-40791: Make compare_digest more constant-time. (GH-20444) * bpo-40791: Make compare_digest more constant-time. The existing volatile `left`/`right` pointers guarantee that the reads will all occur, but does not guarantee that they will be _used_. So a compiler can still short-circuit the loop, saving e.g. the overhead of doing the xors and especially the overhead of the data dependency between `result` and the reads. That would change performance depending on where the first unequal byte occurs. This change removes that optimization. (This is change GH-1 from https://bugs.python.org/issue40791 .) (cherry picked from commit 31729366e2bc09632e78f3896dbce0ae64914f28) Co-authored-by: Devin Jeanpierre --- .../next/Security/2020-05-28-06-06-47.bpo-40791.QGZClX.rst | 1 + Modules/_operator.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Security/2020-05-28-06-06-47.bpo-40791.QGZClX.rst diff --git a/Misc/NEWS.d/next/Security/2020-05-28-06-06-47.bpo-40791.QGZClX.rst b/Misc/NEWS.d/next/Security/2020-05-28-06-06-47.bpo-40791.QGZClX.rst new file mode 100644 index 00000000000000..69b9de1beae0d1 --- /dev/null +++ b/Misc/NEWS.d/next/Security/2020-05-28-06-06-47.bpo-40791.QGZClX.rst @@ -0,0 +1 @@ +Add ``volatile`` to the accumulator variable in ``hmac.compare_digest``, making constant-time-defeating optimizations less likely. \ No newline at end of file diff --git a/Modules/_operator.c b/Modules/_operator.c index 8a54829e5bbcc8..6f8f68f4599e4f 100644 --- a/Modules/_operator.c +++ b/Modules/_operator.c @@ -735,7 +735,7 @@ _tscmp(const unsigned char *a, const unsigned char *b, volatile const unsigned char *left; volatile const unsigned char *right; Py_ssize_t i; - unsigned char result; + volatile unsigned char result; /* loop count depends on length of b */ length = len_b; From 713b4bbd97392acc492a4fefb2d07ae61fb7b75d Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 21 Nov 2020 01:46:21 -0800 Subject: [PATCH 0723/1314] bpo-40550: Fix time-of-check/time-of-action issue in subprocess.Popen.send_signal. (GH-20010) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit send_signal() now swallows the exception if the process it thought was still alive winds up not to exist anymore (always a plausible race condition despite the checks). Co-authored-by: Gregory P. Smith (cherry picked from commit 01a202ab6b0ded546e47073db6498262086c52e9) Co-authored-by: Filipe Laíns --- Lib/subprocess.py | 6 +++++- Lib/test/test_subprocess.py | 13 +++++++++++++ .../2020-05-08-21-30-54.bpo-40550.i7GWkb.rst | 1 + 3 files changed, 19 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Library/2020-05-08-21-30-54.bpo-40550.i7GWkb.rst diff --git a/Lib/subprocess.py b/Lib/subprocess.py index 13600c28cf7117..f1d829a6f1724e 100644 --- a/Lib/subprocess.py +++ b/Lib/subprocess.py @@ -2061,7 +2061,11 @@ def send_signal(self, sig): # The race condition can still happen if the race condition # described above happens between the returncode test # and the kill() call. - os.kill(self.pid, sig) + try: + os.kill(self.pid, sig) + except ProcessLookupError: + # Supress the race condition error; bpo-40550. + pass def terminate(self): """Terminate the process with SIGTERM diff --git a/Lib/test/test_subprocess.py b/Lib/test/test_subprocess.py index 373542463f2e35..7373fe29c47d81 100644 --- a/Lib/test/test_subprocess.py +++ b/Lib/test/test_subprocess.py @@ -3160,6 +3160,19 @@ def test_send_signal_race(self): # so Popen failed to read it and uses a default returncode instead. self.assertIsNotNone(proc.returncode) + def test_send_signal_race2(self): + # bpo-40550: the process might exist between the returncode check and + # the kill operation + p = subprocess.Popen([sys.executable, '-c', 'exit(1)']) + + # wait for process to exit + while not p.returncode: + p.poll() + + with mock.patch.object(p, 'poll', new=lambda: None): + p.returncode = None + p.send_signal(signal.SIGTERM) + def test_communicate_repeated_call_after_stdout_close(self): proc = subprocess.Popen([sys.executable, '-c', 'import os, time; os.close(1), time.sleep(2)'], diff --git a/Misc/NEWS.d/next/Library/2020-05-08-21-30-54.bpo-40550.i7GWkb.rst b/Misc/NEWS.d/next/Library/2020-05-08-21-30-54.bpo-40550.i7GWkb.rst new file mode 100644 index 00000000000000..b0f3f03c34bbc5 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2020-05-08-21-30-54.bpo-40550.i7GWkb.rst @@ -0,0 +1 @@ +Fix time-of-check/time-of-action issue in subprocess.Popen.send_signal. From d153eb8a1e47123ecdb3fb47995a2c39ce7713ea Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 21 Nov 2020 03:09:40 -0800 Subject: [PATCH 0724/1314] bpo-42412: Fix possible leaks and check arguments in PyType_FromModuleAndSpec() (GH-23410) * There were leaks if Py_tp_bases is used more than once or if some call is failed before setting tp_bases. * There was a crash if the bases argument or the Py_tp_bases slot is not a tuple. * The documentation was not accurate. (cherry picked from commit 1db76394ea79030aa4ed5349c950f6c6da51450f) Co-authored-by: Serhiy Storchaka --- Doc/c-api/type.rst | 6 ++++-- Objects/typeobject.c | 23 ++++++++++++++++++----- 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/Doc/c-api/type.rst b/Doc/c-api/type.rst index 73f26875d8194a..822360e06170d9 100644 --- a/Doc/c-api/type.rst +++ b/Doc/c-api/type.rst @@ -155,7 +155,8 @@ The following functions and structs are used to create If *bases* is a tuple, the created heap type contains all types contained in it as base types. - If *bases* is ``NULL``, the *Py_tp_base* slot is used instead. + If *bases* is ``NULL``, the *Py_tp_bases* slot is used instead. + If that also is ``NULL``, the *Py_tp_base* slot is used instead. If that also is ``NULL``, the new type derives from :class:`object`. The *module* argument can be used to record the module in which the new @@ -247,7 +248,8 @@ The following functions and structs are used to create * :c:member:`~PyBufferProcs.bf_getbuffer` * :c:member:`~PyBufferProcs.bf_releasebuffer` - Setting :c:data:`Py_tp_bases` may be problematic on some platforms. + Setting :c:data:`Py_tp_bases` or :c:data:`Py_tp_base` may be + problematic on some platforms. To avoid issues, use the *bases* argument of :py:func:`PyType_FromSpecWithBases` instead. diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 1a12b0ce07fcff..acbe3fa3b5a7f1 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -2951,26 +2951,40 @@ PyType_FromModuleAndSpec(PyObject *module, PyType_Spec *spec, PyObject *bases) base = slot->pfunc; else if (slot->slot == Py_tp_bases) { bases = slot->pfunc; - Py_INCREF(bases); } } - if (!bases) + if (!bases) { bases = PyTuple_Pack(1, base); - if (!bases) + if (!bases) + goto fail; + } + else if (!PyTuple_Check(bases)) { + PyErr_SetString(PyExc_SystemError, "Py_tp_bases is not a tuple"); goto fail; + } + else { + Py_INCREF(bases); + } } - else + else if (!PyTuple_Check(bases)) { + PyErr_SetString(PyExc_SystemError, "bases is not a tuple"); + goto fail; + } + else { Py_INCREF(bases); + } /* Calculate best base, and check that all bases are type objects */ base = best_base(bases); if (base == NULL) { + Py_DECREF(bases); goto fail; } if (!_PyType_HasFeature(base, Py_TPFLAGS_BASETYPE)) { PyErr_Format(PyExc_TypeError, "type '%.100s' is not an acceptable base type", base->tp_name); + Py_DECREF(bases); goto fail; } @@ -2982,7 +2996,6 @@ PyType_FromModuleAndSpec(PyObject *module, PyType_Spec *spec, PyObject *bases) type->tp_as_buffer = &res->as_buffer; /* Set tp_base and tp_bases */ type->tp_bases = bases; - bases = NULL; Py_INCREF(base); type->tp_base = base; From 3b5b1c82a30506e2194fd1c9d9070e7215d79f41 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 21 Nov 2020 03:22:46 -0800 Subject: [PATCH 0725/1314] Fix wrong availability for signal.SIGCHLD (GH-23285) (#23425) I believe this is a mistake. SIGCHLD is only available on Unix systems, not Windows. (cherry picked from commit 4c24b08cd3239b417a5f8c7ba2ba54c840d051e3) Co-authored-by: Zhang Maiyun Co-authored-by: Zhang Maiyun --- Doc/library/signal.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/signal.rst b/Doc/library/signal.rst index 05b285ed110ec4..e1daeff48ad8fc 100644 --- a/Doc/library/signal.rst +++ b/Doc/library/signal.rst @@ -117,7 +117,7 @@ The variables defined in the :mod:`signal` module are: Child process stopped or terminated. - .. availability:: Windows. + .. availability:: Unix. .. data:: SIGCLD From 89d74d0acde25eed953dbfd56b1fafd0df78da7e Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 21 Nov 2020 12:20:26 -0800 Subject: [PATCH 0726/1314] Clarify that Set._from_iterable is not required to be a classmethod. (GH-23272) (GH-23450) --- Doc/library/collections.abc.rst | 2 +- Lib/test/test_collections.py | 56 +++++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+), 1 deletion(-) diff --git a/Doc/library/collections.abc.rst b/Doc/library/collections.abc.rst index db0e25bb0772eb..2345e78a17e4f5 100644 --- a/Doc/library/collections.abc.rst +++ b/Doc/library/collections.abc.rst @@ -291,7 +291,7 @@ Notes on using :class:`Set` and :class:`MutableSet` as a mixin: :meth:`_from_iterable` which calls ``cls(iterable)`` to produce a new set. If the :class:`Set` mixin is being used in a class with a different constructor signature, you will need to override :meth:`_from_iterable` - with a classmethod that can construct new instances from + with a classmethod or regular method that can construct new instances from an iterable argument. (2) diff --git a/Lib/test/test_collections.py b/Lib/test/test_collections.py index a8d3337ef5288d..6aa897927228cc 100644 --- a/Lib/test/test_collections.py +++ b/Lib/test/test_collections.py @@ -1558,6 +1558,62 @@ def assertSameSet(self, s1, s2): # coerce both to a real set then check equality self.assertSetEqual(set(s1), set(s2)) + def test_Set_from_iterable(self): + """Verify _from_iterable overriden to an instance method works.""" + class SetUsingInstanceFromIterable(MutableSet): + def __init__(self, values, created_by): + if not created_by: + raise ValueError(f'created_by must be specified') + self.created_by = created_by + self._values = set(values) + + def _from_iterable(self, values): + return type(self)(values, 'from_iterable') + + def __contains__(self, value): + return value in self._values + + def __iter__(self): + yield from self._values + + def __len__(self): + return len(self._values) + + def add(self, value): + self._values.add(value) + + def discard(self, value): + self._values.discard(value) + + impl = SetUsingInstanceFromIterable([1, 2, 3], 'test') + + actual = impl - {1} + self.assertIsInstance(actual, SetUsingInstanceFromIterable) + self.assertEqual('from_iterable', actual.created_by) + self.assertEqual({2, 3}, actual) + + actual = impl | {4} + self.assertIsInstance(actual, SetUsingInstanceFromIterable) + self.assertEqual('from_iterable', actual.created_by) + self.assertEqual({1, 2, 3, 4}, actual) + + actual = impl & {2} + self.assertIsInstance(actual, SetUsingInstanceFromIterable) + self.assertEqual('from_iterable', actual.created_by) + self.assertEqual({2}, actual) + + actual = impl ^ {3, 4} + self.assertIsInstance(actual, SetUsingInstanceFromIterable) + self.assertEqual('from_iterable', actual.created_by) + self.assertEqual({1, 2, 4}, actual) + + # NOTE: ixor'ing with a list is important here: internally, __ixor__ + # only calls _from_iterable if the other value isn't already a Set. + impl ^= [3, 4] + self.assertIsInstance(impl, SetUsingInstanceFromIterable) + self.assertEqual('test', impl.created_by) + self.assertEqual({1, 2, 4}, impl) + def test_Set_interoperability_with_real_sets(self): # Issue: 8743 class ListSet(Set): From 748d38bf529d71d87cc7ef6d63e9df7d7d771ac9 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 21 Nov 2020 17:45:21 -0800 Subject: [PATCH 0727/1314] [3.9] bpo-38443: Check that the specified universal architectures work (GH-22910) (GH-23451) As [[bpo-38443]()]() says the error message from configure when specifying --enable-universalsdk with a set of architectures that is not supported by the compiler is not very helpful. This PR explicitly checks if the compiler works and bails out if it doesn't. (cherry picked from commit 0f20bd9042c9b7fce20c3b9511cd0820b30094c3) Co-authored-by: Ronald Oussoren --- .../2020-10-23-10-26-53.bpo-38443.vu64tl.rst | 2 ++ configure | 25 +++++++++++++++++++ configure.ac | 7 ++++++ 3 files changed, 34 insertions(+) create mode 100644 Misc/NEWS.d/next/macOS/2020-10-23-10-26-53.bpo-38443.vu64tl.rst diff --git a/Misc/NEWS.d/next/macOS/2020-10-23-10-26-53.bpo-38443.vu64tl.rst b/Misc/NEWS.d/next/macOS/2020-10-23-10-26-53.bpo-38443.vu64tl.rst new file mode 100644 index 00000000000000..008c972e5c6ab0 --- /dev/null +++ b/Misc/NEWS.d/next/macOS/2020-10-23-10-26-53.bpo-38443.vu64tl.rst @@ -0,0 +1,2 @@ +The ``--enable-universalsdk`` and ``--with-universal-archs`` options for the +configure script now check that the specified architectures can be used. diff --git a/configure b/configure index 9e6fd4658333b4..040c828bf95ecb 100755 --- a/configure +++ b/configure @@ -7571,6 +7571,31 @@ $as_echo_n "checking which MACOSX_DEPLOYMENT_TARGET to use... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MACOSX_DEPLOYMENT_TARGET" >&5 $as_echo "$MACOSX_DEPLOYMENT_TARGET" >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if specified universal architectures work" >&5 +$as_echo_n "checking if specified universal architectures work... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +printf("%d", 42); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + as_fn_error $? "check config.log and use the '--with-universal-archs' option" "$LINENO" 5 + +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + # end of Darwin* tests ;; esac diff --git a/configure.ac b/configure.ac index d60f05251ab727..29acb8efa1ad38 100644 --- a/configure.ac +++ b/configure.ac @@ -1976,6 +1976,13 @@ yes) EXPORT_MACOSX_DEPLOYMENT_TARGET='' AC_MSG_RESULT($MACOSX_DEPLOYMENT_TARGET) + AC_MSG_CHECKING(if specified universal architectures work) + AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include ]], [[printf("%d", 42);]])], + [AC_MSG_RESULT(yes)], + [AC_MSG_RESULT(no) + AC_MSG_ERROR(check config.log and use the '--with-universal-archs' option) + ]) + # end of Darwin* tests ;; esac From dd20643b144d1c81989d235c3ec51f18fda618c2 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 21 Nov 2020 21:30:46 -0800 Subject: [PATCH 0728/1314] bpo-42426: IDLE: Fix reporting offset of the RE error in searchengine (GH-23447) (cherry picked from commit 453bc1da2023d6cbe362637a2e0b06d0521f013c) Co-authored-by: Serhiy Storchaka --- Lib/idlelib/NEWS.txt | 2 ++ Lib/idlelib/idle_test/test_searchengine.py | 6 ++++-- Lib/idlelib/searchengine.py | 11 ++++------- .../IDLE/2020-11-21-17-21-21.bpo-42426.kNnPoC.rst | 1 + 4 files changed, 11 insertions(+), 9 deletions(-) create mode 100644 Misc/NEWS.d/next/IDLE/2020-11-21-17-21-21.bpo-42426.kNnPoC.rst diff --git a/Lib/idlelib/NEWS.txt b/Lib/idlelib/NEWS.txt index 6eacde95d908da..e257ee9fdeb32d 100644 --- a/Lib/idlelib/NEWS.txt +++ b/Lib/idlelib/NEWS.txt @@ -3,6 +3,8 @@ Released on 2020-12-07? ====================================== +bpo-42426: Fix reporting offset of the RE error in searchengine. + bpo-42416: Get docstrings for IDLE calltips more often by using inspect.getdoc. diff --git a/Lib/idlelib/idle_test/test_searchengine.py b/Lib/idlelib/idle_test/test_searchengine.py index 3d26d62a95a873..f8401ce9380f25 100644 --- a/Lib/idlelib/idle_test/test_searchengine.py +++ b/Lib/idlelib/idle_test/test_searchengine.py @@ -175,11 +175,13 @@ def test_getprog(self): engine.setpat('') Equal(engine.getprog(), None) + Equal(Mbox.showerror.message, + 'Error: Empty regular expression') engine.setpat('+') engine.revar.set(1) Equal(engine.getprog(), None) - self.assertEqual(Mbox.showerror.message, - 'Error: nothing to repeat at position 0\nPattern: +') + Equal(Mbox.showerror.message, + 'Error: nothing to repeat\nPattern: +\nOffset: 0') def test_report_error(self): showerror = Mbox.showerror diff --git a/Lib/idlelib/searchengine.py b/Lib/idlelib/searchengine.py index 911e7d4691cac1..a50038e282ba6c 100644 --- a/Lib/idlelib/searchengine.py +++ b/Lib/idlelib/searchengine.py @@ -84,20 +84,17 @@ def getprog(self): flags = flags | re.IGNORECASE try: prog = re.compile(pat, flags) - except re.error as what: - args = what.args - msg = args[0] - col = args[1] if len(args) >= 2 else -1 - self.report_error(pat, msg, col) + except re.error as e: + self.report_error(pat, e.msg, e.pos) return None return prog - def report_error(self, pat, msg, col=-1): + def report_error(self, pat, msg, col=None): # Derived class could override this with something fancier msg = "Error: " + str(msg) if pat: msg = msg + "\nPattern: " + str(pat) - if col >= 0: + if col is not None: msg = msg + "\nOffset: " + str(col) tkMessageBox.showerror("Regular expression error", msg, master=self.root) diff --git a/Misc/NEWS.d/next/IDLE/2020-11-21-17-21-21.bpo-42426.kNnPoC.rst b/Misc/NEWS.d/next/IDLE/2020-11-21-17-21-21.bpo-42426.kNnPoC.rst new file mode 100644 index 00000000000000..0ab7972aad982e --- /dev/null +++ b/Misc/NEWS.d/next/IDLE/2020-11-21-17-21-21.bpo-42426.kNnPoC.rst @@ -0,0 +1 @@ +Fix reporting offset of the RE error in searchengine. From 4f87126969245861111cc12ca295899944c11b46 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 21 Nov 2020 22:24:21 -0800 Subject: [PATCH 0729/1314] bpo-42391: Clarify documentation of TestCase.assertIs (GH-23348) Removing 'evaluate' makes it more consistent with other assertX entries. (cherry picked from commit bd8c22e1fa8f8f6e31ee083a8b9321a2c324f02f) Co-authored-by: Ram Rachum --- Doc/library/unittest.rst | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Doc/library/unittest.rst b/Doc/library/unittest.rst index 523e0e6f6e0f35..9fc6620335f88c 100644 --- a/Doc/library/unittest.rst +++ b/Doc/library/unittest.rst @@ -897,8 +897,7 @@ Test cases .. method:: assertIs(first, second, msg=None) assertIsNot(first, second, msg=None) - Test that *first* and *second* evaluate (or don't evaluate) to the - same object. + Test that *first* and *second* are (or are not) the same object. .. versionadded:: 3.1 From 0aab3522b259c40abf1f070c71aa7b914c1239b5 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 21 Nov 2020 22:35:36 -0800 Subject: [PATCH 0730/1314] bpo-41116: Ensure system supplied libraries are found on macOS 11 (GH-23301) (GH-23455) On macOS system provided libraries are in a shared library cache and not at their usual location. This PR teaches distutils to search in the SDK, even if there was no "-sysroot" argument in the compiler flags. (cherry picked from commit 404a719b5127602c1a948f8e189ab61cd3f147d8) Co-authored-by: Ronald Oussoren --- Lib/_osx_support.py | 34 +++++++++++++++++-- Lib/distutils/unixccompiler.py | 2 +- .../2020-11-15-16-43-45.bpo-41116.oCkbrF.rst | 1 + setup.py | 31 +++-------------- 4 files changed, 38 insertions(+), 30 deletions(-) create mode 100644 Misc/NEWS.d/next/macOS/2020-11-15-16-43-45.bpo-41116.oCkbrF.rst diff --git a/Lib/_osx_support.py b/Lib/_osx_support.py index e9efce7d7ed5bd..11129909241f2a 100644 --- a/Lib/_osx_support.py +++ b/Lib/_osx_support.py @@ -52,7 +52,7 @@ def _find_executable(executable, path=None): return executable -def _read_output(commandstring): +def _read_output(commandstring, capture_stderr=False): """Output from successful command execution or None""" # Similar to os.popen(commandstring, "r").read(), # but without actually using os.popen because that @@ -67,7 +67,10 @@ def _read_output(commandstring): os.getpid(),), "w+b") with contextlib.closing(fp) as fp: - cmd = "%s 2>/dev/null >'%s'" % (commandstring, fp.name) + if capture_stderr: + cmd = "%s >'%s' 2>&1" % (commandstring, fp.name) + else: + cmd = "%s 2>/dev/null >'%s'" % (commandstring, fp.name) return fp.read().decode('utf-8').strip() if not os.system(cmd) else None @@ -125,6 +128,33 @@ def _save_modified_value(_config_vars, cv, newvalue): _config_vars[_INITPRE + cv] = oldvalue _config_vars[cv] = newvalue + +_cache_default_sysroot = None +def _default_sysroot(cc): + """ Returns the root of the default SDK for this system, or '/' """ + global _cache_default_sysroot + + if _cache_default_sysroot is not None: + return _cache_default_sysroot + + contents = _read_output('%s -c -E -v - "): + in_incdirs = True + elif line.startswith("End of search list"): + in_incdirs = False + elif in_incdirs: + line = line.strip() + if line == '/usr/include': + _cache_default_sysroot = '/' + elif line.endswith(".sdk/usr/include"): + _cache_default_sysroot = line[:-12] + if _cache_default_sysroot is None: + _cache_default_sysroot = '/' + + return _cache_default_sysroot + def _supports_universal_builds(): """Returns True if universal builds are supported on this system""" # As an approximation, we assume that if we are running on 10.4 or above, diff --git a/Lib/distutils/unixccompiler.py b/Lib/distutils/unixccompiler.py index 4d7a6de740ab3a..f0792de74a1a48 100644 --- a/Lib/distutils/unixccompiler.py +++ b/Lib/distutils/unixccompiler.py @@ -290,7 +290,7 @@ def find_library_file(self, dirs, lib, debug=0): cflags = sysconfig.get_config_var('CFLAGS') m = re.search(r'-isysroot\s*(\S+)', cflags) if m is None: - sysroot = '/' + sysroot = _osx_support._default_sysroot(sysconfig.get_config_var('CC')) else: sysroot = m.group(1) diff --git a/Misc/NEWS.d/next/macOS/2020-11-15-16-43-45.bpo-41116.oCkbrF.rst b/Misc/NEWS.d/next/macOS/2020-11-15-16-43-45.bpo-41116.oCkbrF.rst new file mode 100644 index 00000000000000..c982224e92d719 --- /dev/null +++ b/Misc/NEWS.d/next/macOS/2020-11-15-16-43-45.bpo-41116.oCkbrF.rst @@ -0,0 +1 @@ +Ensure distutils.unixxcompiler.find_library_file can find system provided libraries on macOS 11. \ No newline at end of file diff --git a/setup.py b/setup.py index 0a6cd8ca2e9acb..103688285e68ff 100644 --- a/setup.py +++ b/setup.py @@ -9,6 +9,7 @@ import sys import sysconfig from glob import glob, escape +import _osx_support try: @@ -176,34 +177,10 @@ def macosx_sdk_root(): m = re.search(r'-isysroot\s*(\S+)', cflags) if m is not None: MACOS_SDK_ROOT = m.group(1) - MACOS_SDK_SPECIFIED = MACOS_SDK_ROOT != '/' else: - MACOS_SDK_ROOT = '/' - MACOS_SDK_SPECIFIED = False - cc = sysconfig.get_config_var('CC') - tmpfile = '/tmp/setup_sdk_root.%d' % os.getpid() - try: - os.unlink(tmpfile) - except: - pass - ret = run_command('%s -E -v - %s 1>/dev/null' % (cc, tmpfile)) - in_incdirs = False - try: - if ret == 0: - with open(tmpfile) as fp: - for line in fp.readlines(): - if line.startswith("#include <...>"): - in_incdirs = True - elif line.startswith("End of search list"): - in_incdirs = False - elif in_incdirs: - line = line.strip() - if line == '/usr/include': - MACOS_SDK_ROOT = '/' - elif line.endswith(".sdk/usr/include"): - MACOS_SDK_ROOT = line[:-12] - finally: - os.unlink(tmpfile) + MACOS_SDK_ROOT = _osx_support._default_sysroot( + sysconfig.get_config_var('CC')) + MACOS_SDK_SPECIFIED = MACOS_SDK_ROOT != '/' return MACOS_SDK_ROOT From e8b1c038b14b5fc8120aab62c9bf5fb840274cb6 Mon Sep 17 00:00:00 2001 From: Ronald Oussoren Date: Sun, 22 Nov 2020 11:18:40 +0100 Subject: [PATCH 0731/1314] [3.9] bpo-41100: Support macOS 11 and Apple Silicon (GH-22855) (GH-23295) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * [3.9] bpo-41100: Support macOS 11 and Apple Silicon (GH-22855) Co-authored-by: Lawrence D’Anna * Add support for macOS 11 and Apple Silicon (aka arm64) As a side effect of this work use the system copy of libffi on macOS, and remove the vendored copy * Support building on recent versions of macOS while deploying to older versions This allows building installers on macOS 11 while still supporting macOS 10.9.. (cherry picked from commit 41761933c1c30bb6003b65eef1ba23a83db4eae4) Co-authored-by: Ronald Oussoren * Back port of changes to _decimal to support arm64 * temp_dir is in test.support in 3.9 --- Lib/_osx_support.py | 44 +- Lib/ctypes/macholib/dyld.py | 12 + Lib/ctypes/test/test_macholib.py | 15 +- Lib/distutils/tests/test_build_ext.py | 2 +- Lib/test/test_bytes.py | 1 + Lib/test/test_platform.py | 2 +- Lib/test/test_posix.py | 228 +++++ Lib/test/test_time.py | 30 + Lib/test/test_unicode.py | 2 + Mac/BuildScript/build-installer.py | 30 +- Mac/BuildScript/openssl-mac-arm64.patch | 41 + Mac/README.rst | 37 + Mac/Tools/pythonw.c | 12 +- .../2020-11-01-16-40-23.bpo-41100.BApztP.rst | 8 + Modules/_ctypes/callbacks.c | 39 +- Modules/_ctypes/callproc.c | 127 ++- Modules/_ctypes/ctypes.h | 8 + Modules/_ctypes/malloc_closure.c | 15 +- Modules/_decimal/libmpdec/mpdecimal.h | 3 + Modules/getpath.c | 4 - Modules/posixmodule.c | 825 ++++++++++++++---- Modules/timemodule.c | 214 +++-- Python/bootstrap_hash.c | 42 +- Python/pytime.c | 31 +- configure | 45 +- configure.ac | 24 +- pyconfig.h.in | 3 + setup.py | 94 +- 28 files changed, 1592 insertions(+), 346 deletions(-) create mode 100644 Mac/BuildScript/openssl-mac-arm64.patch create mode 100644 Misc/NEWS.d/next/macOS/2020-11-01-16-40-23.bpo-41100.BApztP.rst diff --git a/Lib/_osx_support.py b/Lib/_osx_support.py index 11129909241f2a..37975fe8a3eefa 100644 --- a/Lib/_osx_support.py +++ b/Lib/_osx_support.py @@ -113,6 +113,26 @@ def _get_system_version(): return _SYSTEM_VERSION +_SYSTEM_VERSION_TUPLE = None +def _get_system_version_tuple(): + """ + Return the macOS system version as a tuple + + The return value is safe to use to compare + two version numbers. + """ + global _SYSTEM_VERSION_TUPLE + if _SYSTEM_VERSION_TUPLE is None: + osx_version = _get_system_version() + if osx_version: + try: + _SYSTEM_VERSION_TUPLE = tuple(int(i) for i in osx_version.split('.')) + except ValueError: + _SYSTEM_VERSION_TUPLE = () + + return _SYSTEM_VERSION_TUPLE + + def _remove_original_values(_config_vars): """Remove original unmodified values for testing""" # This is needed for higher-level cross-platform tests of get_platform. @@ -162,14 +182,18 @@ def _supports_universal_builds(): # builds, in particular -isysroot and -arch arguments to the compiler. This # is in support of allowing 10.4 universal builds to run on 10.3.x systems. - osx_version = _get_system_version() - if osx_version: - try: - osx_version = tuple(int(i) for i in osx_version.split('.')) - except ValueError: - osx_version = '' + osx_version = _get_system_version_tuple() return bool(osx_version >= (10, 4)) if osx_version else False +def _supports_arm64_builds(): + """Returns True if arm64 builds are supported on this system""" + # There are two sets of systems supporting macOS/arm64 builds: + # 1. macOS 11 and later, unconditionally + # 2. macOS 10.15 with Xcode 12.2 or later + # For now the second category is ignored. + osx_version = _get_system_version_tuple() + return osx_version >= (11, 0) if osx_version else False + def _find_appropriate_compiler(_config_vars): """Find appropriate C compiler for extension module builds""" @@ -361,6 +385,12 @@ def compiler_fixup(compiler_so, cc_args): except ValueError: break + elif not _supports_arm64_builds(): + # Look for "-arch arm64" and drop that + for idx in reversed(range(len(compiler_so))): + if compiler_so[idx] == '-arch' and compiler_so[idx+1] == "arm64": + del compiler_so[idx:idx+2] + if 'ARCHFLAGS' in os.environ and not stripArch: # User specified different -arch flags in the environ, # see also distutils.sysconfig @@ -511,6 +541,8 @@ def get_platform_osx(_config_vars, osname, release, machine): if len(archs) == 1: machine = archs[0] + elif archs == ('arm64', 'x86_64'): + machine = 'universal2' elif archs == ('i386', 'ppc'): machine = 'fat' elif archs == ('i386', 'x86_64'): diff --git a/Lib/ctypes/macholib/dyld.py b/Lib/ctypes/macholib/dyld.py index 9d86b058765a3e..1c3f8fd38b0665 100644 --- a/Lib/ctypes/macholib/dyld.py +++ b/Lib/ctypes/macholib/dyld.py @@ -6,6 +6,11 @@ from ctypes.macholib.framework import framework_info from ctypes.macholib.dylib import dylib_info from itertools import * +try: + from _ctypes import _dyld_shared_cache_contains_path +except ImportError: + def _dyld_shared_cache_contains_path(*args): + raise NotImplementedError __all__ = [ 'dyld_find', 'framework_find', @@ -122,8 +127,15 @@ def dyld_find(name, executable_path=None, env=None): dyld_executable_path_search(name, executable_path), dyld_default_search(name, env), ), env): + if os.path.isfile(path): return path + try: + if _dyld_shared_cache_contains_path(path): + return path + except NotImplementedError: + pass + raise ValueError("dylib %s could not be found" % (name,)) def framework_find(fn, executable_path=None, env=None): diff --git a/Lib/ctypes/test/test_macholib.py b/Lib/ctypes/test/test_macholib.py index 6b3526951acfab..a1bac26a7df058 100644 --- a/Lib/ctypes/test/test_macholib.py +++ b/Lib/ctypes/test/test_macholib.py @@ -45,19 +45,22 @@ def find_lib(name): class MachOTest(unittest.TestCase): @unittest.skipUnless(sys.platform == "darwin", 'OSX-specific test') def test_find(self): - - self.assertEqual(find_lib('pthread'), - '/usr/lib/libSystem.B.dylib') + # On Mac OS 11, system dylibs are only present in the shared cache, + # so symlinks like libpthread.dylib -> libSystem.B.dylib will not + # be resolved by dyld_find + self.assertIn(find_lib('pthread'), + ('/usr/lib/libSystem.B.dylib', '/usr/lib/libpthread.dylib')) result = find_lib('z') # Issue #21093: dyld default search path includes $HOME/lib and # /usr/local/lib before /usr/lib, which caused test failures if # a local copy of libz exists in one of them. Now ignore the head # of the path. - self.assertRegex(result, r".*/lib/libz\..*.*\.dylib") + self.assertRegex(result, r".*/lib/libz.*\.dylib") - self.assertEqual(find_lib('IOKit'), - '/System/Library/Frameworks/IOKit.framework/Versions/A/IOKit') + self.assertIn(find_lib('IOKit'), + ('/System/Library/Frameworks/IOKit.framework/Versions/A/IOKit', + '/System/Library/Frameworks/IOKit.framework/IOKit')) if __name__ == "__main__": unittest.main() diff --git a/Lib/distutils/tests/test_build_ext.py b/Lib/distutils/tests/test_build_ext.py index 5e47e0773a9649..5a32e039800f0c 100644 --- a/Lib/distutils/tests/test_build_ext.py +++ b/Lib/distutils/tests/test_build_ext.py @@ -492,7 +492,7 @@ def _try_compile_deployment_target(self, operator, target): # format the target value as defined in the Apple # Availability Macros. We can't use the macro names since # at least one value we test with will not exist yet. - if target[1] < 10: + if target[:2] < (10, 10): # for 10.1 through 10.9.x -> "10n0" target = '%02d%01d0' % target else: diff --git a/Lib/test/test_bytes.py b/Lib/test/test_bytes.py index 770e2c5592cc61..05568f2c679719 100644 --- a/Lib/test/test_bytes.py +++ b/Lib/test/test_bytes.py @@ -1034,6 +1034,7 @@ def test_from_format(self): c_char_p) PyBytes_FromFormat = pythonapi.PyBytes_FromFormat + PyBytes_FromFormat.argtypes = (c_char_p,) PyBytes_FromFormat.restype = py_object # basic tests diff --git a/Lib/test/test_platform.py b/Lib/test/test_platform.py index a5c35dff79b8bc..bd953b5d677ef6 100644 --- a/Lib/test/test_platform.py +++ b/Lib/test/test_platform.py @@ -245,7 +245,7 @@ def test_mac_ver(self): self.assertEqual(res[1], ('', '', '')) if sys.byteorder == 'little': - self.assertIn(res[2], ('i386', 'x86_64')) + self.assertIn(res[2], ('i386', 'x86_64', 'arm64')) else: self.assertEqual(res[2], 'PowerPC') diff --git a/Lib/test/test_posix.py b/Lib/test/test_posix.py index be121ae463dbb3..f4edb8bd9575f4 100644 --- a/Lib/test/test_posix.py +++ b/Lib/test/test_posix.py @@ -1905,6 +1905,233 @@ def test_posix_spawnp(self): assert_python_ok(*args, PATH=path) +@unittest.skipUnless(sys.platform == "darwin", "test weak linking on macOS") +class TestPosixWeaklinking(unittest.TestCase): + # These test cases verify that weak linking support on macOS works + # as expected. These cases only test new behaviour introduced by weak linking, + # regular behaviour is tested by the normal test cases. + # + # See the section on Weak Linking in Mac/README.txt for more information. + def setUp(self): + import sysconfig + import platform + + config_vars = sysconfig.get_config_vars() + self.available = { nm for nm in config_vars if nm.startswith("HAVE_") and config_vars[nm] } + self.mac_ver = tuple(int(part) for part in platform.mac_ver()[0].split(".")) + + def _verify_available(self, name): + if name not in self.available: + raise unittest.SkipTest(f"{name} not weak-linked") + + def test_pwritev(self): + self._verify_available("HAVE_PWRITEV") + if self.mac_ver >= (10, 16): + self.assertTrue(hasattr(os, "pwritev"), "os.pwritev is not available") + self.assertTrue(hasattr(os, "preadv"), "os.readv is not available") + + else: + self.assertFalse(hasattr(os, "pwritev"), "os.pwritev is available") + self.assertFalse(hasattr(os, "preadv"), "os.readv is available") + + def test_stat(self): + self._verify_available("HAVE_FSTATAT") + if self.mac_ver >= (10, 10): + self.assertIn("HAVE_FSTATAT", posix._have_functions) + + else: + self.assertNotIn("HAVE_FSTATAT", posix._have_functions) + + with self.assertRaisesRegex(NotImplementedError, "dir_fd unavailable"): + os.stat("file", dir_fd=0) + + def test_access(self): + self._verify_available("HAVE_FACCESSAT") + if self.mac_ver >= (10, 10): + self.assertIn("HAVE_FACCESSAT", posix._have_functions) + + else: + self.assertNotIn("HAVE_FACCESSAT", posix._have_functions) + + with self.assertRaisesRegex(NotImplementedError, "dir_fd unavailable"): + os.access("file", os.R_OK, dir_fd=0) + + with self.assertRaisesRegex(NotImplementedError, "follow_symlinks unavailable"): + os.access("file", os.R_OK, follow_symlinks=False) + + with self.assertRaisesRegex(NotImplementedError, "effective_ids unavailable"): + os.access("file", os.R_OK, effective_ids=True) + + def test_chmod(self): + self._verify_available("HAVE_FCHMODAT") + if self.mac_ver >= (10, 10): + self.assertIn("HAVE_FCHMODAT", posix._have_functions) + + else: + self.assertNotIn("HAVE_FCHMODAT", posix._have_functions) + self.assertIn("HAVE_LCHMOD", posix._have_functions) + + with self.assertRaisesRegex(NotImplementedError, "dir_fd unavailable"): + os.chmod("file", 0o644, dir_fd=0) + + def test_chown(self): + self._verify_available("HAVE_FCHOWNAT") + if self.mac_ver >= (10, 10): + self.assertIn("HAVE_FCHOWNAT", posix._have_functions) + + else: + self.assertNotIn("HAVE_FCHOWNAT", posix._have_functions) + self.assertIn("HAVE_LCHOWN", posix._have_functions) + + with self.assertRaisesRegex(NotImplementedError, "dir_fd unavailable"): + os.chown("file", 0, 0, dir_fd=0) + + def test_link(self): + self._verify_available("HAVE_LINKAT") + if self.mac_ver >= (10, 10): + self.assertIn("HAVE_LINKAT", posix._have_functions) + + else: + self.assertNotIn("HAVE_LINKAT", posix._have_functions) + + with self.assertRaisesRegex(NotImplementedError, "src_dir_fd unavailable"): + os.link("source", "target", src_dir_fd=0) + + with self.assertRaisesRegex(NotImplementedError, "dst_dir_fd unavailable"): + os.link("source", "target", dst_dir_fd=0) + + with self.assertRaisesRegex(NotImplementedError, "src_dir_fd unavailable"): + os.link("source", "target", src_dir_fd=0, dst_dir_fd=0) + + # issue 41355: !HAVE_LINKAT code path ignores the follow_symlinks flag + with support.temp_dir() as base_path: + link_path = os.path.join(base_path, "link") + target_path = os.path.join(base_path, "target") + source_path = os.path.join(base_path, "source") + + with open(source_path, "w") as fp: + fp.write("data") + + os.symlink("target", link_path) + + # Calling os.link should fail in the link(2) call, and + # should not reject *follow_symlinks* (to match the + # behaviour you'd get when building on a platform without + # linkat) + with self.assertRaises(FileExistsError): + os.link(source_path, link_path, follow_symlinks=True) + + with self.assertRaises(FileExistsError): + os.link(source_path, link_path, follow_symlinks=False) + + + def test_listdir_scandir(self): + self._verify_available("HAVE_FDOPENDIR") + if self.mac_ver >= (10, 10): + self.assertIn("HAVE_FDOPENDIR", posix._have_functions) + + else: + self.assertNotIn("HAVE_FDOPENDIR", posix._have_functions) + + with self.assertRaisesRegex(TypeError, "listdir: path should be string, bytes, os.PathLike or None, not int"): + os.listdir(0) + + with self.assertRaisesRegex(TypeError, "scandir: path should be string, bytes, os.PathLike or None, not int"): + os.scandir(0) + + def test_mkdir(self): + self._verify_available("HAVE_MKDIRAT") + if self.mac_ver >= (10, 10): + self.assertIn("HAVE_MKDIRAT", posix._have_functions) + + else: + self.assertNotIn("HAVE_MKDIRAT", posix._have_functions) + + with self.assertRaisesRegex(NotImplementedError, "dir_fd unavailable"): + os.mkdir("dir", dir_fd=0) + + def test_rename_replace(self): + self._verify_available("HAVE_RENAMEAT") + if self.mac_ver >= (10, 10): + self.assertIn("HAVE_RENAMEAT", posix._have_functions) + + else: + self.assertNotIn("HAVE_RENAMEAT", posix._have_functions) + + with self.assertRaisesRegex(NotImplementedError, "src_dir_fd and dst_dir_fd unavailable"): + os.rename("a", "b", src_dir_fd=0) + + with self.assertRaisesRegex(NotImplementedError, "src_dir_fd and dst_dir_fd unavailable"): + os.rename("a", "b", dst_dir_fd=0) + + with self.assertRaisesRegex(NotImplementedError, "src_dir_fd and dst_dir_fd unavailable"): + os.replace("a", "b", src_dir_fd=0) + + with self.assertRaisesRegex(NotImplementedError, "src_dir_fd and dst_dir_fd unavailable"): + os.replace("a", "b", dst_dir_fd=0) + + def test_unlink_rmdir(self): + self._verify_available("HAVE_UNLINKAT") + if self.mac_ver >= (10, 10): + self.assertIn("HAVE_UNLINKAT", posix._have_functions) + + else: + self.assertNotIn("HAVE_UNLINKAT", posix._have_functions) + + with self.assertRaisesRegex(NotImplementedError, "dir_fd unavailable"): + os.unlink("path", dir_fd=0) + + with self.assertRaisesRegex(NotImplementedError, "dir_fd unavailable"): + os.rmdir("path", dir_fd=0) + + def test_open(self): + self._verify_available("HAVE_OPENAT") + if self.mac_ver >= (10, 10): + self.assertIn("HAVE_OPENAT", posix._have_functions) + + else: + self.assertNotIn("HAVE_OPENAT", posix._have_functions) + + with self.assertRaisesRegex(NotImplementedError, "dir_fd unavailable"): + os.open("path", os.O_RDONLY, dir_fd=0) + + def test_readlink(self): + self._verify_available("HAVE_READLINKAT") + if self.mac_ver >= (10, 10): + self.assertIn("HAVE_READLINKAT", posix._have_functions) + + else: + self.assertNotIn("HAVE_READLINKAT", posix._have_functions) + + with self.assertRaisesRegex(NotImplementedError, "dir_fd unavailable"): + os.readlink("path", dir_fd=0) + + def test_symlink(self): + self._verify_available("HAVE_SYMLINKAT") + if self.mac_ver >= (10, 10): + self.assertIn("HAVE_SYMLINKAT", posix._have_functions) + + else: + self.assertNotIn("HAVE_SYMLINKAT", posix._have_functions) + + with self.assertRaisesRegex(NotImplementedError, "dir_fd unavailable"): + os.symlink("a", "b", dir_fd=0) + + def test_utime(self): + self._verify_available("HAVE_FUTIMENS") + self._verify_available("HAVE_UTIMENSAT") + if self.mac_ver >= (10, 13): + self.assertIn("HAVE_FUTIMENS", posix._have_functions) + self.assertIn("HAVE_UTIMENSAT", posix._have_functions) + + else: + self.assertNotIn("HAVE_FUTIMENS", posix._have_functions) + self.assertNotIn("HAVE_UTIMENSAT", posix._have_functions) + + with self.assertRaisesRegex(NotImplementedError, "dir_fd unavailable"): + os.utime("path", dir_fd=0) + + def test_main(): try: support.run_unittest( @@ -1912,6 +2139,7 @@ def test_main(): PosixGroupsTester, TestPosixSpawn, TestPosixSpawnP, + TestPosixWeaklinking ) finally: support.reap_children() diff --git a/Lib/test/test_time.py b/Lib/test/test_time.py index 80e43fafad8130..6674edc21e9dfa 100644 --- a/Lib/test/test_time.py +++ b/Lib/test/test_time.py @@ -1040,6 +1040,36 @@ def test_object_to_timespec(self): with self.assertRaises(ValueError): pytime_object_to_timespec(float('nan'), time_rnd) +@unittest.skipUnless(sys.platform == "darwin", "test weak linking on macOS") +class TestTimeWeaklinking(unittest.TestCase): + # These test cases verify that weak linking support on macOS works + # as expected. These cases only test new behaviour introduced by weak linking, + # regular behaviour is tested by the normal test cases. + # + # See the section on Weak Linking in Mac/README.txt for more information. + def test_clock_functions(self): + import sysconfig + import platform + + config_vars = sysconfig.get_config_vars() + var_name = "HAVE_CLOCK_GETTIME" + if var_name not in config_vars or not config_vars[var_name]: + raise unittest.SkipTest(f"{var_name} is not available") + + mac_ver = tuple(int(x) for x in platform.mac_ver()[0].split(".")) + + clock_names = [ + "CLOCK_MONOTONIC", "clock_gettime", "clock_gettime_ns", "clock_settime", + "clock_settime_ns", "clock_getres"] + + if mac_ver >= (10, 12): + for name in clock_names: + self.assertTrue(hasattr(time, name), f"time.{name} is not available") + + else: + for name in clock_names: + self.assertFalse(hasattr(time, name), f"time.{name} is available") + if __name__ == "__main__": unittest.main() diff --git a/Lib/test/test_unicode.py b/Lib/test/test_unicode.py index 2ee4e64d635303..23508c56e7ffef 100644 --- a/Lib/test/test_unicode.py +++ b/Lib/test/test_unicode.py @@ -2523,11 +2523,13 @@ class CAPITest(unittest.TestCase): def test_from_format(self): support.import_module('ctypes') from ctypes import ( + c_char_p, pythonapi, py_object, sizeof, c_int, c_long, c_longlong, c_ssize_t, c_uint, c_ulong, c_ulonglong, c_size_t, c_void_p) name = "PyUnicode_FromFormat" _PyUnicode_FromFormat = getattr(pythonapi, name) + _PyUnicode_FromFormat.argtypes = (c_char_p,) _PyUnicode_FromFormat.restype = py_object def PyUnicode_FromFormat(format, *args): diff --git a/Mac/BuildScript/build-installer.py b/Mac/BuildScript/build-installer.py index 2548b212d9ea42..0e76d3ca5bbc2e 100755 --- a/Mac/BuildScript/build-installer.py +++ b/Mac/BuildScript/build-installer.py @@ -116,7 +116,8 @@ def getFullVersion(): DEPSRC = os.path.join(WORKDIR, 'third-party') DEPSRC = os.path.expanduser('~/Universal/other-sources') -universal_opts_map = { '32-bit': ('i386', 'ppc',), +universal_opts_map = { 'universal2': ('arm64', 'x86_64'), + '32-bit': ('i386', 'ppc',), '64-bit': ('x86_64', 'ppc64',), 'intel': ('i386', 'x86_64'), 'intel-32': ('i386',), @@ -124,6 +125,7 @@ def getFullVersion(): '3-way': ('ppc', 'i386', 'x86_64'), 'all': ('i386', 'ppc', 'x86_64', 'ppc64',) } default_target_map = { + 'universal2': '10.9', '64-bit': '10.5', '3-way': '10.5', 'intel': '10.5', @@ -190,6 +192,27 @@ def getTargetCompilers(): def internalTk(): return getDeptargetTuple() >= (10, 6) + +def tweak_tcl_build(basedir, archList): + with open("Makefile", "r") as fp: + contents = fp.readlines() + + # For reasons I don't understand the tcl configure script + # decides that some stdlib symbols aren't present, before + # deciding that strtod is broken. + new_contents = [] + for line in contents: + if line.startswith("COMPAT_OBJS"): + # note: the space before strtod.o is intentional, + # the detection of a broken strtod results in + # "fixstrod.o" on this line. + for nm in ("strstr.o", "strtoul.o", " strtod.o"): + line = line.replace(nm, "") + new_contents.append(line) + + with open("Makefile", "w") as fp: + fp.writelines(new_contents) + # List of names of third party software built with this installer. # The names will be inserted into the rtf version of the License. THIRD_PARTY_LIBS = [] @@ -215,6 +238,9 @@ def library_recipes(): buildrecipe=build_universal_openssl, configure=None, install=None, + patches=[ + "openssl-mac-arm64.patch", + ], ), ]) @@ -231,6 +257,7 @@ def library_recipes(): '--libdir=/Library/Frameworks/Python.framework/Versions/%s/lib'%(getVersion(),), ], useLDFlags=False, + buildrecipe=tweak_tcl_build, install='make TCL_LIBRARY=%(TCL_LIBRARY)s && make install TCL_LIBRARY=%(TCL_LIBRARY)s DESTDIR=%(DESTDIR)s'%{ "DESTDIR": shellQuote(os.path.join(WORKDIR, 'libraries')), "TCL_LIBRARY": shellQuote('/Library/Frameworks/Python.framework/Versions/%s/lib/tcl8.6'%(getVersion())), @@ -801,6 +828,7 @@ def build_openssl_arch(archbase, arch): arch_opts = { "i386": ["darwin-i386-cc"], "x86_64": ["darwin64-x86_64-cc", "enable-ec_nistp_64_gcc_128"], + "arm64": ["darwin64-arm64-cc"], "ppc": ["darwin-ppc-cc"], "ppc64": ["darwin64-ppc-cc"], } diff --git a/Mac/BuildScript/openssl-mac-arm64.patch b/Mac/BuildScript/openssl-mac-arm64.patch new file mode 100644 index 00000000000000..11267fb118744a --- /dev/null +++ b/Mac/BuildScript/openssl-mac-arm64.patch @@ -0,0 +1,41 @@ +diff -ur openssl-1.1.1g-orig/Configurations/10-main.conf openssl-1.1.1g/Configurations/10-main.conf +--- openssl-1.1.1g-orig/Configurations/10-main.conf 2020-04-21 14:22:39.000000000 +0200 ++++ openssl-1.1.1g/Configurations/10-main.conf 2020-07-26 12:21:32.000000000 +0200 +@@ -1557,6 +1557,14 @@ + bn_ops => "SIXTY_FOUR_BIT_LONG", + perlasm_scheme => "macosx", + }, ++ "darwin64-arm64-cc" => { ++ inherit_from => [ "darwin-common", asm("aarch64_asm") ], ++ CFLAGS => add("-Wall"), ++ cflags => add("-arch arm64"), ++ lib_cppflags => add("-DL_ENDIAN"), ++ bn_ops => "SIXTY_FOUR_BIT_LONG", ++ perlasm_scheme => "ios64", ++ }, + + ##### GNU Hurd + "hurd-x86" => { +diff -ur openssl-1.1.1g-orig/config openssl-1.1.1g/config +--- openssl-1.1.1g-orig/config 2020-04-21 14:22:39.000000000 +0200 ++++ openssl-1.1.1g/config 2020-07-26 12:21:59.000000000 +0200 +@@ -255,6 +255,9 @@ + ;; + x86_64) + echo "x86_64-apple-darwin${VERSION}" ++ ;; ++ arm64) ++ echo "arm64-apple-darwin${VERSION}" + ;; + *) + echo "i686-apple-darwin${VERSION}" +@@ -497,6 +500,9 @@ + else + OUT="darwin64-x86_64-cc" + fi ;; ++ x86_64-apple-darwin*) ++ OUT="darwin64-arm64-cc" ++ ;; + armv6+7-*-iphoneos) + __CNF_CFLAGS="$__CNF_CFLAGS -arch armv6 -arch armv7" + __CNF_CXXFLAGS="$__CNF_CXXFLAGS -arch armv6 -arch armv7" diff --git a/Mac/README.rst b/Mac/README.rst index ec7d873df277d7..f3638aa0019aaf 100644 --- a/Mac/README.rst +++ b/Mac/README.rst @@ -120,6 +120,8 @@ support ppc (Xcode 4 on 10.6 and later systems). The flavor can be specified using the configure option ``--with-universal-archs=VALUE``. The following values are available: + * ``universal2``: ``arm64``, ``x86_64`` + * ``intel``: ``i386``, ``x86_64`` * ``intel-32``: ``i386`` @@ -155,6 +157,8 @@ following combinations of SDKs and universal-archs flavors are available: * 10.15 and later SDKs support ``intel-64`` only + * 11.0 and later SDKs support ``universal2`` + The makefile for a framework build will also install ``python3.x-32`` binaries when the universal architecture includes at least one 32-bit architecture (that is, for all flavors but ``64-bit`` and ``intel-64``). @@ -352,6 +356,39 @@ A framework install also installs some applications in ``/Applications/Python X. And lastly a framework installation installs files in ``/usr/local/bin``, all of them symbolic links to files in ``/Library/Frameworks/Python.framework/Versions/X.Y/bin``. +Weak linking support +==================== + +The CPython sources support building with the latest SDK while targetting deployment +to macOS 10.9. This is done through weak linking of symbols introduced in macOS +10.10 or later and checking for their availability at runtime. + +This requires the use of Apple's compiler toolchain on macOS 10.13 or later. + +The basic implementation pattern is: + +* ``HAVE_`` is a macro defined (or not) by the configure script + +* ``HAVE__RUNTIME`` is a macro defined in the relevant source + files. This expands to a call to ``__builtin_available`` when using + a new enough Apple compiler, and to a true value otherwise. + +* Use ``HAVE__RUNTIME`` before calling ````. This macro + *must* be used a the sole expression in an if statement:: + + if (HAVE__RUNTIME) { + /* is available */ + } + + Or: + + if (HAVE__RUNTIME) {} else { + /* is not available */ + } + + Using other patterns (such as ``!HAVE__RUNTIME``) is not supported + by Apple's compilers. + Resources ========= diff --git a/Mac/Tools/pythonw.c b/Mac/Tools/pythonw.c index c8bd3ba8d68c15..78813e818e7dac 100644 --- a/Mac/Tools/pythonw.c +++ b/Mac/Tools/pythonw.c @@ -95,9 +95,6 @@ setup_spawnattr(posix_spawnattr_t* spawnattr) size_t count; cpu_type_t cpu_types[1]; short flags = 0; -#ifdef __LP64__ - int ch; -#endif if ((errno = posix_spawnattr_init(spawnattr)) != 0) { err(2, "posix_spawnattr_int"); @@ -119,10 +116,16 @@ setup_spawnattr(posix_spawnattr_t* spawnattr) #elif defined(__ppc__) cpu_types[0] = CPU_TYPE_POWERPC; + #elif defined(__i386__) cpu_types[0] = CPU_TYPE_X86; + +#elif defined(__arm64__) + cpu_types[0] = CPU_TYPE_ARM64; + #else # error "Unknown CPU" + #endif if (posix_spawnattr_setbinpref_np(spawnattr, count, @@ -220,7 +223,8 @@ main(int argc, char **argv) { /* We're weak-linking to posix-spawnv to ensure that * an executable build on 10.5 can work on 10.4. */ - if (posix_spawn != NULL) { + + if (&posix_spawn != NULL) { posix_spawnattr_t spawnattr = NULL; setup_spawnattr(&spawnattr); diff --git a/Misc/NEWS.d/next/macOS/2020-11-01-16-40-23.bpo-41100.BApztP.rst b/Misc/NEWS.d/next/macOS/2020-11-01-16-40-23.bpo-41100.BApztP.rst new file mode 100644 index 00000000000000..6cbb279e7625ea --- /dev/null +++ b/Misc/NEWS.d/next/macOS/2020-11-01-16-40-23.bpo-41100.BApztP.rst @@ -0,0 +1,8 @@ +Add support for macOS 11 and Apple Silicon systems. + +It is now possible to build "Universal 2" binaries using +"--enable-universalsdk --with-universal-archs=universal2". + +Binaries build on later macOS versions can be deployed back to older +versions (tested up to macOS 10.9), when using the correct deployment +target. This is tested using Xcode 11 and later. diff --git a/Modules/_ctypes/callbacks.c b/Modules/_ctypes/callbacks.c index 2abfa67cdc06bf..39cace58294d58 100644 --- a/Modules/_ctypes/callbacks.c +++ b/Modules/_ctypes/callbacks.c @@ -1,6 +1,8 @@ #include "Python.h" #include "frameobject.h" +#include + #include #ifdef MS_WIN32 #include @@ -18,7 +20,7 @@ CThunkObject_dealloc(PyObject *myself) Py_XDECREF(self->callable); Py_XDECREF(self->restype); if (self->pcl_write) - ffi_closure_free(self->pcl_write); + Py_ffi_closure_free(self->pcl_write); PyObject_GC_Del(self); } @@ -361,8 +363,7 @@ CThunkObject *_ctypes_alloc_callback(PyObject *callable, assert(CThunk_CheckExact((PyObject *)p)); - p->pcl_write = ffi_closure_alloc(sizeof(ffi_closure), - &p->pcl_exec); + p->pcl_write = Py_ffi_closure_alloc(sizeof(ffi_closure), &p->pcl_exec); if (p->pcl_write == NULL) { PyErr_NoMemory(); goto error; @@ -408,13 +409,35 @@ CThunkObject *_ctypes_alloc_callback(PyObject *callable, "ffi_prep_cif failed with %d", result); goto error; } -#if defined(X86_DARWIN) || defined(POWERPC_DARWIN) - result = ffi_prep_closure(p->pcl_write, &p->cif, closure_fcn, p); +#if HAVE_FFI_PREP_CLOSURE_LOC +# if USING_APPLE_OS_LIBFFI +# define HAVE_FFI_PREP_CLOSURE_LOC_RUNTIME __builtin_available(macos 10.15, ios 13, watchos 6, tvos 13, *) +# else +# define HAVE_FFI_PREP_CLOSURE_LOC_RUNTIME 1 +# endif + if (HAVE_FFI_PREP_CLOSURE_LOC_RUNTIME) { + result = ffi_prep_closure_loc(p->pcl_write, &p->cif, closure_fcn, + p, + p->pcl_exec); + } else +#endif + { +#if USING_APPLE_OS_LIBFFI && defined(__arm64__) + PyErr_Format(PyExc_NotImplementedError, "ffi_prep_closure_loc() is missing"); + goto error; #else - result = ffi_prep_closure_loc(p->pcl_write, &p->cif, closure_fcn, - p, - p->pcl_exec); +#ifdef MACOSX + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wdeprecated-declarations" #endif + result = ffi_prep_closure(p->pcl_write, &p->cif, closure_fcn, p); + +#ifdef MACOSX + #pragma clang diagnostic pop +#endif + +#endif + } if (result != FFI_OK) { PyErr_Format(PyExc_RuntimeError, "ffi_prep_closure failed with %d", result); diff --git a/Modules/_ctypes/callproc.c b/Modules/_ctypes/callproc.c index 6030cc3d43670d..b0a36a30248f74 100644 --- a/Modules/_ctypes/callproc.c +++ b/Modules/_ctypes/callproc.c @@ -57,6 +57,8 @@ #include "Python.h" #include "structmember.h" // PyMemberDef +#include + #ifdef MS_WIN32 #include #include @@ -64,6 +66,10 @@ #include "ctypes_dlfcn.h" #endif +#ifdef __APPLE__ +#include +#endif + #ifdef MS_WIN32 #include #endif @@ -812,7 +818,8 @@ static int _call_function_pointer(int flags, ffi_type **atypes, ffi_type *restype, void *resmem, - int argcount) + int argcount, + int argtypecount) { PyThreadState *_save = NULL; /* For Py_BLOCK_THREADS and Py_UNBLOCK_THREADS */ PyObject *error_object = NULL; @@ -835,14 +842,70 @@ static int _call_function_pointer(int flags, if ((flags & FUNCFLAG_CDECL) == 0) cc = FFI_STDCALL; #endif - if (FFI_OK != ffi_prep_cif(&cif, - cc, - argcount, - restype, - atypes)) { - PyErr_SetString(PyExc_RuntimeError, - "ffi_prep_cif failed"); - return -1; + +# if USING_APPLE_OS_LIBFFI +# define HAVE_FFI_PREP_CIF_VAR_RUNTIME __builtin_available(macos 10.15, ios 13, watchos 6, tvos 13, *) +# elif HAVE_FFI_PREP_CIF_VAR +# define HAVE_FFI_PREP_CIF_VAR_RUNTIME true +# else +# define HAVE_FFI_PREP_CIF_VAR_RUNTIME false +# endif + + /* Even on Apple-arm64 the calling convention for variadic functions conincides + * with the standard calling convention in the case that the function called + * only with its fixed arguments. Thus, we do not need a special flag to be + * set on variadic functions. We treat a function as variadic if it is called + * with a nonzero number of variadic arguments */ + bool is_variadic = (argtypecount != 0 && argcount > argtypecount); + (void) is_variadic; + +#if defined(__APPLE__) && defined(__arm64__) + if (is_variadic) { + if (HAVE_FFI_PREP_CIF_VAR_RUNTIME) { + } else { + PyErr_SetString(PyExc_NotImplementedError, "ffi_prep_cif_var() is missing"); + return -1; + } + } +#endif + +#if HAVE_FFI_PREP_CIF_VAR + if (is_variadic) { + if (HAVE_FFI_PREP_CIF_VAR_RUNTIME) { + if (FFI_OK != ffi_prep_cif_var(&cif, + cc, + argtypecount, + argcount, + restype, + atypes)) { + PyErr_SetString(PyExc_RuntimeError, + "ffi_prep_cif_var failed"); + return -1; + } + } else { + if (FFI_OK != ffi_prep_cif(&cif, + cc, + argcount, + restype, + atypes)) { + PyErr_SetString(PyExc_RuntimeError, + "ffi_prep_cif failed"); + return -1; + } + } + } else +#endif + + { + if (FFI_OK != ffi_prep_cif(&cif, + cc, + argcount, + restype, + atypes)) { + PyErr_SetString(PyExc_RuntimeError, + "ffi_prep_cif failed"); + return -1; + } } if (flags & (FUNCFLAG_USE_ERRNO | FUNCFLAG_USE_LASTERROR)) { @@ -1212,9 +1275,8 @@ PyObject *_ctypes_callproc(PPROC pProc, if (-1 == _call_function_pointer(flags, pProc, avalues, atypes, rtype, resbuf, - Py_SAFE_DOWNCAST(argcount, - Py_ssize_t, - int))) + Py_SAFE_DOWNCAST(argcount, Py_ssize_t, int), + Py_SAFE_DOWNCAST(argtype_count, Py_ssize_t, int))) goto cleanup; #ifdef WORDS_BIGENDIAN @@ -1398,6 +1460,42 @@ copy_com_pointer(PyObject *self, PyObject *args) } #else +#ifdef HAVE_DYLD_SHARED_CACHE_CONTAINS_PATH +static PyObject *py_dyld_shared_cache_contains_path(PyObject *self, PyObject *args) +{ + PyObject *name, *name2; + char *name_str; + + if (__builtin_available(macOS 11.0, iOS 14.0, tvOS 14.0, watchOS 7.0, *)) { + int r; + + if (!PyArg_ParseTuple(args, "O", &name)) + return NULL; + + if (name == Py_None) + Py_RETURN_FALSE; + + if (PyUnicode_FSConverter(name, &name2) == 0) + return NULL; + name_str = PyBytes_AS_STRING(name2); + + r = _dyld_shared_cache_contains_path(name_str); + Py_DECREF(name2); + + if (r) { + Py_RETURN_TRUE; + } else { + Py_RETURN_FALSE; + } + + } else { + PyErr_SetString(PyExc_NotImplementedError, "_dyld_shared_cache_contains_path symbol is missing"); + return NULL; + } + + } +#endif + static PyObject *py_dl_open(PyObject *self, PyObject *args) { PyObject *name, *name2; @@ -1887,6 +1985,8 @@ buffer_info(PyObject *self, PyObject *arg) return Py_BuildValue("siN", dict->format, dict->ndim, shape); } + + PyMethodDef _ctypes_module_methods[] = { {"get_errno", get_errno, METH_NOARGS}, {"set_errno", set_errno, METH_VARARGS}, @@ -1908,6 +2008,9 @@ PyMethodDef _ctypes_module_methods[] = { "dlopen(name, flag={RTLD_GLOBAL|RTLD_LOCAL}) open a shared library"}, {"dlclose", py_dl_close, METH_VARARGS, "dlclose a library"}, {"dlsym", py_dl_sym, METH_VARARGS, "find symbol in shared library"}, +#endif +#ifdef HAVE_DYLD_SHARED_CACHE_CONTAINS_PATH + {"_dyld_shared_cache_contains_path", py_dyld_shared_cache_contains_path, METH_VARARGS, "check if path is in the shared cache"}, #endif {"alignment", align_func, METH_O, alignment_doc}, {"sizeof", sizeof_func, METH_O, sizeof_doc}, diff --git a/Modules/_ctypes/ctypes.h b/Modules/_ctypes/ctypes.h index 1effccf9cc5ff9..3f20031d671a8a 100644 --- a/Modules/_ctypes/ctypes.h +++ b/Modules/_ctypes/ctypes.h @@ -366,6 +366,14 @@ PyObject *_ctypes_get_errobj(int **pspace); extern PyObject *ComError; #endif +#if USING_MALLOC_CLOSURE_DOT_C +void Py_ffi_closure_free(void *p); +void *Py_ffi_closure_alloc(size_t size, void** codeloc); +#else +#define Py_ffi_closure_free ffi_closure_free +#define Py_ffi_closure_alloc ffi_closure_alloc +#endif + /* Local Variables: compile-command: "python setup.py -q build install --home ~" diff --git a/Modules/_ctypes/malloc_closure.c b/Modules/_ctypes/malloc_closure.c index f9cdb336958c6f..4f220e42ff3fcc 100644 --- a/Modules/_ctypes/malloc_closure.c +++ b/Modules/_ctypes/malloc_closure.c @@ -89,16 +89,27 @@ static void more_core(void) /******************************************************************/ /* put the item back into the free list */ -void ffi_closure_free(void *p) +void Py_ffi_closure_free(void *p) { +#if USING_APPLE_OS_LIBFFI && HAVE_FFI_CLOSURE_ALLOC + if (__builtin_available(macos 10.15, ios 13, watchos 6, tvos 13, *)) { + ffi_closure_free(p); + return; + } +#endif ITEM *item = (ITEM *)p; item->next = free_list; free_list = item; } /* return one item from the free list, allocating more if needed */ -void *ffi_closure_alloc(size_t ignored, void** codeloc) +void *Py_ffi_closure_alloc(size_t size, void** codeloc) { +#if USING_APPLE_OS_LIBFFI && HAVE_FFI_CLOSURE_ALLOC + if (__builtin_available(macos 10.15, ios 13, watchos 6, tvos 13, *)) { + return ffi_closure_alloc(size, codeloc); + } +#endif ITEM *item; if (!free_list) more_core(); diff --git a/Modules/_decimal/libmpdec/mpdecimal.h b/Modules/_decimal/libmpdec/mpdecimal.h index 2815a8cde31db8..5a2439690c3509 100644 --- a/Modules/_decimal/libmpdec/mpdecimal.h +++ b/Modules/_decimal/libmpdec/mpdecimal.h @@ -121,6 +121,9 @@ const char *mpd_version(void); #elif defined(__x86_64__) #define CONFIG_64 #define ASM + #elif defined(__arm64__) + #define CONFIG_64 + #define ANSI #else #error "unknown architecture for universal build." #endif diff --git a/Modules/getpath.c b/Modules/getpath.c index a84c8586367335..40358190a71b87 100644 --- a/Modules/getpath.c +++ b/Modules/getpath.c @@ -923,11 +923,7 @@ static PyStatus calculate_program_macos(wchar_t **abs_path_p) { char execpath[MAXPATHLEN + 1]; -#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4 uint32_t nsexeclength = Py_ARRAY_LENGTH(execpath) - 1; -#else - unsigned long nsexeclength = Py_ARRAY_LENGTH(execpath) - 1; -#endif /* On Mac OS X, if a script uses an interpreter of the form "#!/opt/python2.3/bin/python", the kernel only passes "python" diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index 8e14ffcc856f85..12f72f525f7ae4 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -7,18 +7,6 @@ of the compiler used. Different compilers define their own feature test macro, e.g. '_MSC_VER'. */ -#ifdef __APPLE__ - /* - * Step 1 of support for weak-linking a number of symbols existing on - * OSX 10.4 and later, see the comment in the #ifdef __APPLE__ block - * at the end of this file for more information. - */ -# pragma weak lchown -# pragma weak statvfs -# pragma weak fstatvfs - -#endif /* __APPLE__ */ - #define PY_SSIZE_T_CLEAN #include "Python.h" @@ -50,6 +38,127 @@ #include /* needed for ctermid() */ +/* + * A number of APIs are available on macOS from a certain macOS version. + * To support building with a new SDK while deploying to older versions + * the availability test is split into two: + * - HAVE_: The configure check for compile time availability + * - HAVE__RUNTIME: Runtime check for availability + * + * The latter is always true when not on macOS, or when using a compiler + * that does not support __has_builtin (older versions of Xcode). + * + * Due to compiler restrictions there is one valid use of HAVE__RUNTIME: + * if (HAVE__RUNTIME) { ... } + * + * In mixing the test with other tests or using negations will result in compile + * errors. + */ +#if defined(__APPLE__) + +#if defined(__has_builtin) && __has_builtin(__builtin_available) +# define HAVE_FSTATAT_RUNTIME __builtin_available(macOS 10.10, iOS 8.0, *) +# define HAVE_FACCESSAT_RUNTIME __builtin_available(macOS 10.10, iOS 8.0, *) +# define HAVE_FCHMODAT_RUNTIME __builtin_available(macOS 10.10, iOS 8.0, *) +# define HAVE_FCHOWNAT_RUNTIME __builtin_available(macOS 10.10, iOS 8.0, *) +# define HAVE_LINKAT_RUNTIME __builtin_available(macOS 10.10, iOS 8.0, *) +# define HAVE_FDOPENDIR_RUNTIME __builtin_available(macOS 10.10, iOS 8.0, *) +# define HAVE_MKDIRAT_RUNTIME __builtin_available(macOS 10.10, iOS 8.0, *) +# define HAVE_RENAMEAT_RUNTIME __builtin_available(macOS 10.10, iOS 8.0, *) +# define HAVE_UNLINKAT_RUNTIME __builtin_available(macOS 10.10, iOS 8.0, *) +# define HAVE_OPENAT_RUNTIME __builtin_available(macOS 10.10, iOS 8.0, *) +# define HAVE_READLINKAT_RUNTIME __builtin_available(macOS 10.10, iOS 8.0, *) +# define HAVE_SYMLINKAT_RUNTIME __builtin_available(macOS 10.10, iOS 8.0, *) +# define HAVE_FUTIMENS_RUNTIME __builtin_available(macOS 10.13, iOS 11.0, tvOS 11.0, watchOS 4.0, *) +# define HAVE_UTIMENSAT_RUNTIME __builtin_available(macOS 10.13, iOS 11.0, tvOS 11.0, watchOS 4.0, *) +# define HAVE_PWRITEV_RUNTIME __builtin_available(macOS 11.0, iOS 14.0, tvOS 14.0, watchOS 7.0, *) + +# define HAVE_POSIX_SPAWN_SETSID_RUNTIME __builtin_available(macOS 10.15, *) + +#else /* Xcode 8 or earlier */ + + /* __builtin_available is not present in these compilers, but + * some of the symbols might be weak linked (10.10 SDK or later + * deploying on 10.9. + * + * Fall back to the older style of availability checking for + * symbols introduced in macOS 10.10. + */ + +# ifdef HAVE_FSTATAT +# define HAVE_FSTATAT_RUNTIME (fstatat != NULL) +# endif + +# ifdef HAVE_FACCESSAT +# define HAVE_FACCESSAT_RUNTIME (faccessat != NULL) +# endif + +# ifdef HAVE_FCHMODAT +# define HAVE_FCHMODAT_RUNTIME (fchmodat != NULL) +# endif + +# ifdef HAVE_FCHOWNAT +# define HAVE_FCHOWNAT_RUNTIME (fchownat != NULL) +# endif + +# ifdef HAVE_LINKAT +# define HAVE_LINKAT_RUNTIME (linkat != NULL) +# endif + +# ifdef HAVE_FDOPENDIR +# define HAVE_FDOPENDIR_RUNTIME (fdopendir != NULL) +# endif + +# ifdef HAVE_MKDIRAT +# define HAVE_MKDIRAT_RUNTIME (mkdirat != NULL) +# endif + +# ifdef HAVE_RENAMEAT +# define HAVE_RENAMEAT_RUNTIME (renameat != NULL) +# endif + +# ifdef HAVE_UNLINKAT +# define HAVE_UNLINKAT_RUNTIME (unlinkat != NULL) +# endif + +# ifdef HAVE_OPENAT +# define HAVE_OPENAT_RUNTIME (openat != NULL) +# endif + +# ifdef HAVE_READLINKAT +# define HAVE_READLINKAT_RUNTIME (readlinkat != NULL) +# endif + +# ifdef HAVE_SYMLINKAT +# define HAVE_SYMLINKAT_RUNTIME (symlinkat != NULL) +# endif + +#endif + +#ifdef HAVE_FUTIMESAT +/* Some of the logic for weak linking depends on this assertion */ +# error "HAVE_FUTIMESAT unexpectedly defined" +#endif + +#else +# define HAVE_FSTATAT_RUNTIME 1 +# define HAVE_FACCESSAT_RUNTIME 1 +# define HAVE_FCHMODAT_RUNTIME 1 +# define HAVE_FCHOWNAT_RUNTIME 1 +# define HAVE_LINKAT_RUNTIME 1 +# define HAVE_FDOPENDIR_RUNTIME 1 +# define HAVE_MKDIRAT_RUNTIME 1 +# define HAVE_RENAMEAT_RUNTIME 1 +# define HAVE_UNLINKAT_RUNTIME 1 +# define HAVE_OPENAT_RUNTIME 1 +# define HAVE_READLINKAT_RUNTIME 1 +# define HAVE_SYMLINKAT_RUNTIME 1 +# define HAVE_FUTIMENS_RUNTIME 1 +# define HAVE_UTIMENSAT_RUNTIME 1 +# define HAVE_PWRITEV_RUNTIME 1 +#endif + + #ifdef __cplusplus extern "C" { #endif @@ -2308,6 +2417,10 @@ posix_do_stat(PyObject *module, const char *function_name, path_t *path, STRUCT_STAT st; int result; +#ifdef HAVE_FSTATAT + int fstatat_unavailable = 0; +#endif + #if !defined(MS_WINDOWS) && !defined(HAVE_FSTATAT) && !defined(HAVE_LSTAT) if (follow_symlinks_specified(function_name, follow_symlinks)) return NULL; @@ -2334,15 +2447,27 @@ posix_do_stat(PyObject *module, const char *function_name, path_t *path, else #endif /* HAVE_LSTAT */ #ifdef HAVE_FSTATAT - if ((dir_fd != DEFAULT_DIR_FD) || !follow_symlinks) - result = fstatat(dir_fd, path->narrow, &st, + if ((dir_fd != DEFAULT_DIR_FD) || !follow_symlinks) { + if (HAVE_FSTATAT_RUNTIME) { + result = fstatat(dir_fd, path->narrow, &st, follow_symlinks ? 0 : AT_SYMLINK_NOFOLLOW); - else + + } else { + fstatat_unavailable = 1; + } + } else #endif /* HAVE_FSTATAT */ result = STAT(path->narrow, &st); #endif /* MS_WINDOWS */ Py_END_ALLOW_THREADS +#ifdef HAVE_FSTATAT + if (fstatat_unavailable) { + argument_unavailable_error("stat", "dir_fd"); + return NULL; + } +#endif + if (result != 0) { return path_error(path); } @@ -2760,6 +2885,10 @@ os_access_impl(PyObject *module, path_t *path, int mode, int dir_fd, int result; #endif +#ifdef HAVE_FACCESSAT + int faccessat_unavailable = 0; +#endif + #ifndef HAVE_FACCESSAT if (follow_symlinks_specified("access", follow_symlinks)) return -1; @@ -2794,17 +2923,40 @@ os_access_impl(PyObject *module, path_t *path, int mode, int dir_fd, if ((dir_fd != DEFAULT_DIR_FD) || effective_ids || !follow_symlinks) { - int flags = 0; - if (!follow_symlinks) - flags |= AT_SYMLINK_NOFOLLOW; - if (effective_ids) - flags |= AT_EACCESS; - result = faccessat(dir_fd, path->narrow, mode, flags); + + if (HAVE_FACCESSAT_RUNTIME) { + int flags = 0; + if (!follow_symlinks) + flags |= AT_SYMLINK_NOFOLLOW; + if (effective_ids) + flags |= AT_EACCESS; + result = faccessat(dir_fd, path->narrow, mode, flags); + } else { + faccessat_unavailable = 1; + } } else #endif result = access(path->narrow, mode); Py_END_ALLOW_THREADS + +#ifdef HAVE_FACCESSAT + if (faccessat_unavailable) { + if (dir_fd != DEFAULT_DIR_FD) { + argument_unavailable_error("access", "dir_fd"); + return -1; + } + if (follow_symlinks_specified("access", follow_symlinks)) + return -1; + + if (effective_ids) { + argument_unavailable_error("access", "effective_ids"); + return -1; + } + /* should be unreachable */ + return -1; + } +#endif return_value = !result; #endif @@ -3002,6 +3154,7 @@ os_chmod_impl(PyObject *module, path_t *path, int mode, int dir_fd, #ifdef HAVE_FCHMODAT int fchmodat_nofollow_unsupported = 0; + int fchmodat_unsupported = 0; #endif #if !(defined(HAVE_FCHMODAT) || defined(HAVE_LCHMOD)) @@ -3037,42 +3190,56 @@ os_chmod_impl(PyObject *module, path_t *path, int mode, int dir_fd, if (path->fd != -1) result = fchmod(path->fd, mode); else -#endif +#endif /* HAVE_CHMOD */ #ifdef HAVE_LCHMOD if ((!follow_symlinks) && (dir_fd == DEFAULT_DIR_FD)) result = lchmod(path->narrow, mode); else -#endif +#endif /* HAVE_LCHMOD */ #ifdef HAVE_FCHMODAT if ((dir_fd != DEFAULT_DIR_FD) || !follow_symlinks) { - /* - * fchmodat() doesn't currently support AT_SYMLINK_NOFOLLOW! - * The documentation specifically shows how to use it, - * and then says it isn't implemented yet. - * (true on linux with glibc 2.15, and openindiana 3.x) - * - * Once it is supported, os.chmod will automatically - * support dir_fd and follow_symlinks=False. (Hopefully.) - * Until then, we need to be careful what exception we raise. - */ - result = fchmodat(dir_fd, path->narrow, mode, - follow_symlinks ? 0 : AT_SYMLINK_NOFOLLOW); - /* - * But wait! We can't throw the exception without allowing threads, - * and we can't do that in this nested scope. (Macro trickery, sigh.) - */ - fchmodat_nofollow_unsupported = - result && - ((errno == ENOTSUP) || (errno == EOPNOTSUPP)) && - !follow_symlinks; + if (HAVE_FCHMODAT_RUNTIME) { + /* + * fchmodat() doesn't currently support AT_SYMLINK_NOFOLLOW! + * The documentation specifically shows how to use it, + * and then says it isn't implemented yet. + * (true on linux with glibc 2.15, and openindiana 3.x) + * + * Once it is supported, os.chmod will automatically + * support dir_fd and follow_symlinks=False. (Hopefully.) + * Until then, we need to be careful what exception we raise. + */ + result = fchmodat(dir_fd, path->narrow, mode, + follow_symlinks ? 0 : AT_SYMLINK_NOFOLLOW); + /* + * But wait! We can't throw the exception without allowing threads, + * and we can't do that in this nested scope. (Macro trickery, sigh.) + */ + fchmodat_nofollow_unsupported = + result && + ((errno == ENOTSUP) || (errno == EOPNOTSUPP)) && + !follow_symlinks; + } else { + fchmodat_unsupported = 1; + fchmodat_nofollow_unsupported = 1; + + result = -1; + } } else -#endif +#endif /* HAVE_FHCMODAT */ result = chmod(path->narrow, mode); Py_END_ALLOW_THREADS if (result) { #ifdef HAVE_FCHMODAT + if (fchmodat_unsupported) { + if (dir_fd != DEFAULT_DIR_FD) { + argument_unavailable_error("chmod", "dir_fd"); + return NULL; + } + } + if (fchmodat_nofollow_unsupported) { if (dir_fd != DEFAULT_DIR_FD) dir_fd_and_follow_symlinks_invalid("chmod", @@ -3082,10 +3249,10 @@ os_chmod_impl(PyObject *module, path_t *path, int mode, int dir_fd, return NULL; } else -#endif +#endif /* HAVE_FCHMODAT */ return path_error(path); } -#endif +#endif /* MS_WINDOWS */ Py_RETURN_NONE; } @@ -3373,6 +3540,10 @@ os_chown_impl(PyObject *module, path_t *path, uid_t uid, gid_t gid, { int result; +#if defined(HAVE_FCHOWNAT) + int fchownat_unsupported = 0; +#endif + #if !(defined(HAVE_LCHOWN) || defined(HAVE_FCHOWNAT)) if (follow_symlinks_specified("chown", follow_symlinks)) return NULL; @@ -3381,19 +3552,6 @@ os_chown_impl(PyObject *module, path_t *path, uid_t uid, gid_t gid, fd_and_follow_symlinks_invalid("chown", path->fd, follow_symlinks)) return NULL; -#ifdef __APPLE__ - /* - * This is for Mac OS X 10.3, which doesn't have lchown. - * (But we still have an lchown symbol because of weak-linking.) - * It doesn't have fchownat either. So there's no possibility - * of a graceful failover. - */ - if ((!follow_symlinks) && (lchown == NULL)) { - follow_symlinks_specified("chown", follow_symlinks); - return NULL; - } -#endif - if (PySys_Audit("os.chown", "OIIi", path->object, uid, gid, dir_fd == DEFAULT_DIR_FD ? -1 : dir_fd) < 0) { return NULL; @@ -3411,14 +3569,28 @@ os_chown_impl(PyObject *module, path_t *path, uid_t uid, gid_t gid, else #endif #ifdef HAVE_FCHOWNAT - if ((dir_fd != DEFAULT_DIR_FD) || (!follow_symlinks)) + if ((dir_fd != DEFAULT_DIR_FD) || (!follow_symlinks)) { + if (HAVE_FCHOWNAT_RUNTIME) { result = fchownat(dir_fd, path->narrow, uid, gid, follow_symlinks ? 0 : AT_SYMLINK_NOFOLLOW); - else + } else { + fchownat_unsupported = 1; + } + } else #endif result = chown(path->narrow, uid, gid); Py_END_ALLOW_THREADS +#ifdef HAVE_FCHOWNAT + if (fchownat_unsupported) { + /* This would be incorrect if the current platform + * doesn't support lchown. + */ + argument_unavailable_error(NULL, "dir_fd"); + return NULL; + } +#endif + if (result) return path_error(path); @@ -3664,6 +3836,9 @@ os_link_impl(PyObject *module, path_t *src, path_t *dst, int src_dir_fd, #else int result; #endif +#if defined(HAVE_LINKAT) + int linkat_unavailable = 0; +#endif #ifndef HAVE_LINKAT if ((src_dir_fd != DEFAULT_DIR_FD) || (dst_dir_fd != DEFAULT_DIR_FD)) { @@ -3698,15 +3873,43 @@ os_link_impl(PyObject *module, path_t *src, path_t *dst, int src_dir_fd, #ifdef HAVE_LINKAT if ((src_dir_fd != DEFAULT_DIR_FD) || (dst_dir_fd != DEFAULT_DIR_FD) || - (!follow_symlinks)) - result = linkat(src_dir_fd, src->narrow, - dst_dir_fd, dst->narrow, - follow_symlinks ? AT_SYMLINK_FOLLOW : 0); + (!follow_symlinks)) { + + if (HAVE_LINKAT_RUNTIME) { + + result = linkat(src_dir_fd, src->narrow, + dst_dir_fd, dst->narrow, + follow_symlinks ? AT_SYMLINK_FOLLOW : 0); + + } +#ifdef __APPLE__ + else { + if (src_dir_fd == DEFAULT_DIR_FD && dst_dir_fd == DEFAULT_DIR_FD) { + /* See issue 41355: This matches the behaviour of !HAVE_LINKAT */ + result = link(src->narrow, dst->narrow); + } else { + linkat_unavailable = 1; + } + } +#endif + } else #endif /* HAVE_LINKAT */ result = link(src->narrow, dst->narrow); Py_END_ALLOW_THREADS +#ifdef HAVE_LINKAT + if (linkat_unavailable) { + /* Either or both dir_fd arguments were specified */ + if (src_dir_fd != DEFAULT_DIR_FD) { + argument_unavailable_error("link", "src_dir_fd"); + } else { + argument_unavailable_error("link", "dst_dir_fd"); + } + return NULL; + } +#endif + if (result) return path_error2(src, dst); #endif /* MS_WINDOWS */ @@ -3829,6 +4032,7 @@ _posix_listdir(path_t *path, PyObject *list) errno = 0; #ifdef HAVE_FDOPENDIR if (path->fd != -1) { + if (HAVE_FDOPENDIR_RUNTIME) { /* closedir() closes the FD, so we duplicate it */ fd = _Py_dup(path->fd); if (fd == -1) @@ -3839,6 +4043,11 @@ _posix_listdir(path_t *path, PyObject *list) Py_BEGIN_ALLOW_THREADS dirp = fdopendir(fd); Py_END_ALLOW_THREADS + } else { + PyErr_SetString(PyExc_TypeError, + "listdir: path should be string, bytes, os.PathLike or None, not int"); + return NULL; + } } else #endif @@ -4152,6 +4361,9 @@ os_mkdir_impl(PyObject *module, path_t *path, int mode, int dir_fd) /*[clinic end generated code: output=a70446903abe821f input=e965f68377e9b1ce]*/ { int result; +#ifdef HAVE_MKDIRAT + int mkdirat_unavailable = 0; +#endif if (PySys_Audit("os.mkdir", "Oii", path->object, mode, dir_fd == DEFAULT_DIR_FD ? -1 : dir_fd) < 0) { @@ -4168,9 +4380,14 @@ os_mkdir_impl(PyObject *module, path_t *path, int mode, int dir_fd) #else Py_BEGIN_ALLOW_THREADS #if HAVE_MKDIRAT - if (dir_fd != DEFAULT_DIR_FD) + if (dir_fd != DEFAULT_DIR_FD) { + if (HAVE_MKDIRAT_RUNTIME) { result = mkdirat(dir_fd, path->narrow, mode); - else + + } else { + mkdirat_unavailable = 1; + } + } else #endif #if defined(__WATCOMC__) && !defined(__QNX__) result = mkdir(path->narrow); @@ -4178,6 +4395,14 @@ os_mkdir_impl(PyObject *module, path_t *path, int mode, int dir_fd) result = mkdir(path->narrow, mode); #endif Py_END_ALLOW_THREADS + +#if HAVE_MKDIRAT + if (mkdirat_unavailable) { + argument_unavailable_error(NULL, "dir_fd"); + return NULL; + } +#endif + if (result < 0) return path_error(path); #endif /* MS_WINDOWS */ @@ -4287,6 +4512,10 @@ internal_rename(path_t *src, path_t *dst, int src_dir_fd, int dst_dir_fd, int is const char *function_name = is_replace ? "replace" : "rename"; int dir_fd_specified; +#ifdef HAVE_RENAMEAT + int renameat_unavailable = 0; +#endif + #ifdef MS_WINDOWS BOOL result; int flags = is_replace ? MOVEFILE_REPLACE_EXISTING : 0; @@ -4326,13 +4555,25 @@ internal_rename(path_t *src, path_t *dst, int src_dir_fd, int dst_dir_fd, int is Py_BEGIN_ALLOW_THREADS #ifdef HAVE_RENAMEAT - if (dir_fd_specified) - result = renameat(src_dir_fd, src->narrow, dst_dir_fd, dst->narrow); - else + if (dir_fd_specified) { + if (HAVE_RENAMEAT_RUNTIME) { + result = renameat(src_dir_fd, src->narrow, dst_dir_fd, dst->narrow); + } else { + renameat_unavailable = 1; + } + } else #endif result = rename(src->narrow, dst->narrow); Py_END_ALLOW_THREADS + +#ifdef HAVE_RENAMEAT + if (renameat_unavailable) { + argument_unavailable_error(function_name, "src_dir_fd and dst_dir_fd"); + return NULL; + } +#endif + if (result) return path_error2(src, dst); #endif @@ -4408,6 +4649,9 @@ os_rmdir_impl(PyObject *module, path_t *path, int dir_fd) /*[clinic end generated code: output=080eb54f506e8301 input=38c8b375ca34a7e2]*/ { int result; +#ifdef HAVE_UNLINKAT + int unlinkat_unavailable = 0; +#endif if (PySys_Audit("os.rmdir", "Oi", path->object, dir_fd == DEFAULT_DIR_FD ? -1 : dir_fd) < 0) { @@ -4420,14 +4664,26 @@ os_rmdir_impl(PyObject *module, path_t *path, int dir_fd) result = !RemoveDirectoryW(path->wide); #else #ifdef HAVE_UNLINKAT - if (dir_fd != DEFAULT_DIR_FD) + if (dir_fd != DEFAULT_DIR_FD) { + if (HAVE_UNLINKAT_RUNTIME) { result = unlinkat(dir_fd, path->narrow, AT_REMOVEDIR); - else + } else { + unlinkat_unavailable = 1; + result = -1; + } + } else #endif result = rmdir(path->narrow); #endif Py_END_ALLOW_THREADS +#ifdef HAVE_UNLINKAT + if (unlinkat_unavailable) { + argument_unavailable_error("rmdir", "dir_fd"); + return NULL; + } +#endif + if (result) return path_error(path); @@ -4571,6 +4827,9 @@ os_unlink_impl(PyObject *module, path_t *path, int dir_fd) /*[clinic end generated code: output=621797807b9963b1 input=d7bcde2b1b2a2552]*/ { int result; +#ifdef HAVE_UNLINKAT + int unlinkat_unavailable = 0; +#endif if (PySys_Audit("os.remove", "Oi", path->object, dir_fd == DEFAULT_DIR_FD ? -1 : dir_fd) < 0) { @@ -4584,15 +4843,27 @@ os_unlink_impl(PyObject *module, path_t *path, int dir_fd) result = !Py_DeleteFileW(path->wide); #else #ifdef HAVE_UNLINKAT - if (dir_fd != DEFAULT_DIR_FD) + if (dir_fd != DEFAULT_DIR_FD) { + if (HAVE_UNLINKAT_RUNTIME) { + result = unlinkat(dir_fd, path->narrow, 0); - else + } else { + unlinkat_unavailable = 1; + } + } else #endif /* HAVE_UNLINKAT */ result = unlink(path->narrow); #endif _Py_END_SUPPRESS_IPH Py_END_ALLOW_THREADS +#ifdef HAVE_UNLINKAT + if (unlinkat_unavailable) { + argument_unavailable_error(NULL, "dir_fd"); + return NULL; + } +#endif + if (result) return path_error(path); @@ -4763,7 +5034,16 @@ typedef struct { static int utime_dir_fd(utime_t *ut, int dir_fd, const char *path, int follow_symlinks) { -#ifdef HAVE_UTIMENSAT +#if defined(__APPLE__) && defined(HAVE_UTIMENSAT) + if (HAVE_UTIMENSAT_RUNTIME) { + int flags = follow_symlinks ? 0 : AT_SYMLINK_NOFOLLOW; + UTIME_TO_TIMESPEC; + return utimensat(dir_fd, path, time, flags); + } else { + errno = ENOSYS; + return -1; + } +#elif defined(HAVE_UTIMENSAT) int flags = follow_symlinks ? 0 : AT_SYMLINK_NOFOLLOW; UTIME_TO_TIMESPEC; return utimensat(dir_fd, path, time, flags); @@ -4790,11 +5070,30 @@ static int utime_fd(utime_t *ut, int fd) { #ifdef HAVE_FUTIMENS + + if (HAVE_FUTIMENS_RUNTIME) { + UTIME_TO_TIMESPEC; return futimens(fd, time); -#else + + } else +#ifndef HAVE_FUTIMES + { + /* Not sure if this can happen */ + PyErr_SetString( + PyExc_RuntimeError, + "neither futimens nor futimes are supported" + " on this system"); + return -1; + } +#endif + +#endif +#ifdef HAVE_FUTIMES + { UTIME_TO_TIMEVAL; return futimes(fd, time); + } #endif } @@ -4813,11 +5112,27 @@ static int utime_nofollow_symlinks(utime_t *ut, const char *path) { #ifdef HAVE_UTIMENSAT - UTIME_TO_TIMESPEC; - return utimensat(DEFAULT_DIR_FD, path, time, AT_SYMLINK_NOFOLLOW); -#else + if (HAVE_UTIMENSAT_RUNTIME) { + UTIME_TO_TIMESPEC; + return utimensat(DEFAULT_DIR_FD, path, time, AT_SYMLINK_NOFOLLOW); + } else +#ifndef HAVE_LUTIMES + { + /* Not sure if this can happen */ + PyErr_SetString( + PyExc_RuntimeError, + "neither utimensat nor lutimes are supported" + " on this system"); + return -1; + } +#endif +#endif + +#ifdef HAVE_LUTIMES + { UTIME_TO_TIMEVAL; return lutimes(path, time); + } #endif } @@ -4828,7 +5143,15 @@ utime_nofollow_symlinks(utime_t *ut, const char *path) static int utime_default(utime_t *ut, const char *path) { -#ifdef HAVE_UTIMENSAT +#if defined(__APPLE__) && defined(HAVE_UTIMENSAT) + if (HAVE_UTIMENSAT_RUNTIME) { + UTIME_TO_TIMESPEC; + return utimensat(DEFAULT_DIR_FD, path, time, 0); + } else { + UTIME_TO_TIMEVAL; + return utimes(path, time); + } +#elif defined(HAVE_UTIMENSAT) UTIME_TO_TIMESPEC; return utimensat(DEFAULT_DIR_FD, path, time, 0); #elif defined(HAVE_UTIMES) @@ -5037,9 +5360,10 @@ os_utime_impl(PyObject *module, path_t *path, PyObject *times, PyObject *ns, #endif #if defined(HAVE_FUTIMESAT) || defined(HAVE_UTIMENSAT) - if ((dir_fd != DEFAULT_DIR_FD) || (!follow_symlinks)) + if ((dir_fd != DEFAULT_DIR_FD) || (!follow_symlinks)) { result = utime_dir_fd(&utime, dir_fd, path->narrow, follow_symlinks); - else + + } else #endif #if defined(HAVE_FUTIMES) || defined(HAVE_FUTIMENS) @@ -5052,6 +5376,14 @@ os_utime_impl(PyObject *module, path_t *path, PyObject *times, PyObject *ns, Py_END_ALLOW_THREADS +#if defined(__APPLE__) && defined(HAVE_UTIMENSAT) + /* See utime_dir_fd implementation */ + if (result == -1 && errno == ENOSYS) { + argument_unavailable_error(NULL, "dir_fd"); + return NULL; + } +#endif + if (result < 0) { /* see previous comment about not putting filename in error here */ posix_error(); @@ -5450,6 +5782,9 @@ parse_posix_spawn_flags(PyObject *module, const char *func_name, PyObject *setpg } if (setsid) { +#ifdef HAVE_POSIX_SPAWN_SETSID_RUNTIME + if (HAVE_POSIX_SPAWN_SETSID_RUNTIME) { +#endif #ifdef POSIX_SPAWN_SETSID all_flags |= POSIX_SPAWN_SETSID; #elif defined(POSIX_SPAWN_SETSID_NP) @@ -5458,6 +5793,14 @@ parse_posix_spawn_flags(PyObject *module, const char *func_name, PyObject *setpg argument_unavailable_error(func_name, "setsid"); return -1; #endif + +#ifdef HAVE_POSIX_SPAWN_SETSID_RUNTIME + } else { + argument_unavailable_error(func_name, "setsid"); + return -1; + } +#endif /* HAVE_POSIX_SPAWN_SETSID_RUNTIME */ + } if (setsigmask) { @@ -8068,16 +8411,30 @@ os_readlink_impl(PyObject *module, path_t *path, int dir_fd) #if defined(HAVE_READLINK) char buffer[MAXPATHLEN+1]; ssize_t length; +#ifdef HAVE_READLINKAT + int readlinkat_unavailable = 0; +#endif Py_BEGIN_ALLOW_THREADS #ifdef HAVE_READLINKAT - if (dir_fd != DEFAULT_DIR_FD) - length = readlinkat(dir_fd, path->narrow, buffer, MAXPATHLEN); - else + if (dir_fd != DEFAULT_DIR_FD) { + if (HAVE_READLINKAT_RUNTIME) { + length = readlinkat(dir_fd, path->narrow, buffer, MAXPATHLEN); + } else { + readlinkat_unavailable = 1; + } + } else #endif length = readlink(path->narrow, buffer, MAXPATHLEN); Py_END_ALLOW_THREADS +#ifdef HAVE_READLINKAT + if (readlinkat_unavailable) { + argument_unavailable_error(NULL, "dir_fd"); + return NULL; + } +#endif + if (length < 0) { return path_error(path); } @@ -8273,6 +8630,9 @@ os_symlink_impl(PyObject *module, path_t *src, path_t *dst, static int windows_has_symlink_unprivileged_flag = TRUE; #else int result; +#ifdef HAVE_SYMLINKAT + int symlinkat_unavailable = 0; +#endif #endif if (PySys_Audit("os.symlink", "OOi", src->object, dst->object, @@ -8335,14 +8695,25 @@ os_symlink_impl(PyObject *module, path_t *src, path_t *dst, } Py_BEGIN_ALLOW_THREADS -#if HAVE_SYMLINKAT - if (dir_fd != DEFAULT_DIR_FD) - result = symlinkat(src->narrow, dir_fd, dst->narrow); - else +#ifdef HAVE_SYMLINKAT + if (dir_fd != DEFAULT_DIR_FD) { + if (HAVE_SYMLINKAT_RUNTIME) { + result = symlinkat(src->narrow, dir_fd, dst->narrow); + } else { + symlinkat_unavailable = 1; + } + } else #endif result = symlink(src->narrow, dst->narrow); Py_END_ALLOW_THREADS +#ifdef HAVE_SYMLINKAT + if (symlinkat_unavailable) { + argument_unavailable_error(NULL, "dir_fd"); + return NULL; + } +#endif + if (result) return path_error2(src, dst); #endif @@ -8613,6 +8984,9 @@ os_open_impl(PyObject *module, path_t *path, int flags, int mode, int dir_fd) { int fd; int async_err = 0; +#ifdef HAVE_OPENAT + int openat_unavailable = 0; +#endif #ifdef O_CLOEXEC int *atomic_flag_works = &_Py_open_cloexec_works; @@ -8637,9 +9011,15 @@ os_open_impl(PyObject *module, path_t *path, int flags, int mode, int dir_fd) fd = _wopen(path->wide, flags, mode); #else #ifdef HAVE_OPENAT - if (dir_fd != DEFAULT_DIR_FD) - fd = openat(dir_fd, path->narrow, flags, mode); - else + if (dir_fd != DEFAULT_DIR_FD) { + if (HAVE_OPENAT_RUNTIME) { + fd = openat(dir_fd, path->narrow, flags, mode); + + } else { + openat_unavailable = 1; + fd = -1; + } + } else #endif /* HAVE_OPENAT */ fd = open(path->narrow, flags, mode); #endif /* !MS_WINDOWS */ @@ -8647,6 +9027,13 @@ os_open_impl(PyObject *module, path_t *path, int flags, int mode, int dir_fd) } while (fd < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals())); _Py_END_SUPPRESS_IPH +#ifdef HAVE_OPENAT + if (openat_unavailable) { + argument_unavailable_error(NULL, "dir_fd"); + return -1; + } +#endif + if (fd < 0) { if (!async_err) PyErr_SetFromErrnoWithFilenameObject(PyExc_OSError, path->object); @@ -9229,12 +9616,25 @@ os_preadv_impl(PyObject *module, int fd, PyObject *buffers, Py_off_t offset, } while (n < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals())); #else do { +#ifdef __APPLE__ +/* This entire function will be removed from the module dict when the API + * is not available. + */ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunguarded-availability" +#pragma clang diagnostic ignored "-Wunguarded-availability-new" +#endif Py_BEGIN_ALLOW_THREADS _Py_BEGIN_SUPPRESS_IPH n = preadv(fd, iov, cnt, offset); _Py_END_SUPPRESS_IPH Py_END_ALLOW_THREADS } while (n < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals())); + +#ifdef __APPLE__ +#pragma clang diagnostic pop +#endif + #endif iov_cleanup(iov, buf, cnt); @@ -9856,6 +10256,15 @@ os_pwritev_impl(PyObject *module, int fd, PyObject *buffers, Py_off_t offset, Py_END_ALLOW_THREADS } while (result < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals())); #else + +#ifdef __APPLE__ +/* This entire function will be removed from the module dict when the API + * is not available. + */ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunguarded-availability" +#pragma clang diagnostic ignored "-Wunguarded-availability-new" +#endif do { Py_BEGIN_ALLOW_THREADS _Py_BEGIN_SUPPRESS_IPH @@ -9863,6 +10272,11 @@ os_pwritev_impl(PyObject *module, int fd, PyObject *buffers, Py_off_t offset, _Py_END_SUPPRESS_IPH Py_END_ALLOW_THREADS } while (result < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals())); + +#ifdef __APPLE__ +#pragma clang diagnostic pop +#endif + #endif iov_cleanup(iov, buf, cnt); @@ -10752,13 +11166,6 @@ os_statvfs_impl(PyObject *module, path_t *path) Py_BEGIN_ALLOW_THREADS #ifdef HAVE_FSTATVFS if (path->fd != -1) { -#ifdef __APPLE__ - /* handle weak-linking on Mac OS X 10.3 */ - if (fstatvfs == NULL) { - fd_specified("statvfs", path->fd); - return NULL; - } -#endif result = fstatvfs(path->fd, &st); } else @@ -12832,12 +13239,17 @@ DirEntry_fetch_stat(PyObject *module, DirEntry *self, int follow_symlinks) const char *path = PyBytes_AS_STRING(ub); if (self->dir_fd != DEFAULT_DIR_FD) { #ifdef HAVE_FSTATAT + if (HAVE_FSTATAT_RUNTIME) { result = fstatat(self->dir_fd, path, &st, follow_symlinks ? 0 : AT_SYMLINK_NOFOLLOW); -#else + } else + +#endif /* HAVE_FSTATAT */ + { + Py_DECREF(ub); PyErr_SetString(PyExc_NotImplementedError, "can't fetch stat"); return NULL; -#endif /* HAVE_FSTATAT */ + } } else #endif @@ -13623,7 +14035,8 @@ os_scandir_impl(PyObject *module, path_t *path) #else /* POSIX */ errno = 0; #ifdef HAVE_FDOPENDIR - if (path->fd != -1) { + if (iterator->path.fd != -1) { + if (HAVE_FDOPENDIR_RUNTIME) { /* closedir() closes the FD, so we duplicate it */ fd = _Py_dup(path->fd); if (fd == -1) @@ -13632,6 +14045,11 @@ os_scandir_impl(PyObject *module, path_t *path) Py_BEGIN_ALLOW_THREADS iterator->dirp = fdopendir(fd); Py_END_ALLOW_THREADS + } else { + PyErr_SetString(PyExc_TypeError, + "scandir: path should be string, bytes, os.PathLike or None, not int"); + return NULL; + } } else #endif @@ -14702,137 +15120,210 @@ all_ins(PyObject *m) } -static const char * const have_functions[] = { + +#define PROBE(name, test) \ + static int name(void) \ + { \ + if (test) { \ + return 1; \ + } else { \ + return 0; \ + } \ + } + +#ifdef HAVE_FSTATAT +PROBE(probe_fstatat, HAVE_FSTATAT_RUNTIME) +#endif + +#ifdef HAVE_FACCESSAT +PROBE(probe_faccessat, HAVE_FACCESSAT_RUNTIME) +#endif + +#ifdef HAVE_FCHMODAT +PROBE(probe_fchmodat, HAVE_FCHMODAT_RUNTIME) +#endif + +#ifdef HAVE_FCHOWNAT +PROBE(probe_fchownat, HAVE_FCHOWNAT_RUNTIME) +#endif + +#ifdef HAVE_LINKAT +PROBE(probe_linkat, HAVE_LINKAT_RUNTIME) +#endif + +#ifdef HAVE_FDOPENDIR +PROBE(probe_fdopendir, HAVE_FDOPENDIR_RUNTIME) +#endif + +#ifdef HAVE_MKDIRAT +PROBE(probe_mkdirat, HAVE_MKDIRAT_RUNTIME) +#endif + +#ifdef HAVE_RENAMEAT +PROBE(probe_renameat, HAVE_RENAMEAT_RUNTIME) +#endif + +#ifdef HAVE_UNLINKAT +PROBE(probe_unlinkat, HAVE_UNLINKAT_RUNTIME) +#endif + +#ifdef HAVE_OPENAT +PROBE(probe_openat, HAVE_OPENAT_RUNTIME) +#endif + +#ifdef HAVE_READLINKAT +PROBE(probe_readlinkat, HAVE_READLINKAT_RUNTIME) +#endif + +#ifdef HAVE_SYMLINKAT +PROBE(probe_symlinkat, HAVE_SYMLINKAT_RUNTIME) +#endif + +#ifdef HAVE_FUTIMENS +PROBE(probe_futimens, HAVE_FUTIMENS_RUNTIME) +#endif + +#ifdef HAVE_UTIMENSAT +PROBE(probe_utimensat, HAVE_UTIMENSAT_RUNTIME) +#endif + + + + +static const struct have_function { + const char * const label; + int (*probe)(void); +} have_functions[] = { #ifdef HAVE_FACCESSAT - "HAVE_FACCESSAT", + { "HAVE_FACCESSAT", probe_faccessat }, #endif #ifdef HAVE_FCHDIR - "HAVE_FCHDIR", + { "HAVE_FCHDIR", NULL }, #endif #ifdef HAVE_FCHMOD - "HAVE_FCHMOD", + { "HAVE_FCHMOD", NULL }, #endif #ifdef HAVE_FCHMODAT - "HAVE_FCHMODAT", + { "HAVE_FCHMODAT", probe_fchmodat }, #endif #ifdef HAVE_FCHOWN - "HAVE_FCHOWN", + { "HAVE_FCHOWN", NULL }, #endif #ifdef HAVE_FCHOWNAT - "HAVE_FCHOWNAT", + { "HAVE_FCHOWNAT", probe_fchownat }, #endif #ifdef HAVE_FEXECVE - "HAVE_FEXECVE", + { "HAVE_FEXECVE", NULL }, #endif #ifdef HAVE_FDOPENDIR - "HAVE_FDOPENDIR", + { "HAVE_FDOPENDIR", probe_fdopendir }, #endif #ifdef HAVE_FPATHCONF - "HAVE_FPATHCONF", + { "HAVE_FPATHCONF", NULL }, #endif #ifdef HAVE_FSTATAT - "HAVE_FSTATAT", + { "HAVE_FSTATAT", probe_fstatat }, #endif #ifdef HAVE_FSTATVFS - "HAVE_FSTATVFS", + { "HAVE_FSTATVFS", NULL }, #endif #if defined HAVE_FTRUNCATE || defined MS_WINDOWS - "HAVE_FTRUNCATE", + { "HAVE_FTRUNCATE", NULL }, #endif #ifdef HAVE_FUTIMENS - "HAVE_FUTIMENS", + { "HAVE_FUTIMENS", probe_futimens }, #endif #ifdef HAVE_FUTIMES - "HAVE_FUTIMES", + { "HAVE_FUTIMES", NULL }, #endif #ifdef HAVE_FUTIMESAT - "HAVE_FUTIMESAT", + { "HAVE_FUTIMESAT", NULL }, #endif #ifdef HAVE_LINKAT - "HAVE_LINKAT", + { "HAVE_LINKAT", probe_linkat }, #endif #ifdef HAVE_LCHFLAGS - "HAVE_LCHFLAGS", + { "HAVE_LCHFLAGS", NULL }, #endif #ifdef HAVE_LCHMOD - "HAVE_LCHMOD", + { "HAVE_LCHMOD", NULL }, #endif #ifdef HAVE_LCHOWN - "HAVE_LCHOWN", + { "HAVE_LCHOWN", NULL }, #endif #ifdef HAVE_LSTAT - "HAVE_LSTAT", + { "HAVE_LSTAT", NULL }, #endif #ifdef HAVE_LUTIMES - "HAVE_LUTIMES", + { "HAVE_LUTIMES", NULL }, #endif #ifdef HAVE_MEMFD_CREATE - "HAVE_MEMFD_CREATE", + { "HAVE_MEMFD_CREATE", NULL }, #endif #ifdef HAVE_MKDIRAT - "HAVE_MKDIRAT", + { "HAVE_MKDIRAT", probe_mkdirat }, #endif #ifdef HAVE_MKFIFOAT - "HAVE_MKFIFOAT", + { "HAVE_MKFIFOAT", NULL }, #endif #ifdef HAVE_MKNODAT - "HAVE_MKNODAT", + { "HAVE_MKNODAT", NULL }, #endif #ifdef HAVE_OPENAT - "HAVE_OPENAT", + { "HAVE_OPENAT", probe_openat }, #endif #ifdef HAVE_READLINKAT - "HAVE_READLINKAT", + { "HAVE_READLINKAT", probe_readlinkat }, #endif #ifdef HAVE_RENAMEAT - "HAVE_RENAMEAT", + { "HAVE_RENAMEAT", probe_renameat }, #endif #ifdef HAVE_SYMLINKAT - "HAVE_SYMLINKAT", + { "HAVE_SYMLINKAT", probe_symlinkat }, #endif #ifdef HAVE_UNLINKAT - "HAVE_UNLINKAT", + { "HAVE_UNLINKAT", probe_unlinkat }, #endif #ifdef HAVE_UTIMENSAT - "HAVE_UTIMENSAT", + { "HAVE_UTIMENSAT", probe_utimensat }, #endif #ifdef MS_WINDOWS - "MS_WINDOWS", + { "MS_WINDOWS", NULL }, #endif - NULL + { NULL, NULL } }; @@ -14841,6 +15332,23 @@ posixmodule_exec(PyObject *m) { _posixstate *state = get_posix_state(m); +#if defined(HAVE_PWRITEV) + if (HAVE_PWRITEV_RUNTIME) {} else { + PyObject* dct = PyModule_GetDict(m); + + if (dct == NULL) { + return -1; + } + + if (PyDict_DelItemString(dct, "pwritev") == -1) { + PyErr_Clear(); + } + if (PyDict_DelItemString(dct, "preadv") == -1) { + PyErr_Clear(); + } + } +#endif + /* Initialize environ dictionary */ PyObject *v = convertenviron(); Py_XINCREF(v); @@ -14953,44 +15461,6 @@ posixmodule_exec(PyObject *m) PyModule_AddObject(m, "uname_result", (PyObject *)UnameResultType); state->UnameResultType = (PyObject *)UnameResultType; -#ifdef __APPLE__ - /* - * Step 2 of weak-linking support on Mac OS X. - * - * The code below removes functions that are not available on the - * currently active platform. - * - * This block allow one to use a python binary that was build on - * OSX 10.4 on OSX 10.3, without losing access to new APIs on - * OSX 10.4. - */ -#ifdef HAVE_FSTATVFS - if (fstatvfs == NULL) { - if (PyObject_DelAttrString(m, "fstatvfs") == -1) { - return -1; - } - } -#endif /* HAVE_FSTATVFS */ - -#ifdef HAVE_STATVFS - if (statvfs == NULL) { - if (PyObject_DelAttrString(m, "statvfs") == -1) { - return -1; - } - } -#endif /* HAVE_STATVFS */ - -# ifdef HAVE_LCHOWN - if (lchown == NULL) { - if (PyObject_DelAttrString(m, "lchown") == -1) { - return -1; - } - } -#endif /* HAVE_LCHOWN */ - - -#endif /* __APPLE__ */ - if ((state->billion = PyLong_FromLong(1000000000)) == NULL) return -1; #if defined(HAVE_WAIT3) || defined(HAVE_WAIT4) @@ -15020,14 +15490,17 @@ posixmodule_exec(PyObject *m) if (!list) { return -1; } - for (const char * const *trace = have_functions; *trace; trace++) { - PyObject *unicode = PyUnicode_DecodeASCII(*trace, strlen(*trace), NULL); + for (const struct have_function *trace = have_functions; trace->label; trace++) { + PyObject *unicode; + if (trace->probe && !trace->probe()) continue; + unicode = PyUnicode_DecodeASCII(trace->label, strlen(trace->label), NULL); if (!unicode) return -1; if (PyList_Append(list, unicode)) return -1; Py_DECREF(unicode); } + PyModule_AddObject(m, "_have_functions", list); return 0; diff --git a/Modules/timemodule.c b/Modules/timemodule.c index eb192c5e7fd31e..80eab30c95d6f0 100644 --- a/Modules/timemodule.c +++ b/Modules/timemodule.c @@ -51,6 +51,15 @@ #define _Py_tzname tzname #endif +#if defined(__APPLE__ ) && defined(__has_builtin) +# if __has_builtin(__builtin_available) +# define HAVE_CLOCK_GETTIME_RUNTIME __builtin_available(macOS 10.12, iOS 10.0, tvOS 10.0, watchOS 3.0, *) +# endif +#endif +#ifndef HAVE_CLOCK_GETTIME_RUNTIME +# define HAVE_CLOCK_GETTIME_RUNTIME 1 +#endif + #define SEC_TO_NS (1000 * 1000 * 1000) /* Forward declarations */ @@ -149,6 +158,16 @@ perf_counter(_Py_clock_info_t *info) } #ifdef HAVE_CLOCK_GETTIME + +#ifdef __APPLE__ +/* + * The clock_* functions will be removed from the module + * dict entirely when the C API is not available. + */ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunguarded-availability" +#endif + static PyObject * time_clock_gettime(PyObject *self, PyObject *args) { @@ -297,6 +316,11 @@ PyDoc_STRVAR(clock_getres_doc, "clock_getres(clk_id) -> floating point number\n\ \n\ Return the resolution (precision) of the specified clock clk_id."); + +#ifdef __APPLE__ +#pragma clang diagnostic pop +#endif + #endif /* HAVE_CLOCK_GETRES */ #ifdef HAVE_PTHREAD_GETCPUCLOCKID @@ -1162,31 +1186,35 @@ _PyTime_GetProcessTimeWithInfo(_PyTime_t *tp, _Py_clock_info_t *info) #if defined(HAVE_CLOCK_GETTIME) \ && (defined(CLOCK_PROCESS_CPUTIME_ID) || defined(CLOCK_PROF)) struct timespec ts; + + if (HAVE_CLOCK_GETTIME_RUNTIME) { + #ifdef CLOCK_PROF - const clockid_t clk_id = CLOCK_PROF; - const char *function = "clock_gettime(CLOCK_PROF)"; + const clockid_t clk_id = CLOCK_PROF; + const char *function = "clock_gettime(CLOCK_PROF)"; #else - const clockid_t clk_id = CLOCK_PROCESS_CPUTIME_ID; - const char *function = "clock_gettime(CLOCK_PROCESS_CPUTIME_ID)"; + const clockid_t clk_id = CLOCK_PROCESS_CPUTIME_ID; + const char *function = "clock_gettime(CLOCK_PROCESS_CPUTIME_ID)"; #endif - if (clock_gettime(clk_id, &ts) == 0) { - if (info) { - struct timespec res; - info->implementation = function; - info->monotonic = 1; - info->adjustable = 0; - if (clock_getres(clk_id, &res)) { - PyErr_SetFromErrno(PyExc_OSError); - return -1; + if (clock_gettime(clk_id, &ts) == 0) { + if (info) { + struct timespec res; + info->implementation = function; + info->monotonic = 1; + info->adjustable = 0; + if (clock_getres(clk_id, &res)) { + PyErr_SetFromErrno(PyExc_OSError); + return -1; + } + info->resolution = res.tv_sec + res.tv_nsec * 1e-9; } - info->resolution = res.tv_sec + res.tv_nsec * 1e-9; - } - if (_PyTime_FromTimespec(tp, &ts) < 0) { - return -1; + if (_PyTime_FromTimespec(tp, &ts) < 0) { + return -1; + } + return 0; } - return 0; } #endif @@ -1390,6 +1418,16 @@ _PyTime_GetThreadTimeWithInfo(_PyTime_t *tp, _Py_clock_info_t *info) #elif defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_PROCESS_CPUTIME_ID) #define HAVE_THREAD_TIME + +#if defined(__APPLE__) && defined(__has_attribute) && __has_attribute(availability) +static int +_PyTime_GetThreadTimeWithInfo(_PyTime_t *tp, _Py_clock_info_t *info) + __attribute__((availability(macos, introduced=10.12))) + __attribute__((availability(ios, introduced=10.0))) + __attribute__((availability(tvos, introduced=10.0))) + __attribute__((availability(watchos, introduced=3.0))); +#endif + static int _PyTime_GetThreadTimeWithInfo(_PyTime_t *tp, _Py_clock_info_t *info) { @@ -1421,6 +1459,15 @@ _PyTime_GetThreadTimeWithInfo(_PyTime_t *tp, _Py_clock_info_t *info) #endif #ifdef HAVE_THREAD_TIME +#ifdef __APPLE__ +/* + * The clock_* functions will be removed from the module + * dict entirely when the C API is not available. + */ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunguarded-availability" +#endif + static PyObject * time_thread_time(PyObject *self, PyObject *unused) { @@ -1451,6 +1498,11 @@ PyDoc_STRVAR(thread_time_ns_doc, \n\ Thread time for profiling as nanoseconds:\n\ sum of the kernel and user-space CPU time."); + +#ifdef __APPLE__ +#pragma clang diagnostic pop +#endif + #endif @@ -1500,9 +1552,19 @@ time_get_clock_info(PyObject *self, PyObject *args) } #ifdef HAVE_THREAD_TIME else if (strcmp(name, "thread_time") == 0) { - if (_PyTime_GetThreadTimeWithInfo(&t, &info) < 0) { + +#ifdef __APPLE__ + if (HAVE_CLOCK_GETTIME_RUNTIME) { +#endif + if (_PyTime_GetThreadTimeWithInfo(&t, &info) < 0) { + return NULL; + } +#ifdef __APPLE__ + } else { + PyErr_SetString(PyExc_ValueError, "unknown clock"); return NULL; } +#endif } #endif else { @@ -1783,68 +1845,116 @@ if it is -1, mktime() should guess based on the date and time.\n"); static int time_exec(PyObject *module) { +#if defined(__APPLE__) && defined(HAVE_CLOCK_GETTIME) + if (HAVE_CLOCK_GETTIME_RUNTIME) { + /* pass: ^^^ cannot use '!' here */ + } else { + PyObject* dct = PyModule_GetDict(module); + if (dct == NULL) { + return -1; + } + + if (PyDict_DelItemString(dct, "clock_gettime") == -1) { + PyErr_Clear(); + } + if (PyDict_DelItemString(dct, "clock_gettime_ns") == -1) { + PyErr_Clear(); + } + if (PyDict_DelItemString(dct, "clock_settime") == -1) { + PyErr_Clear(); + } + if (PyDict_DelItemString(dct, "clock_settime_ns") == -1) { + PyErr_Clear(); + } + if (PyDict_DelItemString(dct, "clock_getres") == -1) { + PyErr_Clear(); + } + } +#endif +#if defined(__APPLE__) && defined(HAVE_THREAD_TIME) + if (HAVE_CLOCK_GETTIME_RUNTIME) { + /* pass: ^^^ cannot use '!' here */ + } else { + PyObject* dct = PyModule_GetDict(module); + + if (PyDict_DelItemString(dct, "thread_time") == -1) { + PyErr_Clear(); + } + if (PyDict_DelItemString(dct, "thread_time_ns") == -1) { + PyErr_Clear(); + } + } +#endif /* Set, or reset, module variables like time.timezone */ if (init_timezone(module) < 0) { return -1; } #if defined(HAVE_CLOCK_GETTIME) || defined(HAVE_CLOCK_SETTIME) || defined(HAVE_CLOCK_GETRES) + if (HAVE_CLOCK_GETTIME_RUNTIME) { #ifdef CLOCK_REALTIME - if (PyModule_AddIntMacro(module, CLOCK_REALTIME) < 0) { - return -1; - } + if (PyModule_AddIntMacro(module, CLOCK_REALTIME) < 0) { + return -1; + } #endif + #ifdef CLOCK_MONOTONIC - if (PyModule_AddIntMacro(module, CLOCK_MONOTONIC) < 0) { - return -1; - } + + if (PyModule_AddIntMacro(module, CLOCK_MONOTONIC) < 0) { + return -1; + } + #endif #ifdef CLOCK_MONOTONIC_RAW - if (PyModule_AddIntMacro(module, CLOCK_MONOTONIC_RAW) < 0) { - return -1; - } + if (PyModule_AddIntMacro(module, CLOCK_MONOTONIC_RAW) < 0) { + return -1; + } #endif + #ifdef CLOCK_HIGHRES - if (PyModule_AddIntMacro(module, CLOCK_HIGHRES) < 0) { - return -1; - } + if (PyModule_AddIntMacro(module, CLOCK_HIGHRES) < 0) { + return -1; + } #endif #ifdef CLOCK_PROCESS_CPUTIME_ID - if (PyModule_AddIntMacro(module, CLOCK_PROCESS_CPUTIME_ID) < 0) { - return -1; - } + if (PyModule_AddIntMacro(module, CLOCK_PROCESS_CPUTIME_ID) < 0) { + return -1; + } #endif + #ifdef CLOCK_THREAD_CPUTIME_ID - if (PyModule_AddIntMacro(module, CLOCK_THREAD_CPUTIME_ID) < 0) { - return -1; - } + if (PyModule_AddIntMacro(module, CLOCK_THREAD_CPUTIME_ID) < 0) { + return -1; + } #endif #ifdef CLOCK_PROF - if (PyModule_AddIntMacro(module, CLOCK_PROF) < 0) { - return -1; - } + if (PyModule_AddIntMacro(module, CLOCK_PROF) < 0) { + return -1; + } #endif #ifdef CLOCK_BOOTTIME - if (PyModule_AddIntMacro(module, CLOCK_BOOTTIME) < 0) { - return -1; - } + if (PyModule_AddIntMacro(module, CLOCK_BOOTTIME) < 0) { + return -1; + } #endif #ifdef CLOCK_TAI - if (PyModule_AddIntMacro(module, CLOCK_TAI) < 0) { - return -1; - } + if (PyModule_AddIntMacro(module, CLOCK_TAI) < 0) { + return -1; + } #endif #ifdef CLOCK_UPTIME - if (PyModule_AddIntMacro(module, CLOCK_UPTIME) < 0) { - return -1; - } + if (PyModule_AddIntMacro(module, CLOCK_UPTIME) < 0) { + return -1; + } #endif #ifdef CLOCK_UPTIME_RAW - if (PyModule_AddIntMacro(module, CLOCK_UPTIME_RAW) < 0) { - return -1; - } + + if (PyModule_AddIntMacro(module, CLOCK_UPTIME_RAW) < 0) { + return -1; + } #endif + } #endif /* defined(HAVE_CLOCK_GETTIME) || defined(HAVE_CLOCK_SETTIME) || defined(HAVE_CLOCK_GETRES) */ diff --git a/Python/bootstrap_hash.c b/Python/bootstrap_hash.c index 47369305ee88e9..a212f69870ed10 100644 --- a/Python/bootstrap_hash.c +++ b/Python/bootstrap_hash.c @@ -25,6 +25,16 @@ # include #endif +#if defined(__APPLE__) && defined(__has_builtin) +# if __has_builtin(__builtin_available) +# define HAVE_GETENTRYPY_GETRANDOM_RUNTIME __builtin_available(macOS 10.12, iOS 10.10, tvOS 10.0, watchOS 3.0, *) +# endif +#endif +#ifndef HAVE_GETENTRYPY_GETRANDOM_RUNTIME +# define HAVE_GETENTRYPY_GETRANDOM_RUNTIME 1 +#endif + + #ifdef Py_DEBUG int _Py_HashSecret_Initialized = 0; #else @@ -208,6 +218,16 @@ py_getrandom(void *buffer, Py_ssize_t size, int blocking, int raise) error. getentropy() is retried if it failed with EINTR: interrupted by a signal. */ + +#if defined(__APPLE__) && defined(__has_attribute) && __has_attribute(availability) +static int +py_getentropy(char *buffer, Py_ssize_t size, int raise) + __attribute__((availability(macos,introduced=10.12))) + __attribute__((availability(ios,introduced=10.0))) + __attribute__((availability(tvos,introduced=10.0))) + __attribute__((availability(watchos,introduced=3.0))); +#endif + static int py_getentropy(char *buffer, Py_ssize_t size, int raise) { @@ -498,19 +518,21 @@ pyurandom(void *buffer, Py_ssize_t size, int blocking, int raise) #else #if defined(PY_GETRANDOM) || defined(PY_GETENTROPY) + if (HAVE_GETENTRYPY_GETRANDOM_RUNTIME) { #ifdef PY_GETRANDOM - res = py_getrandom(buffer, size, blocking, raise); + res = py_getrandom(buffer, size, blocking, raise); #else - res = py_getentropy(buffer, size, raise); + res = py_getentropy(buffer, size, raise); #endif - if (res < 0) { - return -1; - } - if (res == 1) { - return 0; - } - /* getrandom() or getentropy() function is not available: failed with - ENOSYS or EPERM. Fall back on reading from /dev/urandom. */ + if (res < 0) { + return -1; + } + if (res == 1) { + return 0; + } + /* getrandom() or getentropy() function is not available: failed with + ENOSYS or EPERM. Fall back on reading from /dev/urandom. */ + } /* end of availability block */ #endif return dev_urandom(buffer, size, raise); diff --git a/Python/pytime.c b/Python/pytime.c index b121b432f428d7..89d63e080422b3 100644 --- a/Python/pytime.c +++ b/Python/pytime.c @@ -5,6 +5,12 @@ #if defined(__APPLE__) #include /* mach_absolute_time(), mach_timebase_info() */ + +#if defined(__APPLE__) && defined(__has_builtin) +# if __has_builtin(__builtin_available) +# define HAVE_CLOCK_GETTIME_RUNTIME __builtin_available(macOS 10.12, iOS 10.0, tvOS 10.0, watchOS 3.0, *) +# endif +#endif #endif #define _PyTime_check_mul_overflow(a, b) \ @@ -683,15 +689,22 @@ pygettimeofday(_PyTime_t *tp, _Py_clock_info_t *info, int raise) #else /* MS_WINDOWS */ int err; -#ifdef HAVE_CLOCK_GETTIME +#if defined(HAVE_CLOCK_GETTIME) struct timespec ts; -#else +#endif + +#if !defined(HAVE_CLOCK_GETTIME) || defined(__APPLE__) struct timeval tv; #endif assert(info == NULL || raise); #ifdef HAVE_CLOCK_GETTIME + +#ifdef HAVE_CLOCK_GETTIME_RUNTIME + if (HAVE_CLOCK_GETTIME_RUNTIME) { +#endif + err = clock_gettime(CLOCK_REALTIME, &ts); if (err) { if (raise) { @@ -715,7 +728,14 @@ pygettimeofday(_PyTime_t *tp, _Py_clock_info_t *info, int raise) info->resolution = 1e-9; } } -#else /* HAVE_CLOCK_GETTIME */ + +#ifdef HAVE_CLOCK_GETTIME_RUNTIME + } else { +#endif + +#endif + +#if !defined(HAVE_CLOCK_GETTIME) || defined(HAVE_CLOCK_GETTIME_RUNTIME) /* test gettimeofday() */ err = gettimeofday(&tv, (struct timezone *)NULL); @@ -735,6 +755,11 @@ pygettimeofday(_PyTime_t *tp, _Py_clock_info_t *info, int raise) info->monotonic = 0; info->adjustable = 1; } + +#if defined(HAVE_CLOCK_GETTIME_RUNTIME) && defined(HAVE_CLOCK_GETTIME) + } /* end of availibity block */ +#endif + #endif /* !HAVE_CLOCK_GETTIME */ #endif /* !MS_WINDOWS */ return 0; diff --git a/configure b/configure index 040c828bf95ecb..2d379feb4b7bf0 100755 --- a/configure +++ b/configure @@ -1510,8 +1510,8 @@ Optional Packages: specify the kind of universal binary that should be created. this option is only valid when --enable-universalsdk is set; options are: - ("32-bit", "64-bit", "3-way", "intel", "intel-32", - "intel-64", or "all") see Mac/README.rst + ("universal2", "32-bit", "64-bit", "3-way", "intel", + "intel-32", "intel-64", or "all") see Mac/README.rst --with-framework-name=FRAMEWORK specify the name for the python framework on macOS only valid when --enable-framework is set. see @@ -6954,7 +6954,7 @@ fi -# The -arch flags for universal builds on OSX +# The -arch flags for universal builds on macOS UNIVERSAL_ARCH_FLAGS= @@ -7481,6 +7481,11 @@ $as_echo "$CC" >&6; } LIPO_32BIT_FLAGS="-extract ppc7400 -extract i386" ARCH_RUN_32BIT="/usr/bin/arch -i386 -ppc" ;; + universal2) + UNIVERSAL_ARCH_FLAGS="-arch arm64 -arch x86_64" + LIPO_32BIT_FLAGS="" + ARCH_RUN_32BIT="true" + ;; intel) UNIVERSAL_ARCH_FLAGS="-arch i386 -arch x86_64" LIPO_32BIT_FLAGS="-extract i386" @@ -7502,7 +7507,7 @@ $as_echo "$CC" >&6; } ARCH_RUN_32BIT="/usr/bin/arch -i386 -ppc" ;; *) - as_fn_error $? "proper usage is --with-universal-arch=32-bit|64-bit|all|intel|3-way" "$LINENO" 5 + as_fn_error $? "proper usage is --with-universal-arch=universal2|32-bit|64-bit|all|intel|3-way" "$LINENO" 5 ;; esac @@ -9359,7 +9364,7 @@ fi MACOSX_DEFAULT_ARCH="ppc" ;; *) - as_fn_error $? "Unexpected output of 'arch' on OSX" "$LINENO" 5 + as_fn_error $? "Unexpected output of 'arch' on macOS" "$LINENO" 5 ;; esac else @@ -9369,9 +9374,12 @@ fi ;; ppc) MACOSX_DEFAULT_ARCH="ppc64" + ;; + arm64) + MACOSX_DEFAULT_ARCH="arm64" ;; *) - as_fn_error $? "Unexpected output of 'arch' on OSX" "$LINENO" 5 + as_fn_error $? "Unexpected output of 'arch' on macOS" "$LINENO" 5 ;; esac @@ -12012,6 +12020,31 @@ else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for _dyld_shared_cache_contains_path" >&5 +$as_echo_n "checking for _dyld_shared_cache_contains_path... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +void *x=_dyld_shared_cache_contains_path + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + +$as_echo "#define HAVE_DYLD_SHARED_CACHE_CONTAINS_PATH 1" >>confdefs.h + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext diff --git a/configure.ac b/configure.ac index 29acb8efa1ad38..c968d149c22d44 100644 --- a/configure.ac +++ b/configure.ac @@ -218,7 +218,7 @@ AC_ARG_WITH(universal-archs, AS_HELP_STRING([--with-universal-archs=ARCH], [specify the kind of universal binary that should be created. this option is only valid when --enable-universalsdk is set; options are: - ("32-bit", "64-bit", "3-way", "intel", "intel-32", "intel-64", or "all") + ("universal2", "32-bit", "64-bit", "3-way", "intel", "intel-32", "intel-64", or "all") see Mac/README.rst]), [ UNIVERSAL_ARCHS="$withval" @@ -1587,7 +1587,7 @@ AC_SUBST(BASECFLAGS) AC_SUBST(CFLAGS_NODIST) AC_SUBST(LDFLAGS_NODIST) -# The -arch flags for universal builds on OSX +# The -arch flags for universal builds on macOS UNIVERSAL_ARCH_FLAGS= AC_SUBST(UNIVERSAL_ARCH_FLAGS) @@ -1888,6 +1888,11 @@ yes) LIPO_32BIT_FLAGS="-extract ppc7400 -extract i386" ARCH_RUN_32BIT="/usr/bin/arch -i386 -ppc" ;; + universal2) + UNIVERSAL_ARCH_FLAGS="-arch arm64 -arch x86_64" + LIPO_32BIT_FLAGS="" + ARCH_RUN_32BIT="true" + ;; intel) UNIVERSAL_ARCH_FLAGS="-arch i386 -arch x86_64" LIPO_32BIT_FLAGS="-extract i386" @@ -1909,7 +1914,7 @@ yes) ARCH_RUN_32BIT="/usr/bin/arch -i386 -ppc" ;; *) - AC_MSG_ERROR([proper usage is --with-universal-arch=32-bit|64-bit|all|intel|3-way]) + AC_MSG_ERROR([proper usage is --with-universal-arch=universal2|32-bit|64-bit|all|intel|3-way]) ;; esac @@ -2486,7 +2491,7 @@ case $ac_sys_system/$ac_sys_release in MACOSX_DEFAULT_ARCH="ppc" ;; *) - AC_MSG_ERROR([Unexpected output of 'arch' on OSX]) + AC_MSG_ERROR([Unexpected output of 'arch' on macOS]) ;; esac else @@ -2496,9 +2501,12 @@ case $ac_sys_system/$ac_sys_release in ;; ppc) MACOSX_DEFAULT_ARCH="ppc64" + ;; + arm64) + MACOSX_DEFAULT_ARCH="arm64" ;; *) - AC_MSG_ERROR([Unexpected output of 'arch' on OSX]) + AC_MSG_ERROR([Unexpected output of 'arch' on macOS]) ;; esac @@ -3777,6 +3785,12 @@ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ AC_MSG_RESULT(yes)], [AC_MSG_RESULT(no) ]) +AC_MSG_CHECKING(for _dyld_shared_cache_contains_path) +AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], [[void *x=_dyld_shared_cache_contains_path]])], + [AC_DEFINE(HAVE_DYLD_SHARED_CACHE_CONTAINS_PATH, 1, Define if you have the '_dyld_shared_cache_contains_path' function.) + AC_MSG_RESULT(yes)], + [AC_MSG_RESULT(no) +]) AC_MSG_CHECKING(for memfd_create) AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ diff --git a/pyconfig.h.in b/pyconfig.h.in index c9589cd102a192..f39858d10c457a 100644 --- a/pyconfig.h.in +++ b/pyconfig.h.in @@ -778,6 +778,9 @@ /* Define if you have the 'prlimit' functions. */ #undef HAVE_PRLIMIT +/* Define if you have the '_dyld_shared_cache_contains_path' function. */ +#undef HAVE_DYLD_SHARED_CACHE_CONTAINS_PATH + /* Define to 1 if you have the header file. */ #undef HAVE_PROCESS_H diff --git a/setup.py b/setup.py index 103688285e68ff..7432970a106919 100644 --- a/setup.py +++ b/setup.py @@ -216,6 +216,13 @@ def is_macosx_sdk_path(path): or path.startswith('/Library/') ) +def grep_headers_for(function, headers): + for header in headers: + with open(header, 'r', errors='surrogateescape') as f: + if function in f.read(): + return True + return False + def find_file(filename, std_dirs, paths): """Searches for the directory where a given file is located, and returns a possibly-empty list of additional directories, or None @@ -2078,43 +2085,17 @@ def detect_tkinter(self): library_dirs=added_lib_dirs)) return True - def configure_ctypes_darwin(self, ext): - # Darwin (OS X) uses preconfigured files, in - # the Modules/_ctypes/libffi_osx directory. - ffi_srcdir = os.path.abspath(os.path.join(self.srcdir, 'Modules', - '_ctypes', 'libffi_osx')) - sources = [os.path.join(ffi_srcdir, p) - for p in ['ffi.c', - 'x86/darwin64.S', - 'x86/x86-darwin.S', - 'x86/x86-ffi_darwin.c', - 'x86/x86-ffi64.c', - 'powerpc/ppc-darwin.S', - 'powerpc/ppc-darwin_closure.S', - 'powerpc/ppc-ffi_darwin.c', - 'powerpc/ppc64-darwin_closure.S', - ]] - - # Add .S (preprocessed assembly) to C compiler source extensions. - self.compiler.src_extensions.append('.S') - - include_dirs = [os.path.join(ffi_srcdir, 'include'), - os.path.join(ffi_srcdir, 'powerpc')] - ext.include_dirs.extend(include_dirs) - ext.sources.extend(sources) - return True - def configure_ctypes(self, ext): - if not self.use_system_libffi: - if MACOS: - return self.configure_ctypes_darwin(ext) - print('INFO: Could not locate ffi libs and/or headers') - return False return True def detect_ctypes(self): # Thomas Heller's _ctypes module - self.use_system_libffi = False + + if (not sysconfig.get_config_var("LIBFFI_INCLUDEDIR") and MACOS): + self.use_system_libffi = True + else: + self.use_system_libffi = '--with-system-ffi' in sysconfig.get_config_var("CONFIG_ARGS") + include_dirs = [] extra_compile_args = ['-DPy_BUILD_CORE_MODULE'] extra_link_args = [] @@ -2127,11 +2108,9 @@ def detect_ctypes(self): if MACOS: sources.append('_ctypes/malloc_closure.c') - sources.append('_ctypes/darwin/dlfcn_simple.c') + extra_compile_args.append('-DUSING_MALLOC_CLOSURE_DOT_C=1') extra_compile_args.append('-DMACOSX') include_dirs.append('_ctypes/darwin') - # XXX Is this still needed? - # extra_link_args.extend(['-read_only_relocs', 'warning']) elif HOST_PLATFORM == 'sunos5': # XXX This shouldn't be necessary; it appears that some @@ -2161,31 +2140,48 @@ def detect_ctypes(self): sources=['_ctypes/_ctypes_test.c'], libraries=['m'])) + ffi_inc = sysconfig.get_config_var("LIBFFI_INCLUDEDIR") + ffi_lib = None + ffi_inc_dirs = self.inc_dirs.copy() if MACOS: - if '--with-system-ffi' not in sysconfig.get_config_var("CONFIG_ARGS"): - return - # OS X 10.5 comes with libffi.dylib; the include files are - # in /usr/include/ffi - ffi_inc_dirs.append('/usr/include/ffi') - - ffi_inc = [sysconfig.get_config_var("LIBFFI_INCLUDEDIR")] - if not ffi_inc or ffi_inc[0] == '': - ffi_inc = find_file('ffi.h', [], ffi_inc_dirs) - if ffi_inc is not None: - ffi_h = ffi_inc[0] + '/ffi.h' + ffi_in_sdk = os.path.join(macosx_sdk_root(), "usr/include/ffi") + + if not ffi_inc: + if os.path.exists(ffi_in_sdk): + ext.extra_compile_args.append("-DUSING_APPLE_OS_LIBFFI=1") + ffi_inc = ffi_in_sdk + ffi_lib = 'ffi' + else: + # OS X 10.5 comes with libffi.dylib; the include files are + # in /usr/include/ffi + ffi_inc_dirs.append('/usr/include/ffi') + + if not ffi_inc: + found = find_file('ffi.h', [], ffi_inc_dirs) + if found: + ffi_inc = found[0] + if ffi_inc: + ffi_h = ffi_inc + '/ffi.h' if not os.path.exists(ffi_h): ffi_inc = None print('Header file {} does not exist'.format(ffi_h)) - ffi_lib = None - if ffi_inc is not None: + if ffi_lib is None and ffi_inc: for lib_name in ('ffi', 'ffi_pic'): if (self.compiler.find_library_file(self.lib_dirs, lib_name)): ffi_lib = lib_name break if ffi_inc and ffi_lib: - ext.include_dirs.extend(ffi_inc) + ffi_headers = glob(os.path.join(ffi_inc, '*.h')) + if grep_headers_for('ffi_prep_cif_var', ffi_headers): + ext.extra_compile_args.append("-DHAVE_FFI_PREP_CIF_VAR=1") + if grep_headers_for('ffi_prep_closure_loc', ffi_headers): + ext.extra_compile_args.append("-DHAVE_FFI_PREP_CLOSURE_LOC=1") + if grep_headers_for('ffi_closure_alloc', ffi_headers): + ext.extra_compile_args.append("-DHAVE_FFI_CLOSURE_ALLOC=1") + + ext.include_dirs.append(ffi_inc) ext.libraries.append(ffi_lib) self.use_system_libffi = True From 41d1ebb33efb85cf530972da8172460cc076ff61 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 22 Nov 2020 07:16:48 -0800 Subject: [PATCH 0732/1314] Doc: fix typo in typing.Type docs (GH-23460) (cherry picked from commit 5ef53a88f3130cfcf9a9be3abd2ff2f997902647) Co-authored-by: John Belmonte --- Doc/library/typing.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst index 28c607e149139e..af2cafb8b9969c 100644 --- a/Doc/library/typing.rst +++ b/Doc/library/typing.rst @@ -622,7 +622,7 @@ These can be used as types in annotations using ``[]``, each having a unique syn :ref:`type variables `, and unions of any of these types. For example:: - def new_non_team_user(user_class: Type[Union[BaseUser, ProUser]]): ... + def new_non_team_user(user_class: Type[Union[BasicUser, ProUser]]): ... ``Type[Any]`` is equivalent to ``Type`` which in turn is equivalent to ``type``, which is the root of Python's metaclass hierarchy. From 85720596f1baf8db2cd456c8c2bd07dc03c6beca Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 22 Nov 2020 10:22:21 -0800 Subject: [PATCH 0733/1314] bpo-42361: Use Tcl/Tk 8.6.10 when building the installer on recent macOS (GH-23293) Building on older versions, and in particular macOS 10.9 still use Tk 8.6.8 because of build problems on that version of macOS. (cherry picked from commit 690a5fa3ddc675a434730b057ddb5c33f44fd0b7) Co-authored-by: Ronald Oussoren --- Mac/BuildScript/build-installer.py | 41 +++++++++++++++++++++++------- 1 file changed, 32 insertions(+), 9 deletions(-) diff --git a/Mac/BuildScript/build-installer.py b/Mac/BuildScript/build-installer.py index 0e76d3ca5bbc2e..184add4c4f06c5 100755 --- a/Mac/BuildScript/build-installer.py +++ b/Mac/BuildScript/build-installer.py @@ -153,6 +153,9 @@ def getFullVersion(): def getDeptargetTuple(): return tuple([int(n) for n in DEPTARGET.split('.')[0:2]]) +def getBuildTuple(): + return tuple([int(n) for n in platform.mac_ver()[0].split('.')[0:2]]) + def getTargetCompilers(): target_cc_map = { '10.4': ('gcc-4.0', 'g++-4.0'), @@ -192,6 +195,13 @@ def getTargetCompilers(): def internalTk(): return getDeptargetTuple() >= (10, 6) +# Do we use 8.6.8 when building our own copy +# of Tcl/Tk or a modern version. +# We use the old version when buildin on +# old versions of macOS due to build issues. +def useOldTk(): + return getBuildTuple() < (10, 15) + def tweak_tcl_build(basedir, archList): with open("Makefile", "r") as fp: @@ -245,11 +255,26 @@ def library_recipes(): ]) if internalTk(): + if useOldTk(): + tcl_tk_ver='8.6.8' + tcl_checksum='81656d3367af032e0ae6157eff134f89' + + tk_checksum='5e0faecba458ee1386078fb228d008ba' + tk_patches = ['tk868_on_10_8_10_9.patch'] + + else: + tcl_tk_ver='8.6.10' + tcl_checksum='97c55573f8520bcab74e21bfd8d0aadc' + + tk_checksum='602a47ad9ecac7bf655ada729d140a94' + tk_patches = [ ] + + result.extend([ dict( - name="Tcl 8.6.8", - url="ftp://ftp.tcl.tk/pub/tcl//tcl8_6/tcl8.6.8-src.tar.gz", - checksum='81656d3367af032e0ae6157eff134f89', + name="Tcl %s"%(tcl_tk_ver,), + url="ftp://ftp.tcl.tk/pub/tcl//tcl8_6/tcl%s-src.tar.gz"%(tcl_tk_ver,), + checksum=tcl_checksum, buildDir="unix", configure_pre=[ '--enable-shared', @@ -264,12 +289,10 @@ def library_recipes(): }, ), dict( - name="Tk 8.6.8", - url="ftp://ftp.tcl.tk/pub/tcl//tcl8_6/tk8.6.8-src.tar.gz", - checksum='5e0faecba458ee1386078fb228d008ba', - patches=[ - "tk868_on_10_8_10_9.patch", - ], + name="Tk %s"%(tcl_tk_ver,), + url="ftp://ftp.tcl.tk/pub/tcl//tcl8_6/tk%s-src.tar.gz"%(tcl_tk_ver,), + checksum=tk_checksum, + patches=tk_patches, buildDir="unix", configure_pre=[ '--enable-aqua', From 5aa6c99da1087ded0ccb99bb12591e5ab31d75c3 Mon Sep 17 00:00:00 2001 From: Ned Deily Date: Sun, 22 Nov 2020 23:43:04 -0500 Subject: [PATCH 0734/1314] bpo-41100: Update Whatsnew and installer ReadME for 3.9.1 (GH-23472) --- Doc/whatsnew/3.9.rst | 16 +++++++++++++++- Mac/BuildScript/resources/ReadMe.rtf | 18 ++++++++++++++++-- 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/Doc/whatsnew/3.9.rst b/Doc/whatsnew/3.9.rst index a638e544cb38fe..f8f421bdda1c7c 100644 --- a/Doc/whatsnew/3.9.rst +++ b/Doc/whatsnew/3.9.rst @@ -1482,4 +1482,18 @@ and to match the behavior of static type checkers specified in the PEP. File "", line 1, in TypeError: unhashable type: 'set' -(Contributed by Yurii Karabas in :issue:`42345`.) \ No newline at end of file +(Contributed by Yurii Karabas in :issue:`42345`.) + +macOS 11.0 (Big Sur) and Apple Silicon Mac support +-------------------------------------------------- + +As of 3.9.1, Python now fully supports building and running on macOS 11.0 +(Big Sur) and on Apple Silicon Macs (based on the ``ARM64`` architecture). +A new universal build variant, ``universal2``, is now available to natively +support both ``ARM64`` and ``Intel 64`` in one set of executables. Binaries +can also now be built on current versions of macOS to be deployed on a range +of older macOS versions (tested to 10.9) while making some newer OS +functions and options conditionally available based on the operating system +version in use at runtime ("weaklinking"). + +(Contributed by Ronald Oussoren and Lawrence D'Anna in :issue:`41100`.) diff --git a/Mac/BuildScript/resources/ReadMe.rtf b/Mac/BuildScript/resources/ReadMe.rtf index 9bc969863824a3..2c0c3d5eb3a096 100644 --- a/Mac/BuildScript/resources/ReadMe.rtf +++ b/Mac/BuildScript/resources/ReadMe.rtf @@ -3,7 +3,7 @@ \f3\fmodern\fcharset0 CourierNewPSMT;} {\colortbl;\red255\green255\blue255;} {\*\expandedcolortbl;;} -\margl1440\margr1440\vieww13380\viewh14600\viewkind0 +\margl1440\margr1440\vieww13380\viewh14580\viewkind0 \pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\pardirnatural\partightenfactor0 \f0\fs24 \cf0 This package will install Python $FULL_VERSION for macOS $MACOSX_DEPLOYMENT_TARGET for the following architecture(s): $ARCHITECTURES.\ @@ -50,7 +50,21 @@ Due to new security checks on macOS 10.15 Catalina, when launching IDLE macOS ma \f0\b0 button to proceed.\ \ -\f1\b \ul Other changes\ +\f1\b \ul macOS 11.0 (Big Sur) and Apple Silicon Mac support [new in 3.9.1]\ + +\f0\b0 \ulnone \ +As of 2020-11, macOS 11.0 (Big Sur) is the latest release of macOS and one of its major features is the support of new Apple Silicon Macs that are based on the ARM64 CPU architecture specification rather than the Intel 64 (x86_64) architecture used previously. There are other changes in Big Sur that affect Python operation regardless of CPU architecture. As of 3.9.1, Python binaries from python.org fully support Big Sur. \ +\ +python.org binaries for macOS have been provided via a downloadable installer that supports the Intel 64 architecture on macOS 10.9 and newer. This installer variant remains the default download for 3.9.1; it will install and run on all Macs that run macOS 10.9 or later, including 11.0 (Big Sur). This variant should run transparently on new Apple Silicon Macs using Apple's Rosetta 2 emulation. \ +\ +Beginning with 3.9.1, we also provide a new "universal2" installer variant that provides universal binaries for both ARM64 and Intel 64 architectures and is also supported on all Macs that support macOS 10.9 or later. Some of the advantages of the new installer variant: native ARM64 code on Apple Silicon Macs should run significantly faster than Rosetta2-emulated code; some operating system functions and options introduced in macOS releases since 10.9 are now exposed when available (primarily in the os module); binary wheels built for use with the current 10.9 variant *should* also work with the new variant; the new installer variant includes Tcl/Tk 8.6.10 rather than 8.6.8.\ +\ +Because of the scope of changes needed to fully support 11.0 and Apple Silicon Macs, the new "universal2" variant should be considered +\f2\i experimental +\f0\i0 in the 3.9.1 release. You may need to upgrade third-party components, like pip, to later versions once they are released. You may experience differences in behavior in IDLE and other Tk-based applications due to using the newer version of Tk. As always, if you encounter problems when using this installer variant, please check {\field{\*\fldinst{HYPERLINK "https://bugs.python.org"}}{\fldrslt https://bugs.python.org}} for existing reports and for opening new issues.\ + +\f1\b \ul \ +Other changes\ \f0\b0 \ulnone \ For other changes in this release, see the From 3e5330130810e485f1abbf192590b7109880a4da Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 23 Nov 2020 00:51:37 -0800 Subject: [PATCH 0735/1314] bpo-42328: Fix tkinter.ttk.Style.map(). (GH-23300) The function accepts now the representation of the default state as empty sequence (as returned by Style.map()). The structure of the result is now the same on all platform and does not depend on the value of wantobjects. (cherry picked from commit dd844a2916fb3a8f481ec7c732802c13c3375691) Co-authored-by: Serhiy Storchaka --- Lib/tkinter/test/test_ttk/test_functions.py | 7 +- Lib/tkinter/test/test_ttk/test_style.py | 90 +++++++++++++++++-- Lib/tkinter/ttk.py | 38 ++++---- .../2020-11-15-17-02-00.bpo-42328.bqpPlR.rst | 4 + 4 files changed, 111 insertions(+), 28 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2020-11-15-17-02-00.bpo-42328.bqpPlR.rst diff --git a/Lib/tkinter/test/test_ttk/test_functions.py b/Lib/tkinter/test/test_ttk/test_functions.py index f8e69a9f4165d6..5c23d6fecf8b42 100644 --- a/Lib/tkinter/test/test_ttk/test_functions.py +++ b/Lib/tkinter/test/test_ttk/test_functions.py @@ -137,6 +137,9 @@ def test_format_mapdict(self): result = ttk._format_mapdict(opts) self.assertEqual(result, ('-üñíćódè', 'á vãl')) + self.assertEqual(ttk._format_mapdict({'opt': [('value',)]}), + ('-opt', '{} value')) + # empty states valid = {'opt': [('', '', 'hi')]} self.assertEqual(ttk._format_mapdict(valid), ('-opt', '{ } hi')) @@ -159,10 +162,6 @@ def test_format_mapdict(self): opts = {'a': None} self.assertRaises(TypeError, ttk._format_mapdict, opts) - # items in the value must have size >= 2 - self.assertRaises(IndexError, ttk._format_mapdict, - {'a': [('invalid', )]}) - def test_format_elemcreate(self): self.assertTrue(ttk._format_elemcreate(None), (None, ())) diff --git a/Lib/tkinter/test/test_ttk/test_style.py b/Lib/tkinter/test/test_ttk/test_style.py index 3537536d81bc56..54e913311766f1 100644 --- a/Lib/tkinter/test/test_ttk/test_style.py +++ b/Lib/tkinter/test/test_ttk/test_style.py @@ -1,11 +1,22 @@ import unittest import tkinter from tkinter import ttk +from test import support from test.support import requires, run_unittest from tkinter.test.support import AbstractTkTest requires('gui') +CLASS_NAMES = [ + '.', 'ComboboxPopdownFrame', 'Heading', + 'Horizontal.TProgressbar', 'Horizontal.TScale', 'Item', 'Sash', + 'TButton', 'TCheckbutton', 'TCombobox', 'TEntry', + 'TLabelframe', 'TLabelframe.Label', 'TMenubutton', + 'TNotebook', 'TNotebook.Tab', 'Toolbutton', 'TProgressbar', + 'TRadiobutton', 'Treeview', 'TScale', 'TScrollbar', 'TSpinbox', + 'Vertical.TProgressbar', 'Vertical.TScale' +] + class StyleTest(AbstractTkTest, unittest.TestCase): def setUp(self): @@ -23,11 +34,36 @@ def test_configure(self): def test_map(self): style = self.style - style.map('TButton', background=[('active', 'background', 'blue')]) - self.assertEqual(style.map('TButton', 'background'), - [('active', 'background', 'blue')] if self.wantobjects else - [('active background', 'blue')]) - self.assertIsInstance(style.map('TButton'), dict) + + # Single state + for states in ['active'], [('active',)]: + with self.subTest(states=states): + style.map('TButton', background=[(*states, 'white')]) + expected = [('active', 'white')] + self.assertEqual(style.map('TButton', 'background'), expected) + m = style.map('TButton') + self.assertIsInstance(m, dict) + self.assertEqual(m['background'], expected) + + # Multiple states + for states in ['pressed', '!disabled'], ['pressed !disabled'], [('pressed', '!disabled')]: + with self.subTest(states=states): + style.map('TButton', background=[(*states, 'black')]) + expected = [('pressed', '!disabled', 'black')] + self.assertEqual(style.map('TButton', 'background'), expected) + m = style.map('TButton') + self.assertIsInstance(m, dict) + self.assertEqual(m['background'], expected) + + # Default state + for states in [], [''], [()]: + with self.subTest(states=states): + style.map('TButton', background=[(*states, 'grey')]) + expected = [('grey',)] + self.assertEqual(style.map('TButton', 'background'), expected) + m = style.map('TButton') + self.assertIsInstance(m, dict) + self.assertEqual(m['background'], expected) def test_lookup(self): @@ -86,6 +122,50 @@ def test_theme_use(self): self.style.theme_use(curr_theme) + def test_configure_custom_copy(self): + style = self.style + + curr_theme = self.style.theme_use() + self.addCleanup(self.style.theme_use, curr_theme) + for theme in self.style.theme_names(): + self.style.theme_use(theme) + for name in CLASS_NAMES: + default = style.configure(name) + if not default: + continue + with self.subTest(theme=theme, name=name): + if support.verbose >= 2: + print('configure', theme, name, default) + newname = f'C.{name}' + self.assertEqual(style.configure(newname), None) + style.configure(newname, **default) + self.assertEqual(style.configure(newname), default) + for key, value in default.items(): + self.assertEqual(style.configure(newname, key), value) + + + def test_map_custom_copy(self): + style = self.style + + curr_theme = self.style.theme_use() + self.addCleanup(self.style.theme_use, curr_theme) + for theme in self.style.theme_names(): + self.style.theme_use(theme) + for name in CLASS_NAMES: + default = style.map(name) + if not default: + continue + with self.subTest(theme=theme, name=name): + if support.verbose >= 2: + print('map', theme, name, default) + newname = f'C.{name}' + self.assertEqual(style.map(newname), {}) + style.map(newname, **default) + self.assertEqual(style.map(newname), default) + for key, value in default.items(): + self.assertEqual(style.map(newname, key), value) + + tests_gui = (StyleTest, ) if __name__ == "__main__": diff --git a/Lib/tkinter/ttk.py b/Lib/tkinter/ttk.py index c7c71cd5a559cf..968fd54dce1ee0 100644 --- a/Lib/tkinter/ttk.py +++ b/Lib/tkinter/ttk.py @@ -81,8 +81,6 @@ def _mapdict_values(items): # ['active selected', 'grey', 'focus', [1, 2, 3, 4]] opt_val = [] for *state, val in items: - # hacks for backward compatibility - state[0] # raise IndexError if empty if len(state) == 1: # if it is empty (something that evaluates to False), then # format it to Tcl code to denote the "normal" state @@ -243,19 +241,22 @@ def _script_from_settings(settings): def _list_from_statespec(stuple): """Construct a list from the given statespec tuple according to the accepted statespec accepted by _format_mapdict.""" - nval = [] - for val in stuple: - typename = getattr(val, 'typename', None) - if typename is None: - nval.append(val) - else: # this is a Tcl object + if isinstance(stuple, str): + return stuple + result = [] + it = iter(stuple) + for state, val in zip(it, it): + if hasattr(state, 'typename'): # this is a Tcl object + state = str(state).split() + elif isinstance(state, str): + state = state.split() + elif not isinstance(state, (tuple, list)): + state = (state,) + if hasattr(val, 'typename'): val = str(val) - if typename == 'StateSpec': - val = val.split() - nval.append(val) + result.append((*state, val)) - it = iter(nval) - return [_flatten(spec) for spec in zip(it, it)] + return result def _list_from_layouttuple(tk, ltuple): """Construct a list from the tuple returned by ttk::layout, this is @@ -395,13 +396,12 @@ def map(self, style, query_opt=None, **kw): or something else of your preference. A statespec is compound of one or more states and then a value.""" if query_opt is not None: - return _list_from_statespec(self.tk.splitlist( - self.tk.call(self._name, "map", style, '-%s' % query_opt))) + result = self.tk.call(self._name, "map", style, '-%s' % query_opt) + return _list_from_statespec(self.tk.splitlist(result)) - return _splitdict( - self.tk, - self.tk.call(self._name, "map", style, *_format_mapdict(kw)), - conv=_tclobj_to_py) + result = self.tk.call(self._name, "map", style, *_format_mapdict(kw)) + return {k: _list_from_statespec(self.tk.splitlist(v)) + for k, v in _splitdict(self.tk, result).items()} def lookup(self, style, option, state=None, default=None): diff --git a/Misc/NEWS.d/next/Library/2020-11-15-17-02-00.bpo-42328.bqpPlR.rst b/Misc/NEWS.d/next/Library/2020-11-15-17-02-00.bpo-42328.bqpPlR.rst new file mode 100644 index 00000000000000..7e6a176c889412 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2020-11-15-17-02-00.bpo-42328.bqpPlR.rst @@ -0,0 +1,4 @@ +Fixed :meth:`tkinter.ttk.Style.map`. The function accepts now the +representation of the default state as empty sequence (as returned by +``Style.map()``). The structure of the result is now the same on all platform +and does not depend on the value of ``wantobjects``. From 2019e4ff983dae8c17b616941b7a6b3a077278a6 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 23 Nov 2020 11:31:45 -0800 Subject: [PATCH 0736/1314] Descriptor HowTo: Improve the fidelity of the member object simulation (GH-23475) (GH-23479) --- Doc/howto/descriptor.rst | 57 ++++++++++++++++++++++++++++++++-------- 1 file changed, 46 insertions(+), 11 deletions(-) diff --git a/Doc/howto/descriptor.rst b/Doc/howto/descriptor.rst index 76987fda22b59d..8c6e90319a7f36 100644 --- a/Doc/howto/descriptor.rst +++ b/Doc/howto/descriptor.rst @@ -1079,6 +1079,8 @@ simulation where the actual C structure for slots is emulated by a private ``_slotvalues`` list. Reads and writes to that private structure are managed by member descriptors:: + null = object() + class Member: def __init__(self, name, clsname, offset): @@ -1091,20 +1093,28 @@ by member descriptors:: def __get__(self, obj, objtype=None): 'Emulate member_get() in Objects/descrobject.c' # Also see PyMember_GetOne() in Python/structmember.c - return obj._slotvalues[self.offset] + value = obj._slotvalues[self.offset] + if value is null: + raise AttributeError(self.name) + return value def __set__(self, obj, value): 'Emulate member_set() in Objects/descrobject.c' obj._slotvalues[self.offset] = value + def __delete__(self, obj): + 'Emulate member_delete() in Objects/descrobject.c' + value = obj._slotvalues[self.offset] + if value is null: + raise AttributeError(self.name) + obj._slotvalues[self.offset] = null + def __repr__(self): 'Emulate member_repr() in Objects/descrobject.c' return f'' The :meth:`type.__new__` method takes care of adding member objects to class -variables. The :meth:`object.__new__` method takes care of creating instances -that have slots instead of an instance dictionary. Here is a rough equivalent -in pure Python:: +variables:: class Type(type): 'Simulate how the type metaclass adds member objects for slots' @@ -1117,6 +1127,10 @@ in pure Python:: mapping[name] = Member(name, clsname, offset) return type.__new__(mcls, clsname, bases, mapping) +The :meth:`object.__new__` method takes care of creating instances that have +slots instead of an instance dictionary. Here is a rough simulation in pure +Python:: + class Object: 'Simulate how object.__new__() allocates memory for __slots__' @@ -1124,13 +1138,33 @@ in pure Python:: 'Emulate object_new() in Objects/typeobject.c' inst = super().__new__(cls) if hasattr(cls, 'slot_names'): - inst._slotvalues = [None] * len(cls.slot_names) + empty_slots = [null] * len(cls.slot_names) + object.__setattr__(inst, '_slotvalues', empty_slots) return inst + def __setattr__(self, name, value): + 'Emulate _PyObject_GenericSetAttrWithDict() Objects/object.c' + cls = type(self) + if hasattr(cls, 'slot_names') and name not in cls.slot_names: + raise AttributeError( + f'{type(self).__name__!r} object has no attribute {name!r}' + ) + super().__setattr__(name, value) + + def __delattr__(self, name): + 'Emulate _PyObject_GenericSetAttrWithDict() Objects/object.c' + cls = type(self) + if hasattr(cls, 'slot_names') and name not in cls.slot_names: + raise AttributeError( + f'{type(self).__name__!r} object has no attribute {name!r}' + ) + super().__delattr__(name) + To use the simulation in a real class, just inherit from :class:`Object` and set the :term:`metaclass` to :class:`Type`:: class H(Object, metaclass=Type): + 'Instance variables stored in slots' slot_names = ['x', 'y'] @@ -1143,11 +1177,11 @@ At this point, the metaclass has loaded member objects for *x* and *y*:: >>> import pprint >>> pprint.pp(dict(vars(H))) {'__module__': '__main__', + '__doc__': 'Instance variables stored in slots', 'slot_names': ['x', 'y'], '__init__': , 'x': , - 'y': , - '__doc__': None} + 'y': } When instances are created, they have a ``slot_values`` list where the attributes are stored:: @@ -1159,8 +1193,9 @@ attributes are stored:: >>> vars(h) {'_slotvalues': [55, 20]} -Unlike the real ``__slots__``, this simulation does have an instance -dictionary just to hold the ``_slotvalues`` array. So, unlike the real code, -this simulation doesn't block assignments to misspelled attributes:: +Misspelled or unassigned attributes will raise an exception:: - >>> h.xz = 30 # For actual __slots__ this would raise an AttributeError + >>> h.xz + Traceback (most recent call last): + ... + AttributeError: 'H' object has no attribute 'xz' From b6416052f7cc79e45d5cbcaca08e12e4bb0895fc Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 23 Nov 2020 16:11:13 -0800 Subject: [PATCH 0737/1314] Typo (GH-23482) (#23483) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit (cherry picked from commit 989af256161ea3728e1f787329e07e70e0901bc8) Co-authored-by: Jesús Cea Co-authored-by: Jesús Cea --- Doc/library/asyncio-task.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/asyncio-task.rst b/Doc/library/asyncio-task.rst index eb51c704cea394..c638f1263fdaa1 100644 --- a/Doc/library/asyncio-task.rst +++ b/Doc/library/asyncio-task.rst @@ -618,7 +618,7 @@ Running in Threads Asynchronously run function *func* in a separate thread. Any \*args and \*\*kwargs supplied for this function are directly passed - to *func*. Also, the current :class:`contextvars.Context` is propogated, + to *func*. Also, the current :class:`contextvars.Context` is propagated, allowing context variables from the event loop thread to be accessed in the separate thread. From 3266991e721286e942125350ca41e1403d8384d6 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 23 Nov 2020 16:26:31 -0800 Subject: [PATCH 0738/1314] bpo-41100: minor build installer fixes (GH-23480) (cherry picked from commit 936533ca0415c40dc64ccb5f8857720f32b3fcb4) Co-authored-by: Ned Deily --- Mac/BuildScript/build-installer.py | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/Mac/BuildScript/build-installer.py b/Mac/BuildScript/build-installer.py index 184add4c4f06c5..16816d1cf86a44 100755 --- a/Mac/BuildScript/build-installer.py +++ b/Mac/BuildScript/build-installer.py @@ -587,8 +587,8 @@ def checkEnvironment(): Check that we're running on a supported system. """ - if sys.version_info[0:2] < (2, 5): - fatal("This script must be run with Python 2.5 (or later)") + if sys.version_info[0:2] < (2, 7): + fatal("This script must be run with Python 2.7 (or later)") if platform.system() != 'Darwin': fatal("This script should be run on a macOS 10.5 (or later) system") @@ -656,9 +656,6 @@ def checkEnvironment(): base_path = base_path + ':' + OLD_DEVELOPER_TOOLS os.environ['PATH'] = base_path print("Setting default PATH: %s"%(os.environ['PATH'])) - # Ensure we have access to sphinx-build. - # You may have to create a link in /usr/bin for it. - runCommand('sphinx-build --version') def parseOptions(args=None): """ @@ -1618,8 +1615,17 @@ def buildDMG(): if os.path.exists(outdir): shutil.rmtree(outdir) + # We used to use the deployment target as the last characters of the + # installer file name. With the introduction of weaklinked installer + # variants, we may have two variants with the same file name, i.e. + # both ending in '10.9'. To avoid this, we now use the major/minor + # version numbers of the macOS version we are building on, i.e. + # '10.9' as before for 10.9+ variant, '11.0' for universal2 11.0-. + # it's not ideal but should cause the least disruption to packaging + # workflows. + build_system_version = '.'.join(platform.mac_ver()[0].split('.')[0:2]) imagepath = os.path.join(outdir, - 'python-%s-macosx%s'%(getFullVersion(),DEPTARGET)) + 'python-%s-macosx%s'%(getFullVersion(),build_system_version)) if INCLUDE_TIMESTAMP: imagepath = imagepath + '-%04d-%02d-%02d'%(time.localtime()[:3]) imagepath = imagepath + '.dmg' From 96d906b144e6e6aa96c5ffebecbcc5d38034bbda Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 23 Nov 2020 22:34:16 -0800 Subject: [PATCH 0739/1314] bpo-41100: in test_platform, ignore 10.16 (GH-23485) (GH-23486) (cherry picked from commit c0c23ea72b76b06b7db0d09415fa90bab8ded63a) Co-authored-by: Ned Deily --- Lib/test/test_platform.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Lib/test/test_platform.py b/Lib/test/test_platform.py index bd953b5d677ef6..a3b06feb6552ec 100644 --- a/Lib/test/test_platform.py +++ b/Lib/test/test_platform.py @@ -237,7 +237,10 @@ def test_mac_ver(self): # On Snow Leopard, sw_vers reports 10.6.0 as 10.6 if len_diff > 0: expect_list.extend(['0'] * len_diff) - self.assertEqual(result_list, expect_list) + # For compatibility with older binaries, macOS 11.x may report + # itself as '10.16' rather than '11.x.y'. + if result_list != ['10', '16']: + self.assertEqual(result_list, expect_list) # res[1] claims to contain # (version, dev_stage, non_release_version) From 15d42d7ec6ad4305ea20c7b98ab093bd33bc254c Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 24 Nov 2020 05:25:29 -0800 Subject: [PATCH 0740/1314] bpo-42212: Check if generated files are up-to-date in GitHub Actions (GH-23042) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit See https: //github.com/python/core-workflow/issues/380 Signed-off-by: Filipe Laíns (cherry picked from commit d20b7ed9c1fabac3fdebb7ec362fe4f022a54639) Co-authored-by: Filipe Laíns --- .github/workflows/build.yml | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index f66e042dac4998..deb0e67bedb902 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -47,6 +47,34 @@ jobs: # https://github.com/python/core-workflow/issues/373 git diff --name-only origin/$GITHUB_BASE_REF.. | grep -qvE '(\.rst$|^Doc|^Misc)' && echo '::set-output name=run_tests::true' || true fi + + check_generated_files: + name: 'Check if generated files are up to date' + runs-on: ubuntu-latest + needs: check_source + if: needs.check_source.outputs.run_tests == 'true' + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-python@v2 + - name: Install Dependencies + run: sudo ./.github/workflows/posix-deps-apt.sh + - name: Build CPython + run: | + ./configure --with-pydebug + make -j4 regen-all + - name: Check for changes + run: | + changes=$(git status --porcelain) + # Check for changes in regenerated files + if ! test -z "$changes" + then + echo "Generated files not up to date. Perhaps you forgot to run make regen-all ;)" + echo "$changes" + exit 1 + fi + - name: Check exported libpython symbols + run: make smelly + build_win32: name: 'Windows (x86)' runs-on: windows-latest From 88db37442238079a2eff4d142e8e94cfddb58e22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Langa?= Date: Tue, 24 Nov 2020 17:48:47 +0100 Subject: [PATCH 0741/1314] Python 3.9.1rc1 --- Include/patchlevel.h | 8 +- Lib/pydoc_data/topics.py | 173 +++- Misc/NEWS.d/3.9.1rc1.rst | 948 ++++++++++++++++++ .../2020-06-17-09-05-02.bpo-40998.sgqmg9.rst | 2 - .../2020-09-28-21-56-51.bpo-38249.uzMCaZ.rst | 2 - .../2020-11-13-15-04-53.bpo-41617.98_oaE.rst | 3 - .../2020-11-18-11-58-44.bpo-42398.Yt5wO8.rst | 4 - .../2020-10-09-22-50-46.bpo-41986.JUPE59.rst | 2 - .../2020-10-12-20-13-58.bpo-42015.X4H2_V.rst | 3 - .../2020-09-24-12-15-45.bpo-39934.YVHTCF.rst | 3 - .../2020-10-02-11-35-33.bpo-41894.ffmtOt.rst | 3 - .../2020-10-04-10-55-12.bpo-41909.BqHPcm.rst | 2 - .../2020-10-09-10-55-50.bpo-41979.ImXIk2.rst | 1 - .../2020-10-10-13-53-52.bpo-41993.YMzixQ.rst | 2 - .../2020-10-14-16-19-43.bpo-41984.SEtKMr.rst | 2 - .../2020-10-20-11-36-14.bpo-42057.BI-OoV.rst | 2 - .../2020-10-21-14-40-54.bpo-41910.CzBMit.rst | 1 - .../2020-10-23-02-43-24.bpo-42123.64gJWC.rst | 3 - .../2020-10-25-21-14-18.bpo-42150.b70u_T.rst | 2 - .../2020-10-27-18-32-49.bpo-41659.d4a-8o.rst | 3 - .../2020-10-27-21-34-05.bpo-42143.N6KXUO.rst | 2 - .../2020-10-30-22-16-30.bpo-42214.lXskM_.rst | 2 - .../2020-10-31-17-50-23.bpo-42218.Dp_Z3v.rst | 3 - .../2020-11-12-23-16-14.bpo-42332.fEQIdk.rst | 1 - .../2020-11-13-13-53-11.bpo-42296.DuGrLJ.rst | 4 - .../2020-11-16-17-57-09.bpo-42374.t7np1E.rst | 2 - .../2020-11-16-23-45-56.bpo-42381.G4AWxL.rst | 2 - .../2020-11-17-16-25-50.bpo-41686.hX77kL.rst | 4 - .../2020-01-22-05-14-53.bpo-39416.uYjhEm.rst | 1 - .../2020-02-24-09-02-05.bpo-39693.QXw0Fm.rst | 1 - .../2020-09-08-16-57-09.bpo-41726.g0UXrn.rst | 1 - .../2020-09-12-17-37-13.bpo-35293._cOwPD.rst | 1 - .../2020-09-24-15-35-13.bpo-41774.5IqdGP.rst | 2 - .../2020-10-10-01-36-37.bpo-41805.l-CGv5.rst | 3 - .../2020-10-21-02-21-14.bpo-42010.76vJ0u.rst | 4 - .../2020-10-28-21-39-45.bpo-42061._x-0sg.rst | 1 - .../2020-11-15-13-46-31.bpo-42153.KjBhx3.rst | 1 - .../2020-04-22-09-37-40.bpo-38439.ieXL-c.rst | 2 - .../2020-06-16-12-16-13.bpo-40511.XkihpM.rst | 3 - .../2020-09-22-00-45-40.bpo-40181.hhQi3z.rst | 2 - .../2020-09-22-11-13-45.bpo-35764.VoNa8y.rst | 1 - .../2020-09-24-14-31-16.bpo-41775.sB8Vre.rst | 1 - .../2020-10-24-21-27-37.bpo-33987.fIh9JL.rst | 3 - .../2020-11-20-01-30-27.bpo-42415.CyD-va.rst | 1 - .../2020-11-21-17-21-21.bpo-42426.kNnPoC.rst | 1 - .../2020-01-19-18-40-26.bpo-27321.8e6SpM.rst | 2 - .../2020-04-03-16-13-59.bpo-40105.hfM2c0.rst | 2 - .../2020-05-04-12-16-00.bpo-40492.ONk9Na.rst | 3 - .../2020-05-08-21-30-54.bpo-40550.i7GWkb.rst | 1 - .../2020-05-14-16-01-34.bpo-40592.Cmk855.rst | 1 - .../2020-07-08-09-45-00.bpo-16936.z8o8Pn.rst | 1 - .../2020-07-28-12-08-58.bpo-41316.bSCbK4.rst | 1 - .../2020-09-19-23-14-54.bpo-41815.RNpuX3.rst | 2 - .../2020-09-22-00-23-30.bpo-41817.bnh-VG.rst | 1 - .../2020-09-22-11-07-50.bpo-41831.k-Eop_.rst | 3 - .../2020-09-23-23-17-59.bpo-41840.QRFr4L.rst | 3 - .../2020-10-01-10-50-12.bpo-41900.Cho7oh.rst | 2 - .../2020-10-08-18-22-28.bpo-41976.Svm0wb.rst | 3 - .../2020-10-17-07-52-53.bpo-41966.gwEQRZ.rst | 2 - .../2020-10-17-23-17-18.bpo-42065.85BsRA.rst | 3 - .../2020-10-19-14-02-09.bpo-41491.d1BUWH.rst | 1 - .../2020-10-21-23-45-02.bpo-41052.3N7J2J.rst | 2 - .../2020-10-23-19-20-14.bpo-42103.C5obK2.rst | 3 - .../2020-10-24-04-02-36.bpo-42140.miLqvb.rst | 1 - .../2020-10-25-19-25-02.bpo-42146.6A8uvS.rst | 2 - .../2020-10-29-11-17-35.bpo-42183.50ZcIi.rst | 4 - .../2020-10-31-13-28-36.bpo-29566.6aDbty.rst | 1 - .../2020-11-01-15-07-20.bpo-41754.DraSZh.rst | 1 - .../2020-11-02-01-31-15.bpo-42233.YxRj-h.rst | 3 - .../2020-11-02-14-10-48.bpo-35455.Q1xTIo.rst | 3 - .../2020-11-03-09-22-56.bpo-42249.vfNO2u.rst | 1 - .../2020-11-10-14-27-49.bpo-42237.F363jO.rst | 1 - .../2020-11-10-15-40-56.bpo-42014.ShM37l.rst | 1 - .../2020-11-13-18-53-50.bpo-42350.rsql7V.rst | 3 - .../2020-11-15-15-23-34.bpo-42345.hiIR7x.rst | 2 - .../2020-11-15-17-02-00.bpo-42328.bqpPlR.rst | 4 - .../2020-05-28-06-06-47.bpo-40791.QGZClX.rst | 1 - .../2020-10-19-10-56-27.bpo-42051.EU_B7u.rst | 3 - .../2020-10-23-19-19-30.bpo-42103.cILT66.rst | 2 - .../2020-08-03-13-44-37.bpo-41306.VDoWXI.rst | 1 - .../2020-08-25-19-25-36.bpo-41602.Z64s0I.rst | 1 - .../2020-09-18-16-14-03.bpo-41561.uPnwrW.rst | 1 - .../2020-10-05-09-37-43.bpo-41939.P4OlbA.rst | 3 - .../2020-10-05-17-43-46.bpo-41944.rf1dYb.rst | 1 - .../2020-10-08-14-00-17.bpo-41970.aZ8QFf.rst | 2 - .../2020-10-12-00-11-47.bpo-41739.wSCc4K.rst | 2 - .../2020-11-13-21-51-34.bpo-40754.Ekoxkg.rst | 1 - .../2020-05-30-02-46-43.bpo-38324.476M-5.rst | 1 - .../2020-08-26-09-35-06.bpo-41557.vt00cQ.rst | 1 - .../2020-09-11-17-59-33.bpo-41744.e_ugDQ.rst | 1 - .../2020-10-20-13-19-42.bpo-38439.eMLi-t.rst | 1 - .../2020-11-16-22-41-02.bpo-42120.9scgko.rst | 1 - .../2020-08-26-09-31-37.bpo-41557.mcQ75z.rst | 1 - .../2020-10-19-12-25-19.bpo-41471.gwA7un.rst | 1 - .../2020-10-23-10-26-53.bpo-38443.vu64tl.rst | 2 - .../2020-11-01-16-40-23.bpo-41100.BApztP.rst | 8 - .../2020-11-15-16-43-45.bpo-41116.oCkbrF.rst | 1 - README.rst | 4 +- 98 files changed, 1082 insertions(+), 239 deletions(-) create mode 100644 Misc/NEWS.d/3.9.1rc1.rst delete mode 100644 Misc/NEWS.d/next/Build/2020-06-17-09-05-02.bpo-40998.sgqmg9.rst delete mode 100644 Misc/NEWS.d/next/Build/2020-09-28-21-56-51.bpo-38249.uzMCaZ.rst delete mode 100644 Misc/NEWS.d/next/Build/2020-11-13-15-04-53.bpo-41617.98_oaE.rst delete mode 100644 Misc/NEWS.d/next/Build/2020-11-18-11-58-44.bpo-42398.Yt5wO8.rst delete mode 100644 Misc/NEWS.d/next/C API/2020-10-09-22-50-46.bpo-41986.JUPE59.rst delete mode 100644 Misc/NEWS.d/next/C API/2020-10-12-20-13-58.bpo-42015.X4H2_V.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2020-09-24-12-15-45.bpo-39934.YVHTCF.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2020-10-02-11-35-33.bpo-41894.ffmtOt.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2020-10-04-10-55-12.bpo-41909.BqHPcm.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2020-10-09-10-55-50.bpo-41979.ImXIk2.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2020-10-10-13-53-52.bpo-41993.YMzixQ.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2020-10-14-16-19-43.bpo-41984.SEtKMr.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2020-10-20-11-36-14.bpo-42057.BI-OoV.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2020-10-21-14-40-54.bpo-41910.CzBMit.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2020-10-23-02-43-24.bpo-42123.64gJWC.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2020-10-25-21-14-18.bpo-42150.b70u_T.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2020-10-27-18-32-49.bpo-41659.d4a-8o.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2020-10-27-21-34-05.bpo-42143.N6KXUO.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2020-10-30-22-16-30.bpo-42214.lXskM_.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2020-10-31-17-50-23.bpo-42218.Dp_Z3v.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2020-11-12-23-16-14.bpo-42332.fEQIdk.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2020-11-13-13-53-11.bpo-42296.DuGrLJ.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2020-11-16-17-57-09.bpo-42374.t7np1E.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2020-11-16-23-45-56.bpo-42381.G4AWxL.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2020-11-17-16-25-50.bpo-41686.hX77kL.rst delete mode 100644 Misc/NEWS.d/next/Documentation/2020-01-22-05-14-53.bpo-39416.uYjhEm.rst delete mode 100644 Misc/NEWS.d/next/Documentation/2020-02-24-09-02-05.bpo-39693.QXw0Fm.rst delete mode 100644 Misc/NEWS.d/next/Documentation/2020-09-08-16-57-09.bpo-41726.g0UXrn.rst delete mode 100644 Misc/NEWS.d/next/Documentation/2020-09-12-17-37-13.bpo-35293._cOwPD.rst delete mode 100644 Misc/NEWS.d/next/Documentation/2020-09-24-15-35-13.bpo-41774.5IqdGP.rst delete mode 100644 Misc/NEWS.d/next/Documentation/2020-10-10-01-36-37.bpo-41805.l-CGv5.rst delete mode 100644 Misc/NEWS.d/next/Documentation/2020-10-21-02-21-14.bpo-42010.76vJ0u.rst delete mode 100644 Misc/NEWS.d/next/Documentation/2020-10-28-21-39-45.bpo-42061._x-0sg.rst delete mode 100644 Misc/NEWS.d/next/Documentation/2020-11-15-13-46-31.bpo-42153.KjBhx3.rst delete mode 100644 Misc/NEWS.d/next/IDLE/2020-04-22-09-37-40.bpo-38439.ieXL-c.rst delete mode 100644 Misc/NEWS.d/next/IDLE/2020-06-16-12-16-13.bpo-40511.XkihpM.rst delete mode 100644 Misc/NEWS.d/next/IDLE/2020-09-22-00-45-40.bpo-40181.hhQi3z.rst delete mode 100644 Misc/NEWS.d/next/IDLE/2020-09-22-11-13-45.bpo-35764.VoNa8y.rst delete mode 100644 Misc/NEWS.d/next/IDLE/2020-09-24-14-31-16.bpo-41775.sB8Vre.rst delete mode 100644 Misc/NEWS.d/next/IDLE/2020-10-24-21-27-37.bpo-33987.fIh9JL.rst delete mode 100644 Misc/NEWS.d/next/IDLE/2020-11-20-01-30-27.bpo-42415.CyD-va.rst delete mode 100644 Misc/NEWS.d/next/IDLE/2020-11-21-17-21-21.bpo-42426.kNnPoC.rst delete mode 100644 Misc/NEWS.d/next/Library/2020-01-19-18-40-26.bpo-27321.8e6SpM.rst delete mode 100644 Misc/NEWS.d/next/Library/2020-04-03-16-13-59.bpo-40105.hfM2c0.rst delete mode 100644 Misc/NEWS.d/next/Library/2020-05-04-12-16-00.bpo-40492.ONk9Na.rst delete mode 100644 Misc/NEWS.d/next/Library/2020-05-08-21-30-54.bpo-40550.i7GWkb.rst delete mode 100644 Misc/NEWS.d/next/Library/2020-05-14-16-01-34.bpo-40592.Cmk855.rst delete mode 100644 Misc/NEWS.d/next/Library/2020-07-08-09-45-00.bpo-16936.z8o8Pn.rst delete mode 100644 Misc/NEWS.d/next/Library/2020-07-28-12-08-58.bpo-41316.bSCbK4.rst delete mode 100644 Misc/NEWS.d/next/Library/2020-09-19-23-14-54.bpo-41815.RNpuX3.rst delete mode 100644 Misc/NEWS.d/next/Library/2020-09-22-00-23-30.bpo-41817.bnh-VG.rst delete mode 100644 Misc/NEWS.d/next/Library/2020-09-22-11-07-50.bpo-41831.k-Eop_.rst delete mode 100644 Misc/NEWS.d/next/Library/2020-09-23-23-17-59.bpo-41840.QRFr4L.rst delete mode 100644 Misc/NEWS.d/next/Library/2020-10-01-10-50-12.bpo-41900.Cho7oh.rst delete mode 100644 Misc/NEWS.d/next/Library/2020-10-08-18-22-28.bpo-41976.Svm0wb.rst delete mode 100644 Misc/NEWS.d/next/Library/2020-10-17-07-52-53.bpo-41966.gwEQRZ.rst delete mode 100644 Misc/NEWS.d/next/Library/2020-10-17-23-17-18.bpo-42065.85BsRA.rst delete mode 100644 Misc/NEWS.d/next/Library/2020-10-19-14-02-09.bpo-41491.d1BUWH.rst delete mode 100644 Misc/NEWS.d/next/Library/2020-10-21-23-45-02.bpo-41052.3N7J2J.rst delete mode 100644 Misc/NEWS.d/next/Library/2020-10-23-19-20-14.bpo-42103.C5obK2.rst delete mode 100644 Misc/NEWS.d/next/Library/2020-10-24-04-02-36.bpo-42140.miLqvb.rst delete mode 100644 Misc/NEWS.d/next/Library/2020-10-25-19-25-02.bpo-42146.6A8uvS.rst delete mode 100644 Misc/NEWS.d/next/Library/2020-10-29-11-17-35.bpo-42183.50ZcIi.rst delete mode 100644 Misc/NEWS.d/next/Library/2020-10-31-13-28-36.bpo-29566.6aDbty.rst delete mode 100644 Misc/NEWS.d/next/Library/2020-11-01-15-07-20.bpo-41754.DraSZh.rst delete mode 100644 Misc/NEWS.d/next/Library/2020-11-02-01-31-15.bpo-42233.YxRj-h.rst delete mode 100644 Misc/NEWS.d/next/Library/2020-11-02-14-10-48.bpo-35455.Q1xTIo.rst delete mode 100644 Misc/NEWS.d/next/Library/2020-11-03-09-22-56.bpo-42249.vfNO2u.rst delete mode 100644 Misc/NEWS.d/next/Library/2020-11-10-14-27-49.bpo-42237.F363jO.rst delete mode 100644 Misc/NEWS.d/next/Library/2020-11-10-15-40-56.bpo-42014.ShM37l.rst delete mode 100644 Misc/NEWS.d/next/Library/2020-11-13-18-53-50.bpo-42350.rsql7V.rst delete mode 100644 Misc/NEWS.d/next/Library/2020-11-15-15-23-34.bpo-42345.hiIR7x.rst delete mode 100644 Misc/NEWS.d/next/Library/2020-11-15-17-02-00.bpo-42328.bqpPlR.rst delete mode 100644 Misc/NEWS.d/next/Security/2020-05-28-06-06-47.bpo-40791.QGZClX.rst delete mode 100644 Misc/NEWS.d/next/Security/2020-10-19-10-56-27.bpo-42051.EU_B7u.rst delete mode 100644 Misc/NEWS.d/next/Security/2020-10-23-19-19-30.bpo-42103.cILT66.rst delete mode 100644 Misc/NEWS.d/next/Tests/2020-08-03-13-44-37.bpo-41306.VDoWXI.rst delete mode 100644 Misc/NEWS.d/next/Tests/2020-08-25-19-25-36.bpo-41602.Z64s0I.rst delete mode 100644 Misc/NEWS.d/next/Tests/2020-09-18-16-14-03.bpo-41561.uPnwrW.rst delete mode 100644 Misc/NEWS.d/next/Tests/2020-10-05-09-37-43.bpo-41939.P4OlbA.rst delete mode 100644 Misc/NEWS.d/next/Tests/2020-10-05-17-43-46.bpo-41944.rf1dYb.rst delete mode 100644 Misc/NEWS.d/next/Tests/2020-10-08-14-00-17.bpo-41970.aZ8QFf.rst delete mode 100644 Misc/NEWS.d/next/Tests/2020-10-12-00-11-47.bpo-41739.wSCc4K.rst delete mode 100644 Misc/NEWS.d/next/Tests/2020-11-13-21-51-34.bpo-40754.Ekoxkg.rst delete mode 100644 Misc/NEWS.d/next/Windows/2020-05-30-02-46-43.bpo-38324.476M-5.rst delete mode 100644 Misc/NEWS.d/next/Windows/2020-08-26-09-35-06.bpo-41557.vt00cQ.rst delete mode 100644 Misc/NEWS.d/next/Windows/2020-09-11-17-59-33.bpo-41744.e_ugDQ.rst delete mode 100644 Misc/NEWS.d/next/Windows/2020-10-20-13-19-42.bpo-38439.eMLi-t.rst delete mode 100644 Misc/NEWS.d/next/Windows/2020-11-16-22-41-02.bpo-42120.9scgko.rst delete mode 100644 Misc/NEWS.d/next/macOS/2020-08-26-09-31-37.bpo-41557.mcQ75z.rst delete mode 100644 Misc/NEWS.d/next/macOS/2020-10-19-12-25-19.bpo-41471.gwA7un.rst delete mode 100644 Misc/NEWS.d/next/macOS/2020-10-23-10-26-53.bpo-38443.vu64tl.rst delete mode 100644 Misc/NEWS.d/next/macOS/2020-11-01-16-40-23.bpo-41100.BApztP.rst delete mode 100644 Misc/NEWS.d/next/macOS/2020-11-15-16-43-45.bpo-41116.oCkbrF.rst diff --git a/Include/patchlevel.h b/Include/patchlevel.h index 2243329744ced0..1a51847c5541d9 100644 --- a/Include/patchlevel.h +++ b/Include/patchlevel.h @@ -18,12 +18,12 @@ /*--start constants--*/ #define PY_MAJOR_VERSION 3 #define PY_MINOR_VERSION 9 -#define PY_MICRO_VERSION 0 -#define PY_RELEASE_LEVEL PY_RELEASE_LEVEL_FINAL -#define PY_RELEASE_SERIAL 0 +#define PY_MICRO_VERSION 1 +#define PY_RELEASE_LEVEL PY_RELEASE_LEVEL_GAMMA +#define PY_RELEASE_SERIAL 1 /* Version as a string */ -#define PY_VERSION "3.9.0+" +#define PY_VERSION "3.9.1rc1" /*--end constants--*/ /* Version as a single 4-byte hex number, e.g. 0x010502B2 == 1.5.2b2. diff --git a/Lib/pydoc_data/topics.py b/Lib/pydoc_data/topics.py index 40b4579f4c7a45..6411c8cd6be757 100644 --- a/Lib/pydoc_data/topics.py +++ b/Lib/pydoc_data/topics.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -# Autogenerated by Sphinx on Sun Oct 4 19:26:28 2020 +# Autogenerated by Sphinx on Tue Nov 24 17:42:56 2020 topics = {'assert': 'The "assert" statement\n' '**********************\n' '\n' @@ -700,6 +700,11 @@ 'syntax or\n' ' built-in functions. See Special method lookup.\n' '\n' + ' For certain sensitive attribute accesses, raises an ' + 'auditing event\n' + ' "object.__getattr__" with arguments "obj" and ' + '"name".\n' + '\n' 'object.__setattr__(self, name, value)\n' '\n' ' Called when an attribute assignment is attempted. ' @@ -716,6 +721,11 @@ 'for example,\n' ' "object.__setattr__(self, name, value)".\n' '\n' + ' For certain sensitive attribute assignments, raises ' + 'an auditing\n' + ' event "object.__setattr__" with arguments "obj", ' + '"name", "value".\n' + '\n' 'object.__delattr__(self, name)\n' '\n' ' Like "__setattr__()" but for attribute deletion ' @@ -724,6 +734,11 @@ 'obj.name" is\n' ' meaningful for the object.\n' '\n' + ' For certain sensitive attribute deletions, raises an ' + 'auditing event\n' + ' "object.__delattr__" with arguments "obj" and ' + '"name".\n' + '\n' 'object.__dir__(self)\n' '\n' ' Called when "dir()" is called on the object. A ' @@ -1464,8 +1479,8 @@ '\n' ' Called when the instance is “called†as a function; if ' 'this method\n' - ' is defined, "x(arg1, arg2, ...)" is a shorthand for\n' - ' "x.__call__(arg1, arg2, ...)".\n', + ' is defined, "x(arg1, arg2, ...)" roughly translates to\n' + ' "type(x).__call__(x, arg1, ...)".\n', 'calls': 'Calls\n' '*****\n' '\n' @@ -3461,16 +3476,21 @@ ' on the value to determine if the result is true or ' 'false.\n' '\n' - ' By default, "__ne__()" delegates to "__eq__()" and ' - 'inverts the\n' - ' result unless it is "NotImplemented". There are no ' - 'other implied\n' - ' relationships among the comparison operators, for ' - 'example, the\n' - ' truth of "(x` previously did not show the parameterized types in the +``GenericAlias``. They have now been changed to do so. + +.. + +.. bpo: 41754 +.. date: 2020-11-01-15-07-20 +.. nonce: DraSZh +.. section: Library + +webbrowser: Ignore *NotADirectoryError* when calling ``xdg-settings``. + +.. + +.. bpo: 29566 +.. date: 2020-10-31-13-28-36 +.. nonce: 6aDbty +.. section: Library + +``binhex.binhex()`` consisently writes macOS 9 line endings. + +.. + +.. bpo: 42183 +.. date: 2020-10-29-11-17-35 +.. nonce: 50ZcIi +.. section: Library + +Fix a stack overflow error for asyncio Task or Future repr(). + +The overflow occurs under some circumstances when a Task or Future +recursively returns itself. + +.. + +.. bpo: 42146 +.. date: 2020-10-25-19-25-02 +.. nonce: 6A8uvS +.. section: Library + +Fix memory leak in :func:`subprocess.Popen` in case an uid (gid) specified +in `user` (`group`, `extra_groups`) overflows `uid_t` (`gid_t`). + +.. + +.. bpo: 42140 +.. date: 2020-10-24-04-02-36 +.. nonce: miLqvb +.. section: Library + +Improve asyncio.wait function to create the futures set just one time. + +.. + +.. bpo: 42103 +.. date: 2020-10-23-19-20-14 +.. nonce: C5obK2 +.. section: Library + +:exc:`~plistlib.InvalidFileException` and :exc:`RecursionError` are now the +only errors caused by loading malformed binary Plist file (previously +ValueError and TypeError could be raised in some specific cases). + +.. + +.. bpo: 41052 +.. date: 2020-10-21-23-45-02 +.. nonce: 3N7J2J +.. section: Library + +Pickling heap types implemented in C with protocols 0 and 1 raises now an +error instead of producing incorrect data. + +.. + +.. bpo: 41491 +.. date: 2020-10-19-14-02-09 +.. nonce: d1BUWH +.. section: Library + +plistlib: fix parsing XML plists with hexadecimal integer values + +.. + +.. bpo: 42065 +.. date: 2020-10-17-23-17-18 +.. nonce: 85BsRA +.. section: Library + +Fix an incorrectly formatted error from :meth:`_codecs.charmap_decode` when +called with a mapped value outside the range of valid Unicode code points. +PR by Max Bernstein. + +.. + +.. bpo: 41966 +.. date: 2020-10-17-07-52-53 +.. nonce: gwEQRZ +.. section: Library + +Fix pickling pure Python :class:`datetime.time` subclasses. Patch by Dean +Inwood. + +.. + +.. bpo: 41976 +.. date: 2020-10-08-18-22-28 +.. nonce: Svm0wb +.. section: Library + +Fixed a bug that was causing :func:`ctypes.util.find_library` to return +``None`` when triying to locate a library in an environment when gcc>=9 is +available and ``ldconfig`` is not. Patch by Pablo Galindo + +.. + +.. bpo: 41900 +.. date: 2020-10-01-10-50-12 +.. nonce: Cho7oh +.. section: Library + +C14N 2.0 serialisation in xml.etree.ElementTree failed for unprefixed +attributes when a default namespace was defined. + +.. + +.. bpo: 41840 +.. date: 2020-09-23-23-17-59 +.. nonce: QRFr4L +.. section: Library + +Fix a bug in the :mod:`symtable` module that was causing module-scope global +variables to not be reported as both local and global. Patch by Pablo +Galindo. + +.. + +.. bpo: 41831 +.. date: 2020-09-22-11-07-50 +.. nonce: k-Eop_ +.. section: Library + +``str()`` for the ``type`` attribute of the ``tkinter.Event`` object always +returns now the numeric code returned by Tk instead of the name of the event +type. + +.. + +.. bpo: 41817 +.. date: 2020-09-22-00-23-30 +.. nonce: bnh-VG +.. section: Library + +fix `tkinter.EventType` Enum so all members are strings, and none are tuples + +.. + +.. bpo: 41815 +.. date: 2020-09-19-23-14-54 +.. nonce: RNpuX3 +.. section: Library + +Fix SQLite3 segfault when backing up closed database. Patch contributed by +Peter David McCormick. + +.. + +.. bpo: 41316 +.. date: 2020-07-28-12-08-58 +.. nonce: bSCbK4 +.. section: Library + +Fix the :mod:`tarfile` module to write only basename of TAR file to GZIP +compression header. + +.. + +.. bpo: 16936 +.. date: 2020-07-08-09-45-00 +.. nonce: z8o8Pn +.. section: Library + +Allow ``ctypes.wintypes`` to be imported on non-Windows systems. + +.. + +.. bpo: 40592 +.. date: 2020-05-14-16-01-34 +.. nonce: Cmk855 +.. section: Library + +:func:`shutil.which` now ignores empty entries in :envvar:`PATHEXT` instead +of treating them as a match. + +.. + +.. bpo: 40550 +.. date: 2020-05-08-21-30-54 +.. nonce: i7GWkb +.. section: Library + +Fix time-of-check/time-of-action issue in subprocess.Popen.send_signal. + +.. + +.. bpo: 40492 +.. date: 2020-05-04-12-16-00 +.. nonce: ONk9Na +.. section: Library + +Fix ``--outfile`` for :mod:`cProfile` / :mod:`profile` not writing the +output file in the original directory when the program being profiled +changes the working directory. PR by Anthony Sottile. + +.. + +.. bpo: 40105 +.. date: 2020-04-03-16-13-59 +.. nonce: hfM2c0 +.. section: Library + +ZipFile truncates files to avoid corruption when a shorter comment is +provided in append ("a") mode. Patch by Jan Mazur. + +.. + +.. bpo: 27321 +.. date: 2020-01-19-18-40-26 +.. nonce: 8e6SpM +.. section: Library + +Fixed KeyError exception when flattening an email to a string attempts to +replace a non-existent Content-Transfer-Encoding header. + +.. + +.. bpo: 42153 +.. date: 2020-11-15-13-46-31 +.. nonce: KjBhx3 +.. section: Documentation + +Fix the URL for the IMAP protocol documents. + +.. + +.. bpo: 42061 +.. date: 2020-10-28-21-39-45 +.. nonce: _x-0sg +.. section: Documentation + +Document __format__ functionality for IP addresses. + +.. + +.. bpo: 42010 +.. date: 2020-10-21-02-21-14 +.. nonce: 76vJ0u +.. section: Documentation + +Clarify that subscription expressions are also valid for certain +:term:`classes ` and :term:`types ` in the standard library, +and for user-defined classes and types if the classmethod +:meth:`__class_getitem__` is provided. + +.. + +.. bpo: 41805 +.. date: 2020-10-10-01-36-37 +.. nonce: l-CGv5 +.. section: Documentation + +Documented :ref:`generic alias type ` and +:data:`types.GenericAlias`. Also added an entry in glossary for +:term:`generic types `. + +.. + +.. bpo: 41774 +.. date: 2020-09-24-15-35-13 +.. nonce: 5IqdGP +.. section: Documentation + +In Programming FAQ "Sequences (Tuples/Lists)" section, add "How do you +remove multiple items from a list". + +.. + +.. bpo: 35293 +.. date: 2020-09-12-17-37-13 +.. nonce: _cOwPD +.. section: Documentation + +Fix RemovedInSphinx40Warning when building the documentation. Patch by +Dong-hee Na. + +.. + +.. bpo: 41726 +.. date: 2020-09-08-16-57-09 +.. nonce: g0UXrn +.. section: Documentation + +Update the refcounts info of ``PyType_FromModuleAndSpec``. + +.. + +.. bpo: 39693 +.. date: 2020-02-24-09-02-05 +.. nonce: QXw0Fm +.. section: Documentation + +Fix tarfile's extractfile documentation + +.. + +.. bpo: 39416 +.. date: 2020-01-22-05-14-53 +.. nonce: uYjhEm +.. section: Documentation + +Document some restrictions on the default string representations of numeric +classes. + +.. + +.. bpo: 40754 +.. date: 2020-11-13-21-51-34 +.. nonce: Ekoxkg +.. section: Tests + +Include ``_testinternalcapi`` module in Windows installer for test suite + +.. + +.. bpo: 41739 +.. date: 2020-10-12-00-11-47 +.. nonce: wSCc4K +.. section: Tests + +Fix test_logging.test_race_between_set_target_and_flush(): the test now +waits until all threads complete to avoid leaking running threads. + +.. + +.. bpo: 41970 +.. date: 2020-10-08-14-00-17 +.. nonce: aZ8QFf +.. section: Tests + +Avoid a test failure in ``test_lib2to3`` if the module has already imported +at the time the test executes. Patch by Pablo Galindo. + +.. + +.. bpo: 41944 +.. date: 2020-10-05-17-43-46 +.. nonce: rf1dYb +.. section: Tests + +Tests for CJK codecs no longer call ``eval()`` on content received via HTTP. + +.. + +.. bpo: 41939 +.. date: 2020-10-05-09-37-43 +.. nonce: P4OlbA +.. section: Tests + +Fix test_site.test_license_exists_at_url(): call +``urllib.request.urlcleanup()`` to reset the global +``urllib.request._opener``. Patch by Victor Stinner. + +.. + +.. bpo: 41561 +.. date: 2020-09-18-16-14-03 +.. nonce: uPnwrW +.. section: Tests + +test_ssl: skip test_min_max_version_mismatch when TLS 1.0 is not available + +.. + +.. bpo: 41602 +.. date: 2020-08-25-19-25-36 +.. nonce: Z64s0I +.. section: Tests + +Add tests for SIGINT handling in the runpy module. + +.. + +.. bpo: 41306 +.. date: 2020-08-03-13-44-37 +.. nonce: VDoWXI +.. section: Tests + +Fixed a failure in ``test_tk.test_widgets.ScaleTest`` happening when +executing the test with Tk 8.6.10. + +.. + +.. bpo: 42398 +.. date: 2020-11-18-11-58-44 +.. nonce: Yt5wO8 +.. section: Build + +Fix a race condition in "make regen-all" when make -jN option is used to run +jobs in parallel. The clinic.py script now only use atomic write to write +files. Moveover, generated files are now left unchanged if the content does +not change, to not change the file modification time. + +.. + +.. bpo: 41617 +.. date: 2020-11-13-15-04-53 +.. nonce: 98_oaE +.. section: Build + +Fix building ``pycore_bitutils.h`` internal header on old clang version +without ``__builtin_bswap16()`` (ex: Xcode 4.6.3 on Mac OS X 10.7). Patch by +Joshua Root and Victor Stinner. + +.. + +.. bpo: 38249 +.. date: 2020-09-28-21-56-51 +.. nonce: uzMCaZ +.. section: Build + +Update :c:macro:`Py_UNREACHABLE` to use __builtin_unreachable() if only the +compiler is able to use it. Patch by Dong-hee Na. + +.. + +.. bpo: 40998 +.. date: 2020-06-17-09-05-02 +.. nonce: sgqmg9 +.. section: Build + +Addressed three compiler warnings found by undefined behavior sanitizer +(ubsan). + +.. + +.. bpo: 42120 +.. date: 2020-11-16-22-41-02 +.. nonce: 9scgko +.. section: Windows + +Remove macro definition of ``copysign`` (to ``_copysign``) in headers. + +.. + +.. bpo: 38439 +.. date: 2020-10-20-13-19-42 +.. nonce: eMLi-t +.. section: Windows + +Updates the icons for IDLE in the Windows Store package. + +.. + +.. bpo: 41744 +.. date: 2020-09-11-17-59-33 +.. nonce: e_ugDQ +.. section: Windows + +Fixes automatic import of props file when using the Nuget package. + +.. + +.. bpo: 41557 +.. date: 2020-08-26-09-35-06 +.. nonce: vt00cQ +.. section: Windows + +Update Windows installer to use SQLite 3.33.0. + +.. + +.. bpo: 38324 +.. date: 2020-05-30-02-46-43 +.. nonce: 476M-5 +.. section: Windows + +Avoid Unicode errors when accessing certain locale data on Windows. + +.. + +.. bpo: 41116 +.. date: 2020-11-15-16-43-45 +.. nonce: oCkbrF +.. section: macOS + +Ensure distutils.unixxcompiler.find_library_file can find system provided +libraries on macOS 11. + +.. + +.. bpo: 41100 +.. date: 2020-11-01-16-40-23 +.. nonce: BApztP +.. section: macOS + +Add support for macOS 11 and Apple Silicon systems. + +It is now possible to build "Universal 2" binaries using +"--enable-universalsdk --with-universal-archs=universal2". + +Binaries build on later macOS versions can be deployed back to older +versions (tested up to macOS 10.9), when using the correct deployment +target. This is tested using Xcode 11 and later. + +.. + +.. bpo: 38443 +.. date: 2020-10-23-10-26-53 +.. nonce: vu64tl +.. section: macOS + +The ``--enable-universalsdk`` and ``--with-universal-archs`` options for the +configure script now check that the specified architectures can be used. + +.. + +.. bpo: 41471 +.. date: 2020-10-19-12-25-19 +.. nonce: gwA7un +.. section: macOS + +Ignore invalid prefix lengths in system proxy excludes. + +.. + +.. bpo: 41557 +.. date: 2020-08-26-09-31-37 +.. nonce: mcQ75z +.. section: macOS + +Update macOS installer to use SQLite 3.33.0. + +.. + +.. bpo: 42426 +.. date: 2020-11-21-17-21-21 +.. nonce: kNnPoC +.. section: IDLE + +Fix reporting offset of the RE error in searchengine. + +.. + +.. bpo: 42415 +.. date: 2020-11-20-01-30-27 +.. nonce: CyD-va +.. section: IDLE + +Get docstrings for IDLE calltips more often by using inspect.getdoc. + +.. + +.. bpo: 33987 +.. date: 2020-10-24-21-27-37 +.. nonce: fIh9JL +.. section: IDLE + +Mostly finish using ttk widgets, mainly for editor, settings, and searches. +Some patches by Mark Roseman. + +.. + +.. bpo: 41775 +.. date: 2020-09-24-14-31-16 +.. nonce: sB8Vre +.. section: IDLE + +Use 'IDLE Shell' as shell title + +.. + +.. bpo: 35764 +.. date: 2020-09-22-11-13-45 +.. nonce: VoNa8y +.. section: IDLE + +Rewrite the Calltips doc section. + +.. + +.. bpo: 40181 +.. date: 2020-09-22-00-45-40 +.. nonce: hhQi3z +.. section: IDLE + +In calltips, stop reminding that '/' marks the end of positional-only +arguments. + +.. + +.. bpo: 40511 +.. date: 2020-06-16-12-16-13 +.. nonce: XkihpM +.. section: IDLE + +Typing opening and closing parentheses inside the parentheses of a function +call will no longer cause unnecessary "flashing" off and on of an existing +open call-tip, e.g. when typed in a string literal. + +.. + +.. bpo: 38439 +.. date: 2020-04-22-09-37-40 +.. nonce: ieXL-c +.. section: IDLE + +Add a 256×256 pixel IDLE icon to the Windows .ico file. Created by Andrew +Clover. Remove the low-color gif variations from the .ico file. + +.. + +.. bpo: 42015 +.. date: 2020-10-12-20-13-58 +.. nonce: X4H2_V +.. section: C API + +Fix potential crash in deallocating method objects when dynamically +allocated `PyMethodDef`'s lifetime is managed through the ``self`` argument +of a `PyCFunction`. + +.. + +.. bpo: 41986 +.. date: 2020-10-09-22-50-46 +.. nonce: JUPE59 +.. section: C API + +:c:data:`Py_FileSystemDefaultEncodeErrors` and :c:data:`Py_UTF8Mode` are +available again in limited API. diff --git a/Misc/NEWS.d/next/Build/2020-06-17-09-05-02.bpo-40998.sgqmg9.rst b/Misc/NEWS.d/next/Build/2020-06-17-09-05-02.bpo-40998.sgqmg9.rst deleted file mode 100644 index c268e4fd0d9cbf..00000000000000 --- a/Misc/NEWS.d/next/Build/2020-06-17-09-05-02.bpo-40998.sgqmg9.rst +++ /dev/null @@ -1,2 +0,0 @@ -Addressed three compiler warnings found by undefined behavior sanitizer -(ubsan). diff --git a/Misc/NEWS.d/next/Build/2020-09-28-21-56-51.bpo-38249.uzMCaZ.rst b/Misc/NEWS.d/next/Build/2020-09-28-21-56-51.bpo-38249.uzMCaZ.rst deleted file mode 100644 index 3e409ec2e7c202..00000000000000 --- a/Misc/NEWS.d/next/Build/2020-09-28-21-56-51.bpo-38249.uzMCaZ.rst +++ /dev/null @@ -1,2 +0,0 @@ -Update :c:macro:`Py_UNREACHABLE` to use __builtin_unreachable() if only the -compiler is able to use it. Patch by Dong-hee Na. diff --git a/Misc/NEWS.d/next/Build/2020-11-13-15-04-53.bpo-41617.98_oaE.rst b/Misc/NEWS.d/next/Build/2020-11-13-15-04-53.bpo-41617.98_oaE.rst deleted file mode 100644 index a5f35b25e8bf6a..00000000000000 --- a/Misc/NEWS.d/next/Build/2020-11-13-15-04-53.bpo-41617.98_oaE.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix building ``pycore_bitutils.h`` internal header on old clang version -without ``__builtin_bswap16()`` (ex: Xcode 4.6.3 on Mac OS X 10.7). Patch by -Joshua Root and Victor Stinner. diff --git a/Misc/NEWS.d/next/Build/2020-11-18-11-58-44.bpo-42398.Yt5wO8.rst b/Misc/NEWS.d/next/Build/2020-11-18-11-58-44.bpo-42398.Yt5wO8.rst deleted file mode 100644 index 9ab99d0e69dd1d..00000000000000 --- a/Misc/NEWS.d/next/Build/2020-11-18-11-58-44.bpo-42398.Yt5wO8.rst +++ /dev/null @@ -1,4 +0,0 @@ -Fix a race condition in "make regen-all" when make -jN option is used to run -jobs in parallel. The clinic.py script now only use atomic write to write -files. Moveover, generated files are now left unchanged if the content does not -change, to not change the file modification time. diff --git a/Misc/NEWS.d/next/C API/2020-10-09-22-50-46.bpo-41986.JUPE59.rst b/Misc/NEWS.d/next/C API/2020-10-09-22-50-46.bpo-41986.JUPE59.rst deleted file mode 100644 index d456ba66bafd61..00000000000000 --- a/Misc/NEWS.d/next/C API/2020-10-09-22-50-46.bpo-41986.JUPE59.rst +++ /dev/null @@ -1,2 +0,0 @@ -:c:data:`Py_FileSystemDefaultEncodeErrors` and :c:data:`Py_UTF8Mode` are -available again in limited API. diff --git a/Misc/NEWS.d/next/C API/2020-10-12-20-13-58.bpo-42015.X4H2_V.rst b/Misc/NEWS.d/next/C API/2020-10-12-20-13-58.bpo-42015.X4H2_V.rst deleted file mode 100644 index d77619f64bb178..00000000000000 --- a/Misc/NEWS.d/next/C API/2020-10-12-20-13-58.bpo-42015.X4H2_V.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix potential crash in deallocating method objects when dynamically -allocated `PyMethodDef`'s lifetime is managed through the ``self`` -argument of a `PyCFunction`. diff --git a/Misc/NEWS.d/next/Core and Builtins/2020-09-24-12-15-45.bpo-39934.YVHTCF.rst b/Misc/NEWS.d/next/Core and Builtins/2020-09-24-12-15-45.bpo-39934.YVHTCF.rst deleted file mode 100644 index 92cd1ba234d215..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2020-09-24-12-15-45.bpo-39934.YVHTCF.rst +++ /dev/null @@ -1,3 +0,0 @@ -Correctly count control blocks in 'except' in compiler. Ensures that a -syntax error, rather a fatal error, occurs for deeply nested, named -exception handlers. diff --git a/Misc/NEWS.d/next/Core and Builtins/2020-10-02-11-35-33.bpo-41894.ffmtOt.rst b/Misc/NEWS.d/next/Core and Builtins/2020-10-02-11-35-33.bpo-41894.ffmtOt.rst deleted file mode 100644 index 571f5dae1a4a1a..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2020-10-02-11-35-33.bpo-41894.ffmtOt.rst +++ /dev/null @@ -1,3 +0,0 @@ -When loading a native module and a load failure occurs, prevent a possible -UnicodeDecodeError when not running in a UTF-8 locale by decoding the load -error message using the current locale's encoding. diff --git a/Misc/NEWS.d/next/Core and Builtins/2020-10-04-10-55-12.bpo-41909.BqHPcm.rst b/Misc/NEWS.d/next/Core and Builtins/2020-10-04-10-55-12.bpo-41909.BqHPcm.rst deleted file mode 100644 index 388cfea065eedc..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2020-10-04-10-55-12.bpo-41909.BqHPcm.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fixed stack overflow in :func:`issubclass` and :func:`isinstance` when -getting the ``__bases__`` attribute leads to infinite recursion. diff --git a/Misc/NEWS.d/next/Core and Builtins/2020-10-09-10-55-50.bpo-41979.ImXIk2.rst b/Misc/NEWS.d/next/Core and Builtins/2020-10-09-10-55-50.bpo-41979.ImXIk2.rst deleted file mode 100644 index 3250309ca22cd3..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2020-10-09-10-55-50.bpo-41979.ImXIk2.rst +++ /dev/null @@ -1 +0,0 @@ -Star-unpacking is now allowed for with item's targets in the PEG parser. diff --git a/Misc/NEWS.d/next/Core and Builtins/2020-10-10-13-53-52.bpo-41993.YMzixQ.rst b/Misc/NEWS.d/next/Core and Builtins/2020-10-10-13-53-52.bpo-41993.YMzixQ.rst deleted file mode 100644 index 3669cf11ea4cd3..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2020-10-10-13-53-52.bpo-41993.YMzixQ.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fixed potential issues with removing not completely initialized module from -``sys.modules`` when import fails. diff --git a/Misc/NEWS.d/next/Core and Builtins/2020-10-14-16-19-43.bpo-41984.SEtKMr.rst b/Misc/NEWS.d/next/Core and Builtins/2020-10-14-16-19-43.bpo-41984.SEtKMr.rst deleted file mode 100644 index e70d5dc2b8ddec..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2020-10-14-16-19-43.bpo-41984.SEtKMr.rst +++ /dev/null @@ -1,2 +0,0 @@ -The garbage collector now tracks all user-defined classes. Patch by Brandt -Bucher. diff --git a/Misc/NEWS.d/next/Core and Builtins/2020-10-20-11-36-14.bpo-42057.BI-OoV.rst b/Misc/NEWS.d/next/Core and Builtins/2020-10-20-11-36-14.bpo-42057.BI-OoV.rst deleted file mode 100644 index 95c3a248f9a1ab..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2020-10-20-11-36-14.bpo-42057.BI-OoV.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix peephole optimizer misoptimize conditional jump + JUMP_IF_NOT_EXC_MATCH -pair. diff --git a/Misc/NEWS.d/next/Core and Builtins/2020-10-21-14-40-54.bpo-41910.CzBMit.rst b/Misc/NEWS.d/next/Core and Builtins/2020-10-21-14-40-54.bpo-41910.CzBMit.rst deleted file mode 100644 index a40e2519a62c6a..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2020-10-21-14-40-54.bpo-41910.CzBMit.rst +++ /dev/null @@ -1 +0,0 @@ -Document the default implementation of `object.__eq__`. diff --git a/Misc/NEWS.d/next/Core and Builtins/2020-10-23-02-43-24.bpo-42123.64gJWC.rst b/Misc/NEWS.d/next/Core and Builtins/2020-10-23-02-43-24.bpo-42123.64gJWC.rst deleted file mode 100644 index 6461efd76f0f97..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2020-10-23-02-43-24.bpo-42123.64gJWC.rst +++ /dev/null @@ -1,3 +0,0 @@ -Run the parser two times. On the first run, disable all the rules that only -generate better error messages to gain performance. If there's a parse -failure, run the parser a second time with those enabled. diff --git a/Misc/NEWS.d/next/Core and Builtins/2020-10-25-21-14-18.bpo-42150.b70u_T.rst b/Misc/NEWS.d/next/Core and Builtins/2020-10-25-21-14-18.bpo-42150.b70u_T.rst deleted file mode 100644 index 62fabb857aa380..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2020-10-25-21-14-18.bpo-42150.b70u_T.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix possible buffer overflow in the new parser when checking for -continuation lines. Patch by Pablo Galindo. diff --git a/Misc/NEWS.d/next/Core and Builtins/2020-10-27-18-32-49.bpo-41659.d4a-8o.rst b/Misc/NEWS.d/next/Core and Builtins/2020-10-27-18-32-49.bpo-41659.d4a-8o.rst deleted file mode 100644 index 038749a7b16c9d..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2020-10-27-18-32-49.bpo-41659.d4a-8o.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix a bug in the parser, where a curly brace following a `primary` didn't fail immediately. -This led to invalid expressions like `a {b}` to throw a :exc:`SyntaxError` with a wrong offset, -or invalid expressions ending with a curly brace like `a {` to not fail immediately in the REPL. \ No newline at end of file diff --git a/Misc/NEWS.d/next/Core and Builtins/2020-10-27-21-34-05.bpo-42143.N6KXUO.rst b/Misc/NEWS.d/next/Core and Builtins/2020-10-27-21-34-05.bpo-42143.N6KXUO.rst deleted file mode 100644 index 2b16e69da73b5f..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2020-10-27-21-34-05.bpo-42143.N6KXUO.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix handling of errors during creation of ``PyFunctionObject``, which resulted -in operations on uninitialized memory. Patch by Yonatan Goldschmidt. diff --git a/Misc/NEWS.d/next/Core and Builtins/2020-10-30-22-16-30.bpo-42214.lXskM_.rst b/Misc/NEWS.d/next/Core and Builtins/2020-10-30-22-16-30.bpo-42214.lXskM_.rst deleted file mode 100644 index 3f85bbe83901a0..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2020-10-30-22-16-30.bpo-42214.lXskM_.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fixed a possible crash in the PEG parser when checking for the '!=' token in -the ``barry_as_flufl`` rule. Patch by Pablo Galindo. diff --git a/Misc/NEWS.d/next/Core and Builtins/2020-10-31-17-50-23.bpo-42218.Dp_Z3v.rst b/Misc/NEWS.d/next/Core and Builtins/2020-10-31-17-50-23.bpo-42218.Dp_Z3v.rst deleted file mode 100644 index a38a310e4b45b8..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2020-10-31-17-50-23.bpo-42218.Dp_Z3v.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fixed a bug in the PEG parser that was causing crashes in debug mode. Now errors are checked -in left-recursive rules to avoid cases where such errors do not get handled in time and appear -as long-distance crashes in other places. diff --git a/Misc/NEWS.d/next/Core and Builtins/2020-11-12-23-16-14.bpo-42332.fEQIdk.rst b/Misc/NEWS.d/next/Core and Builtins/2020-11-12-23-16-14.bpo-42332.fEQIdk.rst deleted file mode 100644 index 8a2cb87cc0bd29..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2020-11-12-23-16-14.bpo-42332.fEQIdk.rst +++ /dev/null @@ -1 +0,0 @@ -:class:`types.GenericAlias` objects can now be the targets of weakrefs. diff --git a/Misc/NEWS.d/next/Core and Builtins/2020-11-13-13-53-11.bpo-42296.DuGrLJ.rst b/Misc/NEWS.d/next/Core and Builtins/2020-11-13-13-53-11.bpo-42296.DuGrLJ.rst deleted file mode 100644 index 841a26e791ea08..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2020-11-13-13-53-11.bpo-42296.DuGrLJ.rst +++ /dev/null @@ -1,4 +0,0 @@ -On Windows, fix a regression in signal handling which prevented to interrupt -a program using CTRL+C. The signal handler can be run in a thread different -than the Python thread, in which case the test deciding if the thread can -handle signals is wrong. diff --git a/Misc/NEWS.d/next/Core and Builtins/2020-11-16-17-57-09.bpo-42374.t7np1E.rst b/Misc/NEWS.d/next/Core and Builtins/2020-11-16-17-57-09.bpo-42374.t7np1E.rst deleted file mode 100644 index d86d038c8425c5..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2020-11-16-17-57-09.bpo-42374.t7np1E.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix a regression introduced by the new parser, where an unparenthesized walrus operator -was not allowed within generator expressions. \ No newline at end of file diff --git a/Misc/NEWS.d/next/Core and Builtins/2020-11-16-23-45-56.bpo-42381.G4AWxL.rst b/Misc/NEWS.d/next/Core and Builtins/2020-11-16-23-45-56.bpo-42381.G4AWxL.rst deleted file mode 100644 index 5bee5141f6cbcd..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2020-11-16-23-45-56.bpo-42381.G4AWxL.rst +++ /dev/null @@ -1,2 +0,0 @@ -Allow assignment expressions in set literals and set comprehensions as per -PEP 572. Patch by Pablo Galindo. diff --git a/Misc/NEWS.d/next/Core and Builtins/2020-11-17-16-25-50.bpo-41686.hX77kL.rst b/Misc/NEWS.d/next/Core and Builtins/2020-11-17-16-25-50.bpo-41686.hX77kL.rst deleted file mode 100644 index 0265d48660a3c6..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2020-11-17-16-25-50.bpo-41686.hX77kL.rst +++ /dev/null @@ -1,4 +0,0 @@ -On Windows, the ``SIGINT`` event, ``_PyOS_SigintEvent()``, is now created -even if Python is configured to not install signal handlers (if -:c:member:`PyConfig.install_signal_handlers` equals to 0, or -``Py_InitializeEx(0)``). diff --git a/Misc/NEWS.d/next/Documentation/2020-01-22-05-14-53.bpo-39416.uYjhEm.rst b/Misc/NEWS.d/next/Documentation/2020-01-22-05-14-53.bpo-39416.uYjhEm.rst deleted file mode 100644 index 279a5f18ff855e..00000000000000 --- a/Misc/NEWS.d/next/Documentation/2020-01-22-05-14-53.bpo-39416.uYjhEm.rst +++ /dev/null @@ -1 +0,0 @@ -Document some restrictions on the default string representations of numeric classes. diff --git a/Misc/NEWS.d/next/Documentation/2020-02-24-09-02-05.bpo-39693.QXw0Fm.rst b/Misc/NEWS.d/next/Documentation/2020-02-24-09-02-05.bpo-39693.QXw0Fm.rst deleted file mode 100644 index 86049c536815b9..00000000000000 --- a/Misc/NEWS.d/next/Documentation/2020-02-24-09-02-05.bpo-39693.QXw0Fm.rst +++ /dev/null @@ -1 +0,0 @@ -Fix tarfile's extractfile documentation diff --git a/Misc/NEWS.d/next/Documentation/2020-09-08-16-57-09.bpo-41726.g0UXrn.rst b/Misc/NEWS.d/next/Documentation/2020-09-08-16-57-09.bpo-41726.g0UXrn.rst deleted file mode 100644 index 1079a757c054ac..00000000000000 --- a/Misc/NEWS.d/next/Documentation/2020-09-08-16-57-09.bpo-41726.g0UXrn.rst +++ /dev/null @@ -1 +0,0 @@ -Update the refcounts info of ``PyType_FromModuleAndSpec``. diff --git a/Misc/NEWS.d/next/Documentation/2020-09-12-17-37-13.bpo-35293._cOwPD.rst b/Misc/NEWS.d/next/Documentation/2020-09-12-17-37-13.bpo-35293._cOwPD.rst deleted file mode 100644 index 089d44e35d2baa..00000000000000 --- a/Misc/NEWS.d/next/Documentation/2020-09-12-17-37-13.bpo-35293._cOwPD.rst +++ /dev/null @@ -1 +0,0 @@ -Fix RemovedInSphinx40Warning when building the documentation. Patch by Dong-hee Na. diff --git a/Misc/NEWS.d/next/Documentation/2020-09-24-15-35-13.bpo-41774.5IqdGP.rst b/Misc/NEWS.d/next/Documentation/2020-09-24-15-35-13.bpo-41774.5IqdGP.rst deleted file mode 100644 index af8e02437cb2b5..00000000000000 --- a/Misc/NEWS.d/next/Documentation/2020-09-24-15-35-13.bpo-41774.5IqdGP.rst +++ /dev/null @@ -1,2 +0,0 @@ -In Programming FAQ "Sequences (Tuples/Lists)" section, add "How do you -remove multiple items from a list". diff --git a/Misc/NEWS.d/next/Documentation/2020-10-10-01-36-37.bpo-41805.l-CGv5.rst b/Misc/NEWS.d/next/Documentation/2020-10-10-01-36-37.bpo-41805.l-CGv5.rst deleted file mode 100644 index 9c9134350a3176..00000000000000 --- a/Misc/NEWS.d/next/Documentation/2020-10-10-01-36-37.bpo-41805.l-CGv5.rst +++ /dev/null @@ -1,3 +0,0 @@ -Documented :ref:`generic alias type ` and -:data:`types.GenericAlias`. Also added an entry in glossary for -:term:`generic types `. diff --git a/Misc/NEWS.d/next/Documentation/2020-10-21-02-21-14.bpo-42010.76vJ0u.rst b/Misc/NEWS.d/next/Documentation/2020-10-21-02-21-14.bpo-42010.76vJ0u.rst deleted file mode 100644 index 2a0cbf10757837..00000000000000 --- a/Misc/NEWS.d/next/Documentation/2020-10-21-02-21-14.bpo-42010.76vJ0u.rst +++ /dev/null @@ -1,4 +0,0 @@ -Clarify that subscription expressions are also valid for certain -:term:`classes ` and :term:`types ` in the standard library, and -for user-defined classes and types if the classmethod -:meth:`__class_getitem__` is provided. diff --git a/Misc/NEWS.d/next/Documentation/2020-10-28-21-39-45.bpo-42061._x-0sg.rst b/Misc/NEWS.d/next/Documentation/2020-10-28-21-39-45.bpo-42061._x-0sg.rst deleted file mode 100644 index b38bb84350171e..00000000000000 --- a/Misc/NEWS.d/next/Documentation/2020-10-28-21-39-45.bpo-42061._x-0sg.rst +++ /dev/null @@ -1 +0,0 @@ -Document __format__ functionality for IP addresses. \ No newline at end of file diff --git a/Misc/NEWS.d/next/Documentation/2020-11-15-13-46-31.bpo-42153.KjBhx3.rst b/Misc/NEWS.d/next/Documentation/2020-11-15-13-46-31.bpo-42153.KjBhx3.rst deleted file mode 100644 index 0a9451a63fb4f8..00000000000000 --- a/Misc/NEWS.d/next/Documentation/2020-11-15-13-46-31.bpo-42153.KjBhx3.rst +++ /dev/null @@ -1 +0,0 @@ -Fix the URL for the IMAP protocol documents. diff --git a/Misc/NEWS.d/next/IDLE/2020-04-22-09-37-40.bpo-38439.ieXL-c.rst b/Misc/NEWS.d/next/IDLE/2020-04-22-09-37-40.bpo-38439.ieXL-c.rst deleted file mode 100644 index d8d59015f20e3d..00000000000000 --- a/Misc/NEWS.d/next/IDLE/2020-04-22-09-37-40.bpo-38439.ieXL-c.rst +++ /dev/null @@ -1,2 +0,0 @@ -Add a 256×256 pixel IDLE icon to the Windows .ico file. Created by Andrew -Clover. Remove the low-color gif variations from the .ico file. diff --git a/Misc/NEWS.d/next/IDLE/2020-06-16-12-16-13.bpo-40511.XkihpM.rst b/Misc/NEWS.d/next/IDLE/2020-06-16-12-16-13.bpo-40511.XkihpM.rst deleted file mode 100644 index cc967981381769..00000000000000 --- a/Misc/NEWS.d/next/IDLE/2020-06-16-12-16-13.bpo-40511.XkihpM.rst +++ /dev/null @@ -1,3 +0,0 @@ -Typing opening and closing parentheses inside the parentheses of a function -call will no longer cause unnecessary "flashing" off and on of an existing -open call-tip, e.g. when typed in a string literal. diff --git a/Misc/NEWS.d/next/IDLE/2020-09-22-00-45-40.bpo-40181.hhQi3z.rst b/Misc/NEWS.d/next/IDLE/2020-09-22-00-45-40.bpo-40181.hhQi3z.rst deleted file mode 100644 index b6866e19c4d41a..00000000000000 --- a/Misc/NEWS.d/next/IDLE/2020-09-22-00-45-40.bpo-40181.hhQi3z.rst +++ /dev/null @@ -1,2 +0,0 @@ -In calltips, stop reminding that '/' marks the end of positional-only -arguments. diff --git a/Misc/NEWS.d/next/IDLE/2020-09-22-11-13-45.bpo-35764.VoNa8y.rst b/Misc/NEWS.d/next/IDLE/2020-09-22-11-13-45.bpo-35764.VoNa8y.rst deleted file mode 100644 index eb62d3699d5feb..00000000000000 --- a/Misc/NEWS.d/next/IDLE/2020-09-22-11-13-45.bpo-35764.VoNa8y.rst +++ /dev/null @@ -1 +0,0 @@ -Rewrite the Calltips doc section. diff --git a/Misc/NEWS.d/next/IDLE/2020-09-24-14-31-16.bpo-41775.sB8Vre.rst b/Misc/NEWS.d/next/IDLE/2020-09-24-14-31-16.bpo-41775.sB8Vre.rst deleted file mode 100644 index 59605fa40235fb..00000000000000 --- a/Misc/NEWS.d/next/IDLE/2020-09-24-14-31-16.bpo-41775.sB8Vre.rst +++ /dev/null @@ -1 +0,0 @@ -Use 'IDLE Shell' as shell title diff --git a/Misc/NEWS.d/next/IDLE/2020-10-24-21-27-37.bpo-33987.fIh9JL.rst b/Misc/NEWS.d/next/IDLE/2020-10-24-21-27-37.bpo-33987.fIh9JL.rst deleted file mode 100644 index 1e67edc03c658d..00000000000000 --- a/Misc/NEWS.d/next/IDLE/2020-10-24-21-27-37.bpo-33987.fIh9JL.rst +++ /dev/null @@ -1,3 +0,0 @@ -Mostly finish using ttk widgets, mainly for editor, settings, -and searches. Some patches by Mark Roseman. - diff --git a/Misc/NEWS.d/next/IDLE/2020-11-20-01-30-27.bpo-42415.CyD-va.rst b/Misc/NEWS.d/next/IDLE/2020-11-20-01-30-27.bpo-42415.CyD-va.rst deleted file mode 100644 index b61032c1e48e2a..00000000000000 --- a/Misc/NEWS.d/next/IDLE/2020-11-20-01-30-27.bpo-42415.CyD-va.rst +++ /dev/null @@ -1 +0,0 @@ -Get docstrings for IDLE calltips more often by using inspect.getdoc. diff --git a/Misc/NEWS.d/next/IDLE/2020-11-21-17-21-21.bpo-42426.kNnPoC.rst b/Misc/NEWS.d/next/IDLE/2020-11-21-17-21-21.bpo-42426.kNnPoC.rst deleted file mode 100644 index 0ab7972aad982e..00000000000000 --- a/Misc/NEWS.d/next/IDLE/2020-11-21-17-21-21.bpo-42426.kNnPoC.rst +++ /dev/null @@ -1 +0,0 @@ -Fix reporting offset of the RE error in searchengine. diff --git a/Misc/NEWS.d/next/Library/2020-01-19-18-40-26.bpo-27321.8e6SpM.rst b/Misc/NEWS.d/next/Library/2020-01-19-18-40-26.bpo-27321.8e6SpM.rst deleted file mode 100644 index 28acf7f6ef919c..00000000000000 --- a/Misc/NEWS.d/next/Library/2020-01-19-18-40-26.bpo-27321.8e6SpM.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fixed KeyError exception when flattening an email to a string attempts to -replace a non-existent Content-Transfer-Encoding header. diff --git a/Misc/NEWS.d/next/Library/2020-04-03-16-13-59.bpo-40105.hfM2c0.rst b/Misc/NEWS.d/next/Library/2020-04-03-16-13-59.bpo-40105.hfM2c0.rst deleted file mode 100644 index f71a7a1e697a48..00000000000000 --- a/Misc/NEWS.d/next/Library/2020-04-03-16-13-59.bpo-40105.hfM2c0.rst +++ /dev/null @@ -1,2 +0,0 @@ -ZipFile truncates files to avoid corruption when a shorter comment is provided -in append ("a") mode. Patch by Jan Mazur. diff --git a/Misc/NEWS.d/next/Library/2020-05-04-12-16-00.bpo-40492.ONk9Na.rst b/Misc/NEWS.d/next/Library/2020-05-04-12-16-00.bpo-40492.ONk9Na.rst deleted file mode 100644 index 86bc08c79e21e2..00000000000000 --- a/Misc/NEWS.d/next/Library/2020-05-04-12-16-00.bpo-40492.ONk9Na.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix ``--outfile`` for :mod:`cProfile` / :mod:`profile` not writing the output -file in the original directory when the program being profiled changes the -working directory. PR by Anthony Sottile. diff --git a/Misc/NEWS.d/next/Library/2020-05-08-21-30-54.bpo-40550.i7GWkb.rst b/Misc/NEWS.d/next/Library/2020-05-08-21-30-54.bpo-40550.i7GWkb.rst deleted file mode 100644 index b0f3f03c34bbc5..00000000000000 --- a/Misc/NEWS.d/next/Library/2020-05-08-21-30-54.bpo-40550.i7GWkb.rst +++ /dev/null @@ -1 +0,0 @@ -Fix time-of-check/time-of-action issue in subprocess.Popen.send_signal. diff --git a/Misc/NEWS.d/next/Library/2020-05-14-16-01-34.bpo-40592.Cmk855.rst b/Misc/NEWS.d/next/Library/2020-05-14-16-01-34.bpo-40592.Cmk855.rst deleted file mode 100644 index 3211a1bc345fa5..00000000000000 --- a/Misc/NEWS.d/next/Library/2020-05-14-16-01-34.bpo-40592.Cmk855.rst +++ /dev/null @@ -1 +0,0 @@ -:func:`shutil.which` now ignores empty entries in :envvar:`PATHEXT` instead of treating them as a match. diff --git a/Misc/NEWS.d/next/Library/2020-07-08-09-45-00.bpo-16936.z8o8Pn.rst b/Misc/NEWS.d/next/Library/2020-07-08-09-45-00.bpo-16936.z8o8Pn.rst deleted file mode 100644 index c76db4eedecff1..00000000000000 --- a/Misc/NEWS.d/next/Library/2020-07-08-09-45-00.bpo-16936.z8o8Pn.rst +++ /dev/null @@ -1 +0,0 @@ -Allow ``ctypes.wintypes`` to be imported on non-Windows systems. diff --git a/Misc/NEWS.d/next/Library/2020-07-28-12-08-58.bpo-41316.bSCbK4.rst b/Misc/NEWS.d/next/Library/2020-07-28-12-08-58.bpo-41316.bSCbK4.rst deleted file mode 100644 index 139a170866ed49..00000000000000 --- a/Misc/NEWS.d/next/Library/2020-07-28-12-08-58.bpo-41316.bSCbK4.rst +++ /dev/null @@ -1 +0,0 @@ -Fix the :mod:`tarfile` module to write only basename of TAR file to GZIP compression header. \ No newline at end of file diff --git a/Misc/NEWS.d/next/Library/2020-09-19-23-14-54.bpo-41815.RNpuX3.rst b/Misc/NEWS.d/next/Library/2020-09-19-23-14-54.bpo-41815.RNpuX3.rst deleted file mode 100644 index 3560db9bc5d355..00000000000000 --- a/Misc/NEWS.d/next/Library/2020-09-19-23-14-54.bpo-41815.RNpuX3.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix SQLite3 segfault when backing up closed database. Patch contributed by -Peter David McCormick. diff --git a/Misc/NEWS.d/next/Library/2020-09-22-00-23-30.bpo-41817.bnh-VG.rst b/Misc/NEWS.d/next/Library/2020-09-22-00-23-30.bpo-41817.bnh-VG.rst deleted file mode 100644 index 6a634bb613260b..00000000000000 --- a/Misc/NEWS.d/next/Library/2020-09-22-00-23-30.bpo-41817.bnh-VG.rst +++ /dev/null @@ -1 +0,0 @@ -fix `tkinter.EventType` Enum so all members are strings, and none are tuples diff --git a/Misc/NEWS.d/next/Library/2020-09-22-11-07-50.bpo-41831.k-Eop_.rst b/Misc/NEWS.d/next/Library/2020-09-22-11-07-50.bpo-41831.k-Eop_.rst deleted file mode 100644 index 84a3f5253a0604..00000000000000 --- a/Misc/NEWS.d/next/Library/2020-09-22-11-07-50.bpo-41831.k-Eop_.rst +++ /dev/null @@ -1,3 +0,0 @@ -``str()`` for the ``type`` attribute of the ``tkinter.Event`` object always -returns now the numeric code returned by Tk instead of the name of the event -type. diff --git a/Misc/NEWS.d/next/Library/2020-09-23-23-17-59.bpo-41840.QRFr4L.rst b/Misc/NEWS.d/next/Library/2020-09-23-23-17-59.bpo-41840.QRFr4L.rst deleted file mode 100644 index e96942d8ebd07f..00000000000000 --- a/Misc/NEWS.d/next/Library/2020-09-23-23-17-59.bpo-41840.QRFr4L.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix a bug in the :mod:`symtable` module that was causing module-scope global -variables to not be reported as both local and global. Patch by Pablo -Galindo. diff --git a/Misc/NEWS.d/next/Library/2020-10-01-10-50-12.bpo-41900.Cho7oh.rst b/Misc/NEWS.d/next/Library/2020-10-01-10-50-12.bpo-41900.Cho7oh.rst deleted file mode 100644 index 6586c09ec985d5..00000000000000 --- a/Misc/NEWS.d/next/Library/2020-10-01-10-50-12.bpo-41900.Cho7oh.rst +++ /dev/null @@ -1,2 +0,0 @@ -C14N 2.0 serialisation in xml.etree.ElementTree failed for unprefixed attributes -when a default namespace was defined. diff --git a/Misc/NEWS.d/next/Library/2020-10-08-18-22-28.bpo-41976.Svm0wb.rst b/Misc/NEWS.d/next/Library/2020-10-08-18-22-28.bpo-41976.Svm0wb.rst deleted file mode 100644 index c8b3fc771845e3..00000000000000 --- a/Misc/NEWS.d/next/Library/2020-10-08-18-22-28.bpo-41976.Svm0wb.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fixed a bug that was causing :func:`ctypes.util.find_library` to return -``None`` when triying to locate a library in an environment when gcc>=9 is -available and ``ldconfig`` is not. Patch by Pablo Galindo diff --git a/Misc/NEWS.d/next/Library/2020-10-17-07-52-53.bpo-41966.gwEQRZ.rst b/Misc/NEWS.d/next/Library/2020-10-17-07-52-53.bpo-41966.gwEQRZ.rst deleted file mode 100644 index 0e7fad40077be0..00000000000000 --- a/Misc/NEWS.d/next/Library/2020-10-17-07-52-53.bpo-41966.gwEQRZ.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix pickling pure Python :class:`datetime.time` subclasses. Patch by Dean -Inwood. diff --git a/Misc/NEWS.d/next/Library/2020-10-17-23-17-18.bpo-42065.85BsRA.rst b/Misc/NEWS.d/next/Library/2020-10-17-23-17-18.bpo-42065.85BsRA.rst deleted file mode 100644 index 83c86c0799ebfa..00000000000000 --- a/Misc/NEWS.d/next/Library/2020-10-17-23-17-18.bpo-42065.85BsRA.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix an incorrectly formatted error from :meth:`_codecs.charmap_decode` when -called with a mapped value outside the range of valid Unicode code points. -PR by Max Bernstein. diff --git a/Misc/NEWS.d/next/Library/2020-10-19-14-02-09.bpo-41491.d1BUWH.rst b/Misc/NEWS.d/next/Library/2020-10-19-14-02-09.bpo-41491.d1BUWH.rst deleted file mode 100644 index 4f39c91b284fac..00000000000000 --- a/Misc/NEWS.d/next/Library/2020-10-19-14-02-09.bpo-41491.d1BUWH.rst +++ /dev/null @@ -1 +0,0 @@ -plistlib: fix parsing XML plists with hexadecimal integer values diff --git a/Misc/NEWS.d/next/Library/2020-10-21-23-45-02.bpo-41052.3N7J2J.rst b/Misc/NEWS.d/next/Library/2020-10-21-23-45-02.bpo-41052.3N7J2J.rst deleted file mode 100644 index 528e90ed13493c..00000000000000 --- a/Misc/NEWS.d/next/Library/2020-10-21-23-45-02.bpo-41052.3N7J2J.rst +++ /dev/null @@ -1,2 +0,0 @@ -Pickling heap types implemented in C with protocols 0 and 1 raises now an -error instead of producing incorrect data. diff --git a/Misc/NEWS.d/next/Library/2020-10-23-19-20-14.bpo-42103.C5obK2.rst b/Misc/NEWS.d/next/Library/2020-10-23-19-20-14.bpo-42103.C5obK2.rst deleted file mode 100644 index 4eb694c16a0633..00000000000000 --- a/Misc/NEWS.d/next/Library/2020-10-23-19-20-14.bpo-42103.C5obK2.rst +++ /dev/null @@ -1,3 +0,0 @@ -:exc:`~plistlib.InvalidFileException` and :exc:`RecursionError` are now -the only errors caused by loading malformed binary Plist file (previously -ValueError and TypeError could be raised in some specific cases). diff --git a/Misc/NEWS.d/next/Library/2020-10-24-04-02-36.bpo-42140.miLqvb.rst b/Misc/NEWS.d/next/Library/2020-10-24-04-02-36.bpo-42140.miLqvb.rst deleted file mode 100644 index 4160234b5ec685..00000000000000 --- a/Misc/NEWS.d/next/Library/2020-10-24-04-02-36.bpo-42140.miLqvb.rst +++ /dev/null @@ -1 +0,0 @@ -Improve asyncio.wait function to create the futures set just one time. diff --git a/Misc/NEWS.d/next/Library/2020-10-25-19-25-02.bpo-42146.6A8uvS.rst b/Misc/NEWS.d/next/Library/2020-10-25-19-25-02.bpo-42146.6A8uvS.rst deleted file mode 100644 index 041809803db6a2..00000000000000 --- a/Misc/NEWS.d/next/Library/2020-10-25-19-25-02.bpo-42146.6A8uvS.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix memory leak in :func:`subprocess.Popen` in case an uid (gid) specified in -`user` (`group`, `extra_groups`) overflows `uid_t` (`gid_t`). diff --git a/Misc/NEWS.d/next/Library/2020-10-29-11-17-35.bpo-42183.50ZcIi.rst b/Misc/NEWS.d/next/Library/2020-10-29-11-17-35.bpo-42183.50ZcIi.rst deleted file mode 100644 index f6d7653f2cf09f..00000000000000 --- a/Misc/NEWS.d/next/Library/2020-10-29-11-17-35.bpo-42183.50ZcIi.rst +++ /dev/null @@ -1,4 +0,0 @@ -Fix a stack overflow error for asyncio Task or Future repr(). - -The overflow occurs under some circumstances when a Task or Future -recursively returns itself. diff --git a/Misc/NEWS.d/next/Library/2020-10-31-13-28-36.bpo-29566.6aDbty.rst b/Misc/NEWS.d/next/Library/2020-10-31-13-28-36.bpo-29566.6aDbty.rst deleted file mode 100644 index d54c714688531a..00000000000000 --- a/Misc/NEWS.d/next/Library/2020-10-31-13-28-36.bpo-29566.6aDbty.rst +++ /dev/null @@ -1 +0,0 @@ -``binhex.binhex()`` consisently writes macOS 9 line endings. diff --git a/Misc/NEWS.d/next/Library/2020-11-01-15-07-20.bpo-41754.DraSZh.rst b/Misc/NEWS.d/next/Library/2020-11-01-15-07-20.bpo-41754.DraSZh.rst deleted file mode 100644 index 181c2d9650a14c..00000000000000 --- a/Misc/NEWS.d/next/Library/2020-11-01-15-07-20.bpo-41754.DraSZh.rst +++ /dev/null @@ -1 +0,0 @@ -webbrowser: Ignore *NotADirectoryError* when calling ``xdg-settings``. diff --git a/Misc/NEWS.d/next/Library/2020-11-02-01-31-15.bpo-42233.YxRj-h.rst b/Misc/NEWS.d/next/Library/2020-11-02-01-31-15.bpo-42233.YxRj-h.rst deleted file mode 100644 index aad4249fa165bf..00000000000000 --- a/Misc/NEWS.d/next/Library/2020-11-02-01-31-15.bpo-42233.YxRj-h.rst +++ /dev/null @@ -1,3 +0,0 @@ -The :func:`repr` of :mod:`typing` types containing -:ref:`Generic Alias Types ` previously did not show the -parameterized types in the ``GenericAlias``. They have now been changed to do so. diff --git a/Misc/NEWS.d/next/Library/2020-11-02-14-10-48.bpo-35455.Q1xTIo.rst b/Misc/NEWS.d/next/Library/2020-11-02-14-10-48.bpo-35455.Q1xTIo.rst deleted file mode 100644 index e72c7d277a1123..00000000000000 --- a/Misc/NEWS.d/next/Library/2020-11-02-14-10-48.bpo-35455.Q1xTIo.rst +++ /dev/null @@ -1,3 +0,0 @@ -On Solaris, :func:`~time.thread_time` is now implemented with -``gethrvtime()`` because ``clock_gettime(CLOCK_THREAD_CPUTIME_ID)`` is not -always available. Patch by Jakub Kulik. diff --git a/Misc/NEWS.d/next/Library/2020-11-03-09-22-56.bpo-42249.vfNO2u.rst b/Misc/NEWS.d/next/Library/2020-11-03-09-22-56.bpo-42249.vfNO2u.rst deleted file mode 100644 index 071a0fdda1ff80..00000000000000 --- a/Misc/NEWS.d/next/Library/2020-11-03-09-22-56.bpo-42249.vfNO2u.rst +++ /dev/null @@ -1 +0,0 @@ -Fixed writing binary Plist files larger than 4 GiB. diff --git a/Misc/NEWS.d/next/Library/2020-11-10-14-27-49.bpo-42237.F363jO.rst b/Misc/NEWS.d/next/Library/2020-11-10-14-27-49.bpo-42237.F363jO.rst deleted file mode 100644 index 50cab6e1f11f84..00000000000000 --- a/Misc/NEWS.d/next/Library/2020-11-10-14-27-49.bpo-42237.F363jO.rst +++ /dev/null @@ -1 +0,0 @@ -Fix `os.sendfile()` on illumos. diff --git a/Misc/NEWS.d/next/Library/2020-11-10-15-40-56.bpo-42014.ShM37l.rst b/Misc/NEWS.d/next/Library/2020-11-10-15-40-56.bpo-42014.ShM37l.rst deleted file mode 100644 index d3e1abcd84c1e8..00000000000000 --- a/Misc/NEWS.d/next/Library/2020-11-10-15-40-56.bpo-42014.ShM37l.rst +++ /dev/null @@ -1 +0,0 @@ -The ``onerror`` callback from ``shutil.rmtree`` now receives correct function when ``os.open`` fails. \ No newline at end of file diff --git a/Misc/NEWS.d/next/Library/2020-11-13-18-53-50.bpo-42350.rsql7V.rst b/Misc/NEWS.d/next/Library/2020-11-13-18-53-50.bpo-42350.rsql7V.rst deleted file mode 100644 index 090ea2266633e6..00000000000000 --- a/Misc/NEWS.d/next/Library/2020-11-13-18-53-50.bpo-42350.rsql7V.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix the :class:`threading.Thread` class at fork: do nothing if the thread is -already stopped (ex: fork called at Python exit). Previously, an error was -logged in the child process. diff --git a/Misc/NEWS.d/next/Library/2020-11-15-15-23-34.bpo-42345.hiIR7x.rst b/Misc/NEWS.d/next/Library/2020-11-15-15-23-34.bpo-42345.hiIR7x.rst deleted file mode 100644 index 6339182c3ae727..00000000000000 --- a/Misc/NEWS.d/next/Library/2020-11-15-15-23-34.bpo-42345.hiIR7x.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix various issues with ``typing.Literal`` parameter handling (flatten, -deduplicate, use type to cache key). Patch provided by Yurii Karabas. diff --git a/Misc/NEWS.d/next/Library/2020-11-15-17-02-00.bpo-42328.bqpPlR.rst b/Misc/NEWS.d/next/Library/2020-11-15-17-02-00.bpo-42328.bqpPlR.rst deleted file mode 100644 index 7e6a176c889412..00000000000000 --- a/Misc/NEWS.d/next/Library/2020-11-15-17-02-00.bpo-42328.bqpPlR.rst +++ /dev/null @@ -1,4 +0,0 @@ -Fixed :meth:`tkinter.ttk.Style.map`. The function accepts now the -representation of the default state as empty sequence (as returned by -``Style.map()``). The structure of the result is now the same on all platform -and does not depend on the value of ``wantobjects``. diff --git a/Misc/NEWS.d/next/Security/2020-05-28-06-06-47.bpo-40791.QGZClX.rst b/Misc/NEWS.d/next/Security/2020-05-28-06-06-47.bpo-40791.QGZClX.rst deleted file mode 100644 index 69b9de1beae0d1..00000000000000 --- a/Misc/NEWS.d/next/Security/2020-05-28-06-06-47.bpo-40791.QGZClX.rst +++ /dev/null @@ -1 +0,0 @@ -Add ``volatile`` to the accumulator variable in ``hmac.compare_digest``, making constant-time-defeating optimizations less likely. \ No newline at end of file diff --git a/Misc/NEWS.d/next/Security/2020-10-19-10-56-27.bpo-42051.EU_B7u.rst b/Misc/NEWS.d/next/Security/2020-10-19-10-56-27.bpo-42051.EU_B7u.rst deleted file mode 100644 index e865ed12a03878..00000000000000 --- a/Misc/NEWS.d/next/Security/2020-10-19-10-56-27.bpo-42051.EU_B7u.rst +++ /dev/null @@ -1,3 +0,0 @@ -The :mod:`plistlib` module no longer accepts entity declarations in XML -plist files to avoid XML vulnerabilities. This should not affect users as -entity declarations are not used in regular plist files. diff --git a/Misc/NEWS.d/next/Security/2020-10-23-19-19-30.bpo-42103.cILT66.rst b/Misc/NEWS.d/next/Security/2020-10-23-19-19-30.bpo-42103.cILT66.rst deleted file mode 100644 index 15d7b6549ed465..00000000000000 --- a/Misc/NEWS.d/next/Security/2020-10-23-19-19-30.bpo-42103.cILT66.rst +++ /dev/null @@ -1,2 +0,0 @@ -Prevented potential DoS attack via CPU and RAM exhaustion when processing -malformed Apple Property List files in binary format. diff --git a/Misc/NEWS.d/next/Tests/2020-08-03-13-44-37.bpo-41306.VDoWXI.rst b/Misc/NEWS.d/next/Tests/2020-08-03-13-44-37.bpo-41306.VDoWXI.rst deleted file mode 100644 index 5e9ba2d8a27417..00000000000000 --- a/Misc/NEWS.d/next/Tests/2020-08-03-13-44-37.bpo-41306.VDoWXI.rst +++ /dev/null @@ -1 +0,0 @@ -Fixed a failure in ``test_tk.test_widgets.ScaleTest`` happening when executing the test with Tk 8.6.10. diff --git a/Misc/NEWS.d/next/Tests/2020-08-25-19-25-36.bpo-41602.Z64s0I.rst b/Misc/NEWS.d/next/Tests/2020-08-25-19-25-36.bpo-41602.Z64s0I.rst deleted file mode 100644 index fa3d2f1aa374ec..00000000000000 --- a/Misc/NEWS.d/next/Tests/2020-08-25-19-25-36.bpo-41602.Z64s0I.rst +++ /dev/null @@ -1 +0,0 @@ -Add tests for SIGINT handling in the runpy module. diff --git a/Misc/NEWS.d/next/Tests/2020-09-18-16-14-03.bpo-41561.uPnwrW.rst b/Misc/NEWS.d/next/Tests/2020-09-18-16-14-03.bpo-41561.uPnwrW.rst deleted file mode 100644 index 10bce825961c3c..00000000000000 --- a/Misc/NEWS.d/next/Tests/2020-09-18-16-14-03.bpo-41561.uPnwrW.rst +++ /dev/null @@ -1 +0,0 @@ -test_ssl: skip test_min_max_version_mismatch when TLS 1.0 is not available diff --git a/Misc/NEWS.d/next/Tests/2020-10-05-09-37-43.bpo-41939.P4OlbA.rst b/Misc/NEWS.d/next/Tests/2020-10-05-09-37-43.bpo-41939.P4OlbA.rst deleted file mode 100644 index e58ad2616da1ba..00000000000000 --- a/Misc/NEWS.d/next/Tests/2020-10-05-09-37-43.bpo-41939.P4OlbA.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix test_site.test_license_exists_at_url(): call -``urllib.request.urlcleanup()`` to reset the global -``urllib.request._opener``. Patch by Victor Stinner. diff --git a/Misc/NEWS.d/next/Tests/2020-10-05-17-43-46.bpo-41944.rf1dYb.rst b/Misc/NEWS.d/next/Tests/2020-10-05-17-43-46.bpo-41944.rf1dYb.rst deleted file mode 100644 index 4f9782f1c85af9..00000000000000 --- a/Misc/NEWS.d/next/Tests/2020-10-05-17-43-46.bpo-41944.rf1dYb.rst +++ /dev/null @@ -1 +0,0 @@ -Tests for CJK codecs no longer call ``eval()`` on content received via HTTP. diff --git a/Misc/NEWS.d/next/Tests/2020-10-08-14-00-17.bpo-41970.aZ8QFf.rst b/Misc/NEWS.d/next/Tests/2020-10-08-14-00-17.bpo-41970.aZ8QFf.rst deleted file mode 100644 index 4cdca197fbfc64..00000000000000 --- a/Misc/NEWS.d/next/Tests/2020-10-08-14-00-17.bpo-41970.aZ8QFf.rst +++ /dev/null @@ -1,2 +0,0 @@ -Avoid a test failure in ``test_lib2to3`` if the module has already imported -at the time the test executes. Patch by Pablo Galindo. diff --git a/Misc/NEWS.d/next/Tests/2020-10-12-00-11-47.bpo-41739.wSCc4K.rst b/Misc/NEWS.d/next/Tests/2020-10-12-00-11-47.bpo-41739.wSCc4K.rst deleted file mode 100644 index 7aee2b94444727..00000000000000 --- a/Misc/NEWS.d/next/Tests/2020-10-12-00-11-47.bpo-41739.wSCc4K.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix test_logging.test_race_between_set_target_and_flush(): the test now -waits until all threads complete to avoid leaking running threads. diff --git a/Misc/NEWS.d/next/Tests/2020-11-13-21-51-34.bpo-40754.Ekoxkg.rst b/Misc/NEWS.d/next/Tests/2020-11-13-21-51-34.bpo-40754.Ekoxkg.rst deleted file mode 100644 index 4bd423b54a4499..00000000000000 --- a/Misc/NEWS.d/next/Tests/2020-11-13-21-51-34.bpo-40754.Ekoxkg.rst +++ /dev/null @@ -1 +0,0 @@ -Include ``_testinternalcapi`` module in Windows installer for test suite diff --git a/Misc/NEWS.d/next/Windows/2020-05-30-02-46-43.bpo-38324.476M-5.rst b/Misc/NEWS.d/next/Windows/2020-05-30-02-46-43.bpo-38324.476M-5.rst deleted file mode 100644 index c45aa13091429e..00000000000000 --- a/Misc/NEWS.d/next/Windows/2020-05-30-02-46-43.bpo-38324.476M-5.rst +++ /dev/null @@ -1 +0,0 @@ -Avoid Unicode errors when accessing certain locale data on Windows. diff --git a/Misc/NEWS.d/next/Windows/2020-08-26-09-35-06.bpo-41557.vt00cQ.rst b/Misc/NEWS.d/next/Windows/2020-08-26-09-35-06.bpo-41557.vt00cQ.rst deleted file mode 100644 index 9d85461f00923f..00000000000000 --- a/Misc/NEWS.d/next/Windows/2020-08-26-09-35-06.bpo-41557.vt00cQ.rst +++ /dev/null @@ -1 +0,0 @@ -Update Windows installer to use SQLite 3.33.0. diff --git a/Misc/NEWS.d/next/Windows/2020-09-11-17-59-33.bpo-41744.e_ugDQ.rst b/Misc/NEWS.d/next/Windows/2020-09-11-17-59-33.bpo-41744.e_ugDQ.rst deleted file mode 100644 index 6106d6604c7dd5..00000000000000 --- a/Misc/NEWS.d/next/Windows/2020-09-11-17-59-33.bpo-41744.e_ugDQ.rst +++ /dev/null @@ -1 +0,0 @@ -Fixes automatic import of props file when using the Nuget package. \ No newline at end of file diff --git a/Misc/NEWS.d/next/Windows/2020-10-20-13-19-42.bpo-38439.eMLi-t.rst b/Misc/NEWS.d/next/Windows/2020-10-20-13-19-42.bpo-38439.eMLi-t.rst deleted file mode 100644 index acbc80c10f5e23..00000000000000 --- a/Misc/NEWS.d/next/Windows/2020-10-20-13-19-42.bpo-38439.eMLi-t.rst +++ /dev/null @@ -1 +0,0 @@ -Updates the icons for IDLE in the Windows Store package. diff --git a/Misc/NEWS.d/next/Windows/2020-11-16-22-41-02.bpo-42120.9scgko.rst b/Misc/NEWS.d/next/Windows/2020-11-16-22-41-02.bpo-42120.9scgko.rst deleted file mode 100644 index c574956d11d932..00000000000000 --- a/Misc/NEWS.d/next/Windows/2020-11-16-22-41-02.bpo-42120.9scgko.rst +++ /dev/null @@ -1 +0,0 @@ -Remove macro definition of ``copysign`` (to ``_copysign``) in headers. diff --git a/Misc/NEWS.d/next/macOS/2020-08-26-09-31-37.bpo-41557.mcQ75z.rst b/Misc/NEWS.d/next/macOS/2020-08-26-09-31-37.bpo-41557.mcQ75z.rst deleted file mode 100644 index 5f2d9937c0606d..00000000000000 --- a/Misc/NEWS.d/next/macOS/2020-08-26-09-31-37.bpo-41557.mcQ75z.rst +++ /dev/null @@ -1 +0,0 @@ -Update macOS installer to use SQLite 3.33.0. diff --git a/Misc/NEWS.d/next/macOS/2020-10-19-12-25-19.bpo-41471.gwA7un.rst b/Misc/NEWS.d/next/macOS/2020-10-19-12-25-19.bpo-41471.gwA7un.rst deleted file mode 100644 index db5dd00b19b0d4..00000000000000 --- a/Misc/NEWS.d/next/macOS/2020-10-19-12-25-19.bpo-41471.gwA7un.rst +++ /dev/null @@ -1 +0,0 @@ -Ignore invalid prefix lengths in system proxy excludes. diff --git a/Misc/NEWS.d/next/macOS/2020-10-23-10-26-53.bpo-38443.vu64tl.rst b/Misc/NEWS.d/next/macOS/2020-10-23-10-26-53.bpo-38443.vu64tl.rst deleted file mode 100644 index 008c972e5c6ab0..00000000000000 --- a/Misc/NEWS.d/next/macOS/2020-10-23-10-26-53.bpo-38443.vu64tl.rst +++ /dev/null @@ -1,2 +0,0 @@ -The ``--enable-universalsdk`` and ``--with-universal-archs`` options for the -configure script now check that the specified architectures can be used. diff --git a/Misc/NEWS.d/next/macOS/2020-11-01-16-40-23.bpo-41100.BApztP.rst b/Misc/NEWS.d/next/macOS/2020-11-01-16-40-23.bpo-41100.BApztP.rst deleted file mode 100644 index 6cbb279e7625ea..00000000000000 --- a/Misc/NEWS.d/next/macOS/2020-11-01-16-40-23.bpo-41100.BApztP.rst +++ /dev/null @@ -1,8 +0,0 @@ -Add support for macOS 11 and Apple Silicon systems. - -It is now possible to build "Universal 2" binaries using -"--enable-universalsdk --with-universal-archs=universal2". - -Binaries build on later macOS versions can be deployed back to older -versions (tested up to macOS 10.9), when using the correct deployment -target. This is tested using Xcode 11 and later. diff --git a/Misc/NEWS.d/next/macOS/2020-11-15-16-43-45.bpo-41116.oCkbrF.rst b/Misc/NEWS.d/next/macOS/2020-11-15-16-43-45.bpo-41116.oCkbrF.rst deleted file mode 100644 index c982224e92d719..00000000000000 --- a/Misc/NEWS.d/next/macOS/2020-11-15-16-43-45.bpo-41116.oCkbrF.rst +++ /dev/null @@ -1 +0,0 @@ -Ensure distutils.unixxcompiler.find_library_file can find system provided libraries on macOS 11. \ No newline at end of file diff --git a/README.rst b/README.rst index 64885138f8b31b..18dd74caf23a6c 100644 --- a/README.rst +++ b/README.rst @@ -1,5 +1,5 @@ -This is Python version 3.9.0 -============================ +This is Python version 3.9.1rc1 +=============================== .. image:: https://travis-ci.org/python/cpython.svg?branch=3.9 :alt: CPython build status on Travis CI From 543724b972c27626d9e5bc6a644dcf2db22c96b2 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 24 Nov 2020 22:47:17 -0800 Subject: [PATCH 0742/1314] Add doctests to the descriptor HowTo (GH-23500) (GH-23505) --- Doc/howto/descriptor.rst | 454 ++++++++++++++++++++++++++++++++++----- 1 file changed, 397 insertions(+), 57 deletions(-) diff --git a/Doc/howto/descriptor.rst b/Doc/howto/descriptor.rst index 8c6e90319a7f36..e94f0ef88416ed 100644 --- a/Doc/howto/descriptor.rst +++ b/Doc/howto/descriptor.rst @@ -43,21 +43,26 @@ Simple example: A descriptor that returns a constant ---------------------------------------------------- The :class:`Ten` class is a descriptor that always returns the constant ``10`` -from its :meth:`__get__` method:: +from its :meth:`__get__` method: +.. testcode:: class Ten: def __get__(self, obj, objtype=None): return 10 -To use the descriptor, it must be stored as a class variable in another class:: +To use the descriptor, it must be stored as a class variable in another class: + +.. testcode:: class A: x = 5 # Regular class attribute y = Ten() # Descriptor instance An interactive session shows the difference between normal attribute lookup -and descriptor lookup:: +and descriptor lookup: + +.. doctest:: >>> a = A() # Make an instance of class A >>> a.x # Normal attribute lookup @@ -83,7 +88,9 @@ Dynamic lookups --------------- Interesting descriptors typically run computations instead of returning -constants:: +constants: + +.. testcode:: import os @@ -131,7 +138,9 @@ the public attribute is accessed. In the following example, *age* is the public attribute and *_age* is the private attribute. When the public attribute is accessed, the descriptor logs -the lookup or update:: +the lookup or update: + +.. testcode:: import logging @@ -201,7 +210,9 @@ variable name was used. In this example, the :class:`Person` class has two descriptor instances, *name* and *age*. When the :class:`Person` class is defined, it makes a callback to :meth:`__set_name__` in *LoggedAccess* so that the field names can -be recorded, giving each descriptor its own *public_name* and *private_name*:: +be recorded, giving each descriptor its own *public_name* and *private_name*: + +.. testcode:: import logging @@ -236,7 +247,9 @@ be recorded, giving each descriptor its own *public_name* and *private_name*:: An interactive session shows that the :class:`Person` class has called :meth:`__set_name__` so that the field names would be recorded. Here -we call :func:`vars` to look up the descriptor without triggering it:: +we call :func:`vars` to look up the descriptor without triggering it: + +.. doctest:: >>> vars(vars(Person)['name']) {'public_name': 'name', 'private_name': '_name'} @@ -307,7 +320,9 @@ restrictions. If those restrictions aren't met, it raises an exception to prevent data corruption at its source. This :class:`Validator` class is both an :term:`abstract base class` and a -managed attribute descriptor:: +managed attribute descriptor: + +.. testcode:: from abc import ABC, abstractmethod @@ -347,7 +362,7 @@ Here are three practical data validation utilities: user-defined `predicate `_ as well. -:: +.. testcode:: class OneOf(Validator): @@ -400,10 +415,12 @@ Here are three practical data validation utilities: ) -Practical use -------------- +Practical application +--------------------- + +Here's how the data validators can be used in a real class: -Here's how the data validators can be used in a real class:: +.. testcode:: class Component: @@ -418,11 +435,26 @@ Here's how the data validators can be used in a real class:: The descriptors prevent invalid instances from being created:: - Component('WIDGET', 'metal', 5) # Allowed. - Component('Widget', 'metal', 5) # Blocked: 'Widget' is not all uppercase - Component('WIDGET', 'metle', 5) # Blocked: 'metle' is misspelled - Component('WIDGET', 'metal', -5) # Blocked: -5 is negative - Component('WIDGET', 'metal', 'V') # Blocked: 'V' isn't a number + >>> Component('Widget', 'metal', 5) # Blocked: 'Widget' is not all uppercase + Traceback (most recent call last): + ... + ValueError: Expected to be true for 'Widget' + + >>> Component('WIDGET', 'metle', 5) # Blocked: 'metle' is misspelled + Traceback (most recent call last): + ... + ValueError: Expected 'metle' to be one of {'metal', 'plastic', 'wood'} + + >>> Component('WIDGET', 'metal', -5) # Blocked: -5 is negative + Traceback (most recent call last): + ... + ValueError: Expected -5 to be at least 0 + >>> Component('WIDGET', 'metal', 'V') # Blocked: 'V' isn't a number + Traceback (most recent call last): + ... + TypeError: Expected 'V' to be an int or float + + >>> c = Component('WIDGET', 'metal', 5) # Allowed: The inputs are valid Technical Tutorial @@ -526,7 +558,9 @@ If a descriptor is found for ``a.x``, then it is invoked with: ``desc.__get__(a, type(a))``. The logic for a dotted lookup is in :meth:`object.__getattribute__`. Here is -a pure Python equivalent:: +a pure Python equivalent: + +.. testcode:: def object_getattribute(obj, name): "Emulate PyObject_GenericGetAttr() in Objects/object.c" @@ -546,9 +580,108 @@ a pure Python equivalent:: return cls_var # class variable raise AttributeError(name) + +.. testcode:: + :hide: + + # Test the fidelity of object_getattribute() by comparing it with the + # normal object.__getattribute__(). The former will be accessed by + # square brackets and the latter by the dot operator. + + class Object: + + def __getitem__(obj, name): + try: + return object_getattribute(obj, name) + except AttributeError: + if not hasattr(type(obj), '__getattr__'): + raise + return type(obj).__getattr__(obj, name) # __getattr__ + + class DualOperator(Object): + + x = 10 + + def __init__(self, z): + self.z = z + + @property + def p2(self): + return 2 * self.x + + @property + def p3(self): + return 3 * self.x + + def m5(self, y): + return 5 * y + + def m7(self, y): + return 7 * y + + def __getattr__(self, name): + return ('getattr_hook', self, name) + + class DualOperatorWithSlots: + + __getitem__ = Object.__getitem__ + + __slots__ = ['z'] + + x = 15 + + def __init__(self, z): + self.z = z + + @property + def p2(self): + return 2 * self.x + + def m5(self, y): + return 5 * y + + def __getattr__(self, name): + return ('getattr_hook', self, name) + + +.. doctest:: + :hide: + + >>> a = DualOperator(11) + >>> vars(a).update(p3 = '_p3', m7 = '_m7') + >>> a.x == a['x'] == 10 + True + >>> a.z == a['z'] == 11 + True + >>> a.p2 == a['p2'] == 20 + True + >>> a.p3 == a['p3'] == 30 + True + >>> a.m5(100) == a.m5(100) == 500 + True + >>> a.m7 == a['m7'] == '_m7' + True + >>> a.g == a['g'] == ('getattr_hook', a, 'g') + True + + >>> b = DualOperatorWithSlots(22) + >>> b.x == b['x'] == 15 + True + >>> b.z == b['z'] == 22 + True + >>> b.p2 == b['p2'] == 30 + True + >>> b.m5(200) == b['m5'](200) == 1000 + True + >>> b.g == b['g'] == ('getattr_hook', b, 'g') + True + + Interestingly, attribute lookup doesn't call :meth:`object.__getattribute__` directly. Instead, both the dot operator and the :func:`getattr` function -perform attribute lookup by way of a helper function:: +perform attribute lookup by way of a helper function: + +.. testcode:: def getattr_hook(obj, name): "Emulate slot_tp_getattr_hook() in Objects/typeobject.c" @@ -650,7 +783,9 @@ be used to implement an `object relational mapping The essential idea is that the data is stored in an external database. The Python instances only hold keys to the database's tables. Descriptors take -care of lookups or updates:: +care of lookups or updates: + +.. testcode:: class Field: @@ -665,8 +800,11 @@ care of lookups or updates:: conn.execute(self.store, [value, obj.key]) conn.commit() -We can use the :class:`Field` class to define "models" that describe the schema -for each table in a database:: +We can use the :class:`Field` class to define `models +`_ that describe the schema for +each table in a database: + +.. testcode:: class Movie: table = 'Movies' # Table name @@ -687,12 +825,41 @@ for each table in a database:: def __init__(self, key): self.key = key -An interactive session shows how data is retrieved from the database and how -it can be updated:: +To use the models, first connect to the database:: >>> import sqlite3 >>> conn = sqlite3.connect('entertainment.db') +An interactive session shows how data is retrieved from the database and how +it can be updated: + +.. testsetup:: + + song_data = [ + ('Country Roads', 'John Denver', 1972), + ('Me and Bobby McGee', 'Janice Joplin', 1971), + ('Coal Miners Daughter', 'Loretta Lynn', 1970), + ] + + movie_data = [ + ('Star Wars', 'George Lucas', 1977), + ('Jaws', 'Steven Spielberg', 1975), + ('Aliens', 'James Cameron', 1986), + ] + + import sqlite3 + + conn = sqlite3.connect(':memory:') + conn.execute('CREATE TABLE Music (title text, artist text, year integer);') + conn.execute('CREATE INDEX MusicNdx ON Music (title);') + conn.executemany('INSERT INTO Music VALUES (?, ?, ?);', song_data) + conn.execute('CREATE TABLE Movies (title text, director text, year integer);') + conn.execute('CREATE INDEX MovieNdx ON Music (title);') + conn.executemany('INSERT INTO Movies VALUES (?, ?, ?);', movie_data) + conn.commit() + +.. doctest:: + >>> Movie('Star Wars').director 'George Lucas' >>> jaws = Movie('Jaws') @@ -724,7 +891,9 @@ triggers a function call upon access to an attribute. Its signature is:: property(fget=None, fset=None, fdel=None, doc=None) -> property -The documentation shows a typical use to define a managed attribute ``x``:: +The documentation shows a typical use to define a managed attribute ``x``: + +.. testcode:: class C: def getx(self): return self.__x @@ -733,7 +902,9 @@ The documentation shows a typical use to define a managed attribute ``x``:: x = property(getx, setx, delx, "I'm the 'x' property.") To see how :func:`property` is implemented in terms of the descriptor protocol, -here is a pure Python equivalent:: +here is a pure Python equivalent: + +.. testcode:: class Property: "Emulate PyProperty_Type() in Objects/descrobject.c" @@ -772,6 +943,57 @@ here is a pure Python equivalent:: def deleter(self, fdel): return type(self)(self.fget, self.fset, fdel, self.__doc__) +.. testcode:: + :hide: + + # Verify the Property() emulation + + class CC: + def getx(self): + return self.__x + def setx(self, value): + self.__x = value + def delx(self): + del self.__x + x = Property(getx, setx, delx, "I'm the 'x' property.") + + # Now do it again but use the decorator style + + class CCC: + @Property + def x(self): + return self.__x + @x.setter + def x(self, value): + self.__x = value + @x.deleter + def x(self): + del self.__x + + +.. doctest:: + :hide: + + >>> cc = CC() + >>> hasattr(cc, 'x') + False + >>> cc.x = 33 + >>> cc.x + 33 + >>> del cc.x + >>> hasattr(cc, 'x') + False + + >>> ccc = CCC() + >>> hasattr(ccc, 'x') + False + >>> ccc.x = 333 + >>> ccc.x == 333 + True + >>> del ccc.x + >>> hasattr(ccc, 'x') + False + The :func:`property` builtin helps whenever a user interface has granted attribute access and then subsequent changes require the intervention of a method. @@ -780,7 +1002,9 @@ For instance, a spreadsheet class may grant access to a cell value through ``Cell('b10').value``. Subsequent improvements to the program require the cell to be recalculated on every access; however, the programmer does not want to affect existing client code accessing the attribute directly. The solution is -to wrap access to the value attribute in a property data descriptor:: +to wrap access to the value attribute in a property data descriptor: + +.. testcode:: class Cell: ... @@ -791,6 +1015,9 @@ to wrap access to the value attribute in a property data descriptor:: self.recalc() return self._value +Either the built-in :func:`property` or our :func:`Property` equivalent would +work in this example. + Functions and methods --------------------- @@ -804,7 +1031,9 @@ prepended to the other arguments. By convention, the instance is called *self* but could be called *this* or any other variable name. Methods can be created manually with :class:`types.MethodType` which is -roughly equivalent to:: +roughly equivalent to: + +.. testcode:: class MethodType: "Emulate Py_MethodType in Objects/classobject.c" @@ -821,7 +1050,9 @@ roughly equivalent to:: To support automatic creation of methods, functions include the :meth:`__get__` method for binding methods during attribute access. This means that functions are non-data descriptors that return bound methods -during dotted lookup from an instance. Here's how it works:: +during dotted lookup from an instance. Here's how it works: + +.. testcode:: class Function: ... @@ -833,13 +1064,17 @@ during dotted lookup from an instance. Here's how it works:: return MethodType(self, obj) Running the following class in the interpreter shows how the function -descriptor works in practice:: +descriptor works in practice: + +.. testcode:: class D: def f(self, x): return x -The function has a :term:`qualified name` attribute to support introspection:: +The function has a :term:`qualified name` attribute to support introspection: + +.. doctest:: >>> D.f.__qualname__ 'D.f' @@ -867,7 +1102,7 @@ Internally, the bound method stores the underlying function and the bound instance:: >>> d.f.__func__ - + >>> d.f.__self__ <__main__.D object at 0x1012e1f98> @@ -919,20 +1154,26 @@ It can be called either from an object or the class: ``s.erf(1.5) --> .9332`` o ``Sample.erf(1.5) --> .9332``. Since static methods return the underlying function with no changes, the -example calls are unexciting:: +example calls are unexciting: + +.. testcode:: class E: @staticmethod def f(x): print(x) +.. doctest:: + >>> E.f(3) 3 >>> E().f(3) 3 Using the non-data descriptor protocol, a pure Python version of -:func:`staticmethod` would look like this:: +:func:`staticmethod` would look like this: + +.. doctest:: class StaticMethod: "Emulate PyStaticMethod_Type() in Objects/funcobject.c" @@ -949,27 +1190,31 @@ Class methods Unlike static methods, class methods prepend the class reference to the argument list before calling the function. This format is the same -for whether the caller is an object or a class:: +for whether the caller is an object or a class: + +.. testcode:: class F: @classmethod def f(cls, x): return cls.__name__, x - >>> print(F.f(3)) +.. doctest:: + + >>> F.f(3) ('F', 3) - >>> print(F().f(3)) + >>> F().f(3) ('F', 3) This behavior is useful whenever the method only needs to have a class reference and does rely on data stored in a specific instance. One use for class methods is to create alternate class constructors. For example, the classmethod :func:`dict.fromkeys` creates a new dictionary from a list of -keys. The pure Python equivalent is:: +keys. The pure Python equivalent is: - class Dict: - ... +.. testcode:: + class Dict(dict): @classmethod def fromkeys(cls, iterable, value=None): "Emulate dict_fromkeys() in Objects/dictobject.c" @@ -978,13 +1223,17 @@ keys. The pure Python equivalent is:: d[key] = value return d -Now a new dictionary of unique keys can be constructed like this:: +Now a new dictionary of unique keys can be constructed like this: + +.. doctest:: >>> Dict.fromkeys('abracadabra') - {'a': None, 'r': None, 'b': None, 'c': None, 'd': None} + {'a': None, 'b': None, 'r': None, 'c': None, 'd': None} Using the non-data descriptor protocol, a pure Python version of -:func:`classmethod` would look like this:: +:func:`classmethod` would look like this: + +.. testcode:: class ClassMethod: "Emulate PyClassMethod_Type() in Objects/funcobject.c" @@ -999,9 +1248,31 @@ Using the non-data descriptor protocol, a pure Python version of return self.f.__get__(cls) return MethodType(self.f, cls) +.. testcode:: + :hide: + + # Verify the emulation works + class T: + @ClassMethod + def cm(cls, x, y): + return (cls, x, y) + +.. doctest:: + :hide: + + >>> T.cm(11, 22) + (, 11, 22) + + # Also call it from an instance + >>> t = T() + >>> t.cm(11, 22) + (, 11, 22) + The code path for ``hasattr(obj, '__get__')`` was added in Python 3.9 and makes it possible for :func:`classmethod` to support chained decorators. -For example, a classmethod and property could be chained together:: +For example, a classmethod and property could be chained together: + +.. testcode:: class G: @classmethod @@ -1009,6 +1280,12 @@ For example, a classmethod and property could be chained together:: def __doc__(cls): return f'A doc for {cls.__name__!r}' +.. doctest:: + + >>> G.__doc__ + "A doc for 'G'" + + Member objects and __slots__ ---------------------------- @@ -1017,11 +1294,15 @@ fixed-length array of slot values. From a user point of view that has several effects: 1. Provides immediate detection of bugs due to misspelled attribute -assignments. Only attribute names specified in ``__slots__`` are allowed:: +assignments. Only attribute names specified in ``__slots__`` are allowed: + +.. testcode:: class Vehicle: __slots__ = ('id_number', 'make', 'model') +.. doctest:: + >>> auto = Vehicle() >>> auto.id_nubmer = 'VYE483814LQEX' Traceback (most recent call last): @@ -1029,7 +1310,9 @@ assignments. Only attribute names specified in ``__slots__`` are allowed:: AttributeError: 'Vehicle' object has no attribute 'id_nubmer' 2. Helps create immutable objects where descriptors manage access to private -attributes stored in ``__slots__``:: +attributes stored in ``__slots__``: + +.. testcode:: class Immutable: @@ -1047,7 +1330,19 @@ attributes stored in ``__slots__``:: def name(self): # Read-only descriptor return self._name - mark = Immutable('Botany', 'Mark Watney') # Create an immutable instance +.. doctest:: + + >>> mark = Immutable('Botany', 'Mark Watney') + >>> mark.dept + 'Botany' + >>> mark.dept = 'Space Pirate' + Traceback (most recent call last): + ... + AttributeError: can't set attribute + >>> mark.location = 'Mars' + Traceback (most recent call last): + ... + AttributeError: 'Immutable' object has no attribute 'location' 3. Saves memory. On a 64-bit Linux build, an instance with two attributes takes 48 bytes with ``__slots__`` and 152 bytes without. This `flyweight @@ -1055,7 +1350,9 @@ design pattern `_ likely only matters when a large number of instances are going to be created. 4. Blocks tools like :func:`functools.cached_property` which require an -instance dictionary to function correctly:: +instance dictionary to function correctly: + +.. testcode:: from functools import cached_property @@ -1067,17 +1364,21 @@ instance dictionary to function correctly:: return 4 * sum((-1.0)**n / (2.0*n + 1.0) for n in reversed(range(100_000))) +.. doctest:: + >>> CP().pi Traceback (most recent call last): ... TypeError: No '__dict__' attribute on 'CP' instance to cache 'pi' property. -It's not possible to create an exact drop-in pure Python version of +It is not possible to create an exact drop-in pure Python version of ``__slots__`` because it requires direct access to C structures and control over object memory allocation. However, we can build a mostly faithful simulation where the actual C structure for slots is emulated by a private ``_slotvalues`` list. Reads and writes to that private structure are managed -by member descriptors:: +by member descriptors: + +.. testcode:: null = object() @@ -1114,7 +1415,9 @@ by member descriptors:: return f'' The :meth:`type.__new__` method takes care of adding member objects to class -variables:: +variables: + +.. testcode:: class Type(type): 'Simulate how the type metaclass adds member objects for slots' @@ -1129,7 +1432,9 @@ variables:: The :meth:`object.__new__` method takes care of creating instances that have slots instead of an instance dictionary. Here is a rough simulation in pure -Python:: +Python: + +.. testcode:: class Object: 'Simulate how object.__new__() allocates memory for __slots__' @@ -1161,7 +1466,9 @@ Python:: super().__delattr__(name) To use the simulation in a real class, just inherit from :class:`Object` and -set the :term:`metaclass` to :class:`Type`:: +set the :term:`metaclass` to :class:`Type`: + +.. testcode:: class H(Object, metaclass=Type): 'Instance variables stored in slots' @@ -1174,8 +1481,8 @@ set the :term:`metaclass` to :class:`Type`:: At this point, the metaclass has loaded member objects for *x* and *y*:: - >>> import pprint - >>> pprint.pp(dict(vars(H))) + >>> from pprint import pp + >>> pp(dict(vars(H))) {'__module__': '__main__', '__doc__': 'Instance variables stored in slots', 'slot_names': ['x', 'y'], @@ -1183,8 +1490,20 @@ At this point, the metaclass has loaded member objects for *x* and *y*:: 'x': , 'y': } +.. doctest:: + :hide: + + # We test this separately because the preceding section is not + # doctestable due to the hex memory address for the __init__ function + >>> isinstance(vars(H)['x'], Member) + True + >>> isinstance(vars(H)['y'], Member) + True + When instances are created, they have a ``slot_values`` list where the -attributes are stored:: +attributes are stored: + +.. doctest:: >>> h = H(10, 20) >>> vars(h) @@ -1193,9 +1512,30 @@ attributes are stored:: >>> vars(h) {'_slotvalues': [55, 20]} -Misspelled or unassigned attributes will raise an exception:: +Misspelled or unassigned attributes will raise an exception: + +.. doctest:: >>> h.xz Traceback (most recent call last): ... AttributeError: 'H' object has no attribute 'xz' + +.. doctest:: + :hide: + + # Examples for deleted attributes are not shown because this section + # is already a bit lengthy. We still test that code here. + >>> del h.x + >>> hasattr(h, 'x') + False + + # Also test the code for uninitialized slots + >>> class HU(Object, metaclass=Type): + ... slot_names = ['x', 'y'] + ... + >>> hu = HU() + >>> hasattr(hu, 'x') + False + >>> hasattr(hu, 'y') + False From 9d2c2a8e3b8fe18ee1568bfa4a419847b3e78575 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 25 Nov 2020 01:52:51 -0800 Subject: [PATCH 0743/1314] bpo-12800: tarfile: Restore fix from 011525ee9 (GH-21409) Restore fix from 011525ee92eb1c13ad1a62d28725a840e28f8160. (cherry picked from commit 4fedd7123eaf147edd55eabbbd72e0bcc8368e47) Co-authored-by: Julien Palard --- Lib/tarfile.py | 3 +++ Lib/test/test_tarfile.py | 6 +++--- .../next/Library/2020-07-09-11-32-28.bpo-12800.fNgWwx.rst | 4 ++++ 3 files changed, 10 insertions(+), 3 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2020-07-09-11-32-28.bpo-12800.fNgWwx.rst diff --git a/Lib/tarfile.py b/Lib/tarfile.py index e42279470dac65..1d15612616f1d8 100755 --- a/Lib/tarfile.py +++ b/Lib/tarfile.py @@ -2237,6 +2237,9 @@ def makelink(self, tarinfo, targetpath): try: # For systems that support symbolic and hard links. if tarinfo.issym(): + if os.path.lexists(targetpath): + # Avoid FileExistsError on following os.symlink. + os.unlink(targetpath) os.symlink(tarinfo.linkname, targetpath) else: # See extract(). diff --git a/Lib/test/test_tarfile.py b/Lib/test/test_tarfile.py index 1e5186a90b37f9..29cde91bf7fc13 100644 --- a/Lib/test/test_tarfile.py +++ b/Lib/test/test_tarfile.py @@ -1346,10 +1346,10 @@ def test_extractall_symlinks(self): f.write('something\n') os.symlink(source_file, target_file) with tarfile.open(temparchive, 'w') as tar: - tar.add(source_file) - tar.add(target_file) + tar.add(source_file, arcname="source") + tar.add(target_file, arcname="symlink") # Let's extract it to the location which contains the symlink - with tarfile.open(temparchive) as tar: + with tarfile.open(temparchive, errorlevel=2) as tar: # this should not raise OSError: [Errno 17] File exists try: tar.extractall(path=tempdir) diff --git a/Misc/NEWS.d/next/Library/2020-07-09-11-32-28.bpo-12800.fNgWwx.rst b/Misc/NEWS.d/next/Library/2020-07-09-11-32-28.bpo-12800.fNgWwx.rst new file mode 100644 index 00000000000000..fdd7c5e74f33a3 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2020-07-09-11-32-28.bpo-12800.fNgWwx.rst @@ -0,0 +1,4 @@ +Extracting a symlink from a tarball should succeed and overwrite the symlink +if it already exists. The fix is to remove the existing file or symlink +before extraction. Based on patch by Chris AtLee, Jeffrey Kintscher, and +Senthil Kumaran. From 0aedcff34cc2a3358db5f128f714bcb077aa649c Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 25 Nov 2020 02:16:32 -0800 Subject: [PATCH 0744/1314] Add more tests to the descriptor howto guide (GH-23506) (GH-23510) --- Doc/howto/descriptor.rst | 29 +++++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/Doc/howto/descriptor.rst b/Doc/howto/descriptor.rst index e94f0ef88416ed..bc741c738b98da 100644 --- a/Doc/howto/descriptor.rst +++ b/Doc/howto/descriptor.rst @@ -170,7 +170,15 @@ the lookup or update: An interactive session shows that all access to the managed attribute *age* is -logged, but that the regular attribute *name* is not logged:: +logged, but that the regular attribute *name* is not logged: + +.. testcode:: + :hide: + + import logging, sys + logging.basicConfig(level=logging.INFO, stream=sys.stdout, force=True) + +.. doctest:: >>> mary = Person('Mary M', 30) # The initial age update is logged INFO:root:Updating 'age' to 30 @@ -256,7 +264,15 @@ we call :func:`vars` to look up the descriptor without triggering it: >>> vars(vars(Person)['age']) {'public_name': 'age', 'private_name': '_age'} -The new class now logs access to both *name* and *age*:: +The new class now logs access to both *name* and *age*: + +.. testcode:: + :hide: + + import logging, sys + logging.basicConfig(level=logging.INFO, stream=sys.stdout, force=True) + +.. doctest:: >>> pete = Person('Peter P', 10) INFO:root:Updating 'name' to 'Peter P' @@ -433,7 +449,9 @@ Here's how the data validators can be used in a real class: self.kind = kind self.quantity = quantity -The descriptors prevent invalid instances from being created:: +The descriptors prevent invalid instances from being created: + +.. doctest:: >>> Component('Widget', 'metal', 5) # Blocked: 'Widget' is not all uppercase Traceback (most recent call last): @@ -1227,7 +1245,10 @@ Now a new dictionary of unique keys can be constructed like this: .. doctest:: - >>> Dict.fromkeys('abracadabra') + >>> d = Dict.fromkeys('abracadabra') + >>> type(d) is Dict + True + >>> d {'a': None, 'b': None, 'r': None, 'c': None, 'd': None} Using the non-data descriptor protocol, a pure Python version of From dca61e770d6c423a183325b7a3708b8aae9e062d Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 25 Nov 2020 12:14:32 -0800 Subject: [PATCH 0745/1314] Typo: fix inverted sense of statement (GH-23288) (GH-23512) --- Doc/howto/descriptor.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/howto/descriptor.rst b/Doc/howto/descriptor.rst index bc741c738b98da..ab5a573c6a06d1 100644 --- a/Doc/howto/descriptor.rst +++ b/Doc/howto/descriptor.rst @@ -1225,7 +1225,7 @@ for whether the caller is an object or a class: ('F', 3) This behavior is useful whenever the method only needs to have a class -reference and does rely on data stored in a specific instance. One use for +reference and does not rely on data stored in a specific instance. One use for class methods is to create alternate class constructors. For example, the classmethod :func:`dict.fromkeys` creates a new dictionary from a list of keys. The pure Python equivalent is: From 761c5a1ce477b82cca35a79917c88d72d57ed776 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Langa?= Date: Thu, 26 Nov 2020 18:49:45 +0100 Subject: [PATCH 0746/1314] Post 3.9.1rc1 --- Include/patchlevel.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Include/patchlevel.h b/Include/patchlevel.h index 1a51847c5541d9..09db42f19fd760 100644 --- a/Include/patchlevel.h +++ b/Include/patchlevel.h @@ -23,7 +23,7 @@ #define PY_RELEASE_SERIAL 1 /* Version as a string */ -#define PY_VERSION "3.9.1rc1" +#define PY_VERSION "3.9.1rc1+" /*--end constants--*/ /* Version as a single 4-byte hex number, e.g. 0x010502B2 == 1.5.2b2. From df6c8bcffef3380869c8f76317610ce452880b25 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 28 Nov 2020 07:07:51 -0800 Subject: [PATCH 0747/1314] bpo-34215: Clarify IncompleteReadError message when "expected" is None (GH-21925) (GH-23539) Co-Authored-By: Tyler Bell (cherry picked from commit 8085f742f4adfbc85f13fc734dfab036aa23acfb) Co-authored-by: Zackery Spytz Co-authored-by: Zackery Spytz --- Lib/asyncio/exceptions.py | 3 ++- Lib/test/test_asyncio/test_streams.py | 8 +++++--- .../next/Library/2020-08-19-20-17-51.bpo-34215._Cv8c-.rst | 2 ++ 3 files changed, 9 insertions(+), 4 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2020-08-19-20-17-51.bpo-34215._Cv8c-.rst diff --git a/Lib/asyncio/exceptions.py b/Lib/asyncio/exceptions.py index e03602ef576234..f07e4486577381 100644 --- a/Lib/asyncio/exceptions.py +++ b/Lib/asyncio/exceptions.py @@ -34,8 +34,9 @@ class IncompleteReadError(EOFError): - expected: total number of expected bytes (or None if unknown) """ def __init__(self, partial, expected): + r_expected = 'undefined' if expected is None else repr(expected) super().__init__(f'{len(partial)} bytes read on a total of ' - f'{expected!r} expected bytes') + f'{r_expected} expected bytes') self.partial = partial self.expected = expected diff --git a/Lib/test/test_asyncio/test_streams.py b/Lib/test/test_asyncio/test_streams.py index 1e9d115661d087..71de82dfc7ebba 100644 --- a/Lib/test/test_asyncio/test_streams.py +++ b/Lib/test/test_asyncio/test_streams.py @@ -452,12 +452,14 @@ def test_readuntil_multi_chunks_1(self): def test_readuntil_eof(self): stream = asyncio.StreamReader(loop=self.loop) - stream.feed_data(b'some dataAA') + data = b'some dataAA' + stream.feed_data(data) stream.feed_eof() - with self.assertRaises(asyncio.IncompleteReadError) as cm: + with self.assertRaisesRegex(asyncio.IncompleteReadError, + 'undefined expected bytes') as cm: self.loop.run_until_complete(stream.readuntil(b'AAA')) - self.assertEqual(cm.exception.partial, b'some dataAA') + self.assertEqual(cm.exception.partial, data) self.assertIsNone(cm.exception.expected) self.assertEqual(b'', stream._buffer) diff --git a/Misc/NEWS.d/next/Library/2020-08-19-20-17-51.bpo-34215._Cv8c-.rst b/Misc/NEWS.d/next/Library/2020-08-19-20-17-51.bpo-34215._Cv8c-.rst new file mode 100644 index 00000000000000..4d91678948f40a --- /dev/null +++ b/Misc/NEWS.d/next/Library/2020-08-19-20-17-51.bpo-34215._Cv8c-.rst @@ -0,0 +1,2 @@ +Clarify the error message for :exc:`asyncio.IncompleteReadError` when +``expected`` is ``None``. From cc5eb935c79bae13def91965e5fb7e8346d9dea1 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 28 Nov 2020 07:14:23 -0800 Subject: [PATCH 0748/1314] bpo-42489: Fix the signature for list.sort() in the tutorial (GH-23538) (cherry picked from commit d41ec65ab7411e877ca33d05e8c900feca530635) Co-authored-by: Zackery Spytz --- Doc/tutorial/datastructures.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/tutorial/datastructures.rst b/Doc/tutorial/datastructures.rst index ff4c797f66cd63..5c6b65f05e1e5f 100644 --- a/Doc/tutorial/datastructures.rst +++ b/Doc/tutorial/datastructures.rst @@ -78,7 +78,7 @@ objects: Return the number of times *x* appears in the list. -.. method:: list.sort(key=None, reverse=False) +.. method:: list.sort(*, key=None, reverse=False) :noindex: Sort the items of the list in place (the arguments can be used for sort From 5d54dfadcf87998ae914ec64d7010ae7392924b2 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 28 Nov 2020 14:05:37 -0800 Subject: [PATCH 0749/1314] Fix multiprocessing markup (GH-23525) (cherry picked from commit 4b44472966f17ad96d4370569ae049de9873e4af) Co-authored-by: Andre Delfino --- Doc/library/multiprocessing.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Doc/library/multiprocessing.rst b/Doc/library/multiprocessing.rst index 046ed39caff5c9..ab84d39ed05163 100644 --- a/Doc/library/multiprocessing.rst +++ b/Doc/library/multiprocessing.rst @@ -2569,9 +2569,9 @@ Address Formats filesystem. * An ``'AF_PIPE'`` address is a string of the form - :samp:`r'\\\\.\\pipe\\{PipeName}'`. To use :func:`Client` to connect to a named - pipe on a remote computer called *ServerName* one should use an address of the - form :samp:`r'\\\\{ServerName}\\pipe\\{PipeName}'` instead. + :samp:`r'\\\\.\\pipe\\{PipeName}'`. To use :func:`Client` to connect to a named + pipe on a remote computer called *ServerName* one should use an address of the + form :samp:`r'\\\\{ServerName}\\pipe\\{PipeName}'` instead. Note that any string beginning with two backslashes is assumed by default to be an ``'AF_PIPE'`` address rather than an ``'AF_UNIX'`` address. From cfb2f796342c224599eeab847e8593343a775408 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 28 Nov 2020 14:06:05 -0800 Subject: [PATCH 0750/1314] Fix dis markup (GH-23524) (cherry picked from commit fa840cc81d61b936ef95fdf7509a11b5927dc585) Co-authored-by: Andre Delfino --- Doc/library/dis.rst | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Doc/library/dis.rst b/Doc/library/dis.rst index d0307bd8e9f3d0..c1e72d1d1633b5 100644 --- a/Doc/library/dis.rst +++ b/Doc/library/dis.rst @@ -861,7 +861,7 @@ All of the following opcodes use their arguments. .. opcode:: LIST_TO_TUPLE - Pops a list from the stack and pushes a tuple containing the same values. + Pops a list from the stack and pushes a tuple containing the same values. .. versionadded:: 3.9 @@ -889,7 +889,7 @@ All of the following opcodes use their arguments. .. opcode:: DICT_MERGE - Like :opcode:`DICT_UPDATE` but raises an exception for duplicate keys. + Like :opcode:`DICT_UPDATE` but raises an exception for duplicate keys. .. versionadded:: 3.9 @@ -907,14 +907,14 @@ All of the following opcodes use their arguments. .. opcode:: IS_OP (invert) - Performs ``is`` comparison, or ``is not`` if ``invert`` is 1. + Performs ``is`` comparison, or ``is not`` if ``invert`` is 1. .. versionadded:: 3.9 .. opcode:: CONTAINS_OP (invert) - Performs ``in`` comparison, or ``not in`` if ``invert`` is 1. + Performs ``in`` comparison, or ``not in`` if ``invert`` is 1. .. versionadded:: 3.9 @@ -955,8 +955,8 @@ All of the following opcodes use their arguments. .. opcode:: JUMP_IF_NOT_EXC_MATCH (target) - Tests whether the second value on the stack is an exception matching TOS, - and jumps if it is not. Pops two values from the stack. + Tests whether the second value on the stack is an exception matching TOS, + and jumps if it is not. Pops two values from the stack. .. versionadded:: 3.9 From cf47b3969e21f66655fcb414ff9bfdd503069c2d Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 29 Nov 2020 01:58:01 -0800 Subject: [PATCH 0751/1314] bpo-39096: Improve description of 'e', 'f' and 'g' presentation types (GH-23537) (GH-23550) * Improve description of 'e', 'f' and 'g' presentation types * Drop the 'E' from Scientific 'E' notation; remove >= 0 qualifications * Fix false statement that the alternate form is valid for Decimal * Nitpick: remove the Harvard/Oxford comma * Add note that the decimal point is also removed if no digits follow it, except in alternate form (cherry picked from commit c642374b3ef72f6f300616f07aea2a3f9ed83e51) Co-authored-by: Mark Dickinson Co-authored-by: Mark Dickinson --- Doc/library/string.rst | 43 ++++++++++++++++++++++++++++++------------ 1 file changed, 31 insertions(+), 12 deletions(-) diff --git a/Doc/library/string.rst b/Doc/library/string.rst index 91f43e9353d915..5542e9b727a6b8 100644 --- a/Doc/library/string.rst +++ b/Doc/library/string.rst @@ -384,10 +384,10 @@ following: The ``'#'`` option causes the "alternate form" to be used for the conversion. The alternate form is defined differently for different -types. This option is only valid for integer, float, complex and -Decimal types. For integers, when binary, octal, or hexadecimal output +types. This option is only valid for integer, float and complex +types. For integers, when binary, octal, or hexadecimal output is used, this option adds the prefix respective ``'0b'``, ``'0o'``, or -``'0x'`` to the output value. For floats, complex and Decimal the +``'0x'`` to the output value. For float and complex the alternate form causes the result of the conversion to always contain a decimal-point character, even if no digits follow it. Normally, a decimal-point character appears in the result of these conversions @@ -476,20 +476,36 @@ with the floating point presentation types listed below (except ``'n'`` and ``None``). When doing so, :func:`float` is used to convert the integer to a floating point number before formatting. -The available presentation types for floating point and decimal values are: +The available presentation types for :class:`float` and +:class:`~decimal.Decimal` values are: +---------+----------------------------------------------------------+ | Type | Meaning | +=========+==========================================================+ - | ``'e'`` | Exponent notation. Prints the number in scientific | - | | notation using the letter 'e' to indicate the exponent. | - | | The default precision is ``6``. | + | ``'e'`` | Scientific notation. For a given precision ``p``, | + | | formats the number in scientific notation with the | + | | letter 'e' separating the coefficient from the exponent. | + | | The coefficient has one digit before and ``p`` digits | + | | after the decimal point, for a total of ``p + 1`` | + | | significant digits. With no precision given, uses a | + | | precision of ``6`` digits after the decimal point for | + | | :class:`float`, and shows all coefficient digits | + | | for :class:`~decimal.Decimal`. If no digits follow the | + | | decimal point, the decimal point is also removed unless | + | | the ``#`` option is used. | +---------+----------------------------------------------------------+ - | ``'E'`` | Exponent notation. Same as ``'e'`` except it uses an | - | | upper case 'E' as the separator character. | + | ``'E'`` | Scientific notation. Same as ``'e'`` except it uses | + | | an upper case 'E' as the separator character. | +---------+----------------------------------------------------------+ - | ``'f'`` | Fixed-point notation. Displays the number as a | - | | fixed-point number. The default precision is ``6``. | + | ``'f'`` | Fixed-point notation. For a given precision ``p``, | + | | formats the number as a decimal number with exactly | + | | ``p`` digits following the decimal point. With no | + | | precision given, uses a precision of ``6`` digits after | + | | the decimal point for :class:`float`, and uses a | + | | precision large enough to show all coefficient digits | + | | for :class:`~decimal.Decimal`. If no digits follow the | + | | decimal point, the decimal point is also removed unless | + | | the ``#`` option is used. | +---------+----------------------------------------------------------+ | ``'F'`` | Fixed-point notation. Same as ``'f'``, but converts | | | ``nan`` to ``NAN`` and ``inf`` to ``INF``. | @@ -518,7 +534,10 @@ The available presentation types for floating point and decimal values are: | | the precision. | | | | | | A precision of ``0`` is treated as equivalent to a | - | | precision of ``1``. The default precision is ``6``. | + | | precision of ``1``. With no precision given, uses a | + | | precision of ``6`` significant digits for | + | | :class:`float`, and shows all coefficient digits | + | | for :class:`~decimal.Decimal`. | +---------+----------------------------------------------------------+ | ``'G'`` | General format. Same as ``'g'`` except switches to | | | ``'E'`` if the number gets too large. The | From fcf7391f598e027a083173662a3ecf7865251291 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 29 Nov 2020 10:47:31 -0800 Subject: [PATCH 0752/1314] bpo-42406: Fix whichmodule() with multiprocessing (GH-23403) * bpo-42406: Fix whichmodule() with multiprocessing Signed-off-by: Renato L. de F. Cunha Co-authored-by: Gregory P. Smith (cherry picked from commit 86684319d3dad8e1a7b0559727a48e0bc50afb01) Co-authored-by: Renato Cunha --- Lib/pickle.py | 4 +++- .../next/Library/2020-11-19-10-44-41.bpo-42406.r9rNCj.rst | 3 +++ 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Library/2020-11-19-10-44-41.bpo-42406.r9rNCj.rst diff --git a/Lib/pickle.py b/Lib/pickle.py index cbac5f168b45eb..e63a8b6e4dbb70 100644 --- a/Lib/pickle.py +++ b/Lib/pickle.py @@ -340,7 +340,9 @@ def whichmodule(obj, name): # Protect the iteration by using a list copy of sys.modules against dynamic # modules that trigger imports of other modules upon calls to getattr. for module_name, module in sys.modules.copy().items(): - if module_name == '__main__' or module is None: + if (module_name == '__main__' + or module_name == '__mp_main__' # bpo-42406 + or module is None): continue try: if _getattribute(module, name)[0] is obj: diff --git a/Misc/NEWS.d/next/Library/2020-11-19-10-44-41.bpo-42406.r9rNCj.rst b/Misc/NEWS.d/next/Library/2020-11-19-10-44-41.bpo-42406.r9rNCj.rst new file mode 100644 index 00000000000000..c157df138a5ea0 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2020-11-19-10-44-41.bpo-42406.r9rNCj.rst @@ -0,0 +1,3 @@ +We fixed an issue in `pickle.whichmodule` in which importing +`multiprocessing` could change the how pickle identifies which module an +object belongs to, potentially breaking the unpickling of those objects. From a83119d7be95dd3f5ff22abe289da6091584f853 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 29 Nov 2020 11:14:10 -0800 Subject: [PATCH 0753/1314] bpo-42450: Minor updates to the itertools recipes (GH-23555) (GH-23562) --- Doc/library/itertools.rst | 10 +++++----- Lib/test/test_itertools.py | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Doc/library/itertools.rst b/Doc/library/itertools.rst index 107bc515a67785..3de66c93492815 100644 --- a/Doc/library/itertools.rst +++ b/Doc/library/itertools.rst @@ -755,7 +755,7 @@ which incur interpreter overhead. "Count how many times the predicate is true" return sum(map(pred, iterable)) - def padnone(iterable): + def pad_none(iterable): """Returns the sequence elements and then returns None indefinitely. Useful for emulating the behavior of the built-in map() function. @@ -809,7 +809,7 @@ which incur interpreter overhead. nexts = cycle(islice(nexts, num_active)) def partition(pred, iterable): - 'Use a predicate to partition entries into false entries and true entries' + "Use a predicate to partition entries into false entries and true entries" # partition(is_odd, range(10)) --> 0 2 4 6 8 and 1 3 5 7 9 t1, t2 = tee(iterable) return filterfalse(pred, t1), filter(pred, t2) @@ -881,7 +881,7 @@ which incur interpreter overhead. def random_product(*args, repeat=1): "Random selection from itertools.product(*args, **kwds)" pools = [tuple(pool) for pool in args] * repeat - return tuple(random.choice(pool) for pool in pools) + return tuple(map(random.choice, pools)) def random_permutation(iterable, r=None): "Random selection from itertools.permutations(iterable, r)" @@ -900,11 +900,11 @@ which incur interpreter overhead. "Random selection from itertools.combinations_with_replacement(iterable, r)" pool = tuple(iterable) n = len(pool) - indices = sorted(random.randrange(n) for i in range(r)) + indices = sorted(random.choices(range(n), k=r)) return tuple(pool[i] for i in indices) def nth_combination(iterable, r, index): - 'Equivalent to list(combinations(iterable, r))[index]' + "Equivalent to list(combinations(iterable, r))[index]" pool = tuple(iterable) n = len(pool) if r < 0 or r > n: diff --git a/Lib/test/test_itertools.py b/Lib/test/test_itertools.py index eaa6197bec395c..702cf0820316b1 100644 --- a/Lib/test/test_itertools.py +++ b/Lib/test/test_itertools.py @@ -2290,7 +2290,7 @@ def test_permutations_sizeof(self): ... "Count how many times the predicate is true" ... return sum(map(pred, iterable)) ->>> def padnone(iterable): +>>> def pad_none(iterable): ... "Returns the sequence elements and then returns None indefinitely" ... return chain(iterable, repeat(None)) @@ -2460,7 +2460,7 @@ def test_permutations_sizeof(self): >>> list(pairwise('a')) [] ->>> list(islice(padnone('abc'), 0, 6)) +>>> list(islice(pad_none('abc'), 0, 6)) ['a', 'b', 'c', None, None, None] >>> list(ncycles('abc', 3)) From 586bdd1add2ca7236e3096ab7167862cf17f0939 Mon Sep 17 00:00:00 2001 From: Irit Katriel Date: Mon, 30 Nov 2020 01:40:45 +0000 Subject: [PATCH 0754/1314] [3.9] bpo-42474: test TracebackException comparison to non-equal instances (GH-23557) --- Lib/test/test_traceback.py | 41 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 39 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_traceback.py b/Lib/test/test_traceback.py index f9a5f2fc53e1e9..d564f3040ea18a 100644 --- a/Lib/test/test_traceback.py +++ b/Lib/test/test_traceback.py @@ -1103,7 +1103,7 @@ def test_context(self): self.assertEqual(exc_info[0], exc.exc_type) self.assertEqual(str(exc_info[1]), str(exc)) - def test_comparison(self): + def test_comparison_basic(self): try: 1/0 except Exception: @@ -1115,6 +1115,43 @@ def test_comparison(self): self.assertNotEqual(exc, object()) self.assertEqual(exc, ALWAYS_EQ) + def test_comparison_params_variations(self): + def raise_exc(): + try: + raise ValueError('bad value') + except: + raise + + def raise_with_locals(): + x, y = 1, 2 + raise_exc() + + try: + raise_with_locals() + except Exception: + exc_info = sys.exc_info() + + exc = traceback.TracebackException(*exc_info) + exc1 = traceback.TracebackException(*exc_info, limit=10) + exc2 = traceback.TracebackException(*exc_info, limit=2) + + self.assertEqual(exc, exc1) # limit=10 gets all frames + self.assertNotEqual(exc, exc2) # limit=2 truncates the output + + # locals change the output + exc3 = traceback.TracebackException(*exc_info, capture_locals=True) + self.assertNotEqual(exc, exc3) + + # there are no locals in the innermost frame + exc4 = traceback.TracebackException(*exc_info, limit=-1) + exc5 = traceback.TracebackException(*exc_info, limit=-1, capture_locals=True) + self.assertEqual(exc4, exc5) + + # there are locals in the next-to-innermost frame + exc6 = traceback.TracebackException(*exc_info, limit=-2) + exc7 = traceback.TracebackException(*exc_info, limit=-2, capture_locals=True) + self.assertNotEqual(exc6, exc7) + def test_unhashable(self): class UnhashableException(Exception): def __eq__(self, other): @@ -1156,7 +1193,7 @@ def test_lookup_lines(self): f = test_frame(c, None, None) tb = test_tb(f, 6, None) exc = traceback.TracebackException(Exception, e, tb, lookup_lines=False) - self.assertEqual({}, linecache.cache) + self.assertEqual(linecache.cache, {}) linecache.updatecache('/foo.py', globals()) self.assertEqual(exc.stack[0].line, "import sys") From 03ae7e4518dae6547576c616173106d2eb283ae2 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 30 Nov 2020 00:43:59 -0800 Subject: [PATCH 0755/1314] bpo-42142: Try to fix timeouts in ttk tests (GH-23474) Instead of using wait_visibility() which waits event in dead loop use update() which should proceed all queued events. (cherry picked from commit 6cc2c419f6cf5ed336609ba01055e77d7c553e6d) Co-authored-by: Serhiy Storchaka --- Lib/tkinter/test/test_ttk/test_extensions.py | 6 ------ Lib/tkinter/test/test_ttk/test_widgets.py | 20 +++++++------------- 2 files changed, 7 insertions(+), 19 deletions(-) diff --git a/Lib/tkinter/test/test_ttk/test_extensions.py b/Lib/tkinter/test/test_ttk/test_extensions.py index a45f882bb00d48..6937ba1ca9be41 100644 --- a/Lib/tkinter/test/test_ttk/test_extensions.py +++ b/Lib/tkinter/test/test_ttk/test_extensions.py @@ -114,7 +114,6 @@ def check_positions(scale, scale_pos, label, label_pos): def test_horizontal_range(self): lscale = ttk.LabeledScale(self.root, from_=0, to=10) lscale.pack() - lscale.wait_visibility() lscale.update() linfo_1 = lscale.label.place_info() @@ -144,7 +143,6 @@ def test_horizontal_range(self): def test_variable_change(self): x = ttk.LabeledScale(self.root) x.pack() - x.wait_visibility() x.update() curr_xcoord = x.scale.coords()[0] @@ -187,7 +185,6 @@ def test_variable_change(self): def test_resize(self): x = ttk.LabeledScale(self.root) x.pack(expand=True, fill='both') - x.wait_visibility() x.update() width, height = x.master.winfo_width(), x.master.winfo_height() @@ -268,7 +265,6 @@ def test_menu(self): # check that variable is updated correctly optmenu.pack() - optmenu.wait_visibility() optmenu['menu'].invoke(0) self.assertEqual(optmenu._variable.get(), items[0]) @@ -299,9 +295,7 @@ def test_unique_radiobuttons(self): textvar2 = tkinter.StringVar(self.root) optmenu2 = ttk.OptionMenu(self.root, textvar2, default, *items) optmenu.pack() - optmenu.wait_visibility() optmenu2.pack() - optmenu2.wait_visibility() optmenu['menu'].invoke(1) optmenu2['menu'].invoke(2) optmenu_stringvar_name = optmenu['menu'].entrycget(0, 'variable') diff --git a/Lib/tkinter/test/test_ttk/test_widgets.py b/Lib/tkinter/test/test_ttk/test_widgets.py index 2598bc67652075..572e6daddf0084 100644 --- a/Lib/tkinter/test/test_ttk/test_widgets.py +++ b/Lib/tkinter/test/test_ttk/test_widgets.py @@ -60,11 +60,10 @@ def setUp(self): super().setUp() self.widget = ttk.Button(self.root, width=0, text="Text") self.widget.pack() - self.widget.wait_visibility() def test_identify(self): - self.widget.update_idletasks() + self.widget.update() self.assertEqual(self.widget.identify( int(self.widget.winfo_width() / 2), int(self.widget.winfo_height() / 2) @@ -326,8 +325,7 @@ def test_bbox(self): def test_identify(self): self.entry.pack() - self.entry.wait_visibility() - self.entry.update_idletasks() + self.entry.update() # bpo-27313: macOS Cocoa widget differs from X, allow either if sys.platform == 'darwin': @@ -449,7 +447,7 @@ def test_virtual_event(self): self.combo.bind('<>', lambda evt: success.append(True)) self.combo.pack() - self.combo.wait_visibility() + self.combo.update() height = self.combo.winfo_height() self._show_drop_down_listbox() @@ -465,7 +463,7 @@ def test_postcommand(self): self.combo['postcommand'] = lambda: success.append(True) self.combo.pack() - self.combo.wait_visibility() + self.combo.update() self._show_drop_down_listbox() self.assertTrue(success) @@ -665,7 +663,6 @@ def test_sashpos(self): self.assertRaises(tkinter.TclError, self.paned.sashpos, 1) self.paned.pack(expand=True, fill='both') - self.paned.wait_visibility() curr_pos = self.paned.sashpos(0) self.paned.sashpos(0, 1000) @@ -933,7 +930,7 @@ def test_tab_identifiers(self): self.nb.add(self.child1, text='a') self.nb.pack() - self.nb.wait_visibility() + self.nb.update() if sys.platform == 'darwin': tb_idx = "@20,5" else: @@ -1041,7 +1038,7 @@ def test_insert(self): def test_select(self): self.nb.pack() - self.nb.wait_visibility() + self.nb.update() success = [] tab_changed = [] @@ -1084,7 +1081,7 @@ def test_tabs(self): def test_traversal(self): self.nb.pack() - self.nb.wait_visibility() + self.nb.update() self.nb.select(0) @@ -1342,7 +1339,6 @@ def test_show(self): def test_bbox(self): self.tv.pack() self.assertEqual(self.tv.bbox(''), '') - self.tv.wait_visibility() self.tv.update() item_id = self.tv.insert('', 'end') @@ -1536,7 +1532,6 @@ def simulate_heading_click(x, y): success = [] # no success for now self.tv.pack() - self.tv.wait_visibility() self.tv.heading('#0', command=lambda: success.append(True)) self.tv.column('#0', width=100) self.tv.update() @@ -1784,7 +1779,6 @@ def test_tag_bind(self): lambda evt: events.append(2)) self.tv.pack() - self.tv.wait_visibility() self.tv.update() pos_y = set() From cf22aa3bc698847459a6bf20c166aa80825b810a Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 30 Nov 2020 09:07:26 -0800 Subject: [PATCH 0756/1314] bpo-42487: don't call __getitem__ of underlying maps in ChainMap.__iter__ (GH-23534) (GH-23569) --- Lib/collections/__init__.py | 2 +- Lib/test/test_collections.py | 16 ++++++++++++++++ .../2020-11-28-04-31-20.bpo-42487.iqtC4L.rst | 1 + 3 files changed, 18 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Library/2020-11-28-04-31-20.bpo-42487.iqtC4L.rst diff --git a/Lib/collections/__init__.py b/Lib/collections/__init__.py index efd654e8ed739e..bc69a6757f2948 100644 --- a/Lib/collections/__init__.py +++ b/Lib/collections/__init__.py @@ -949,7 +949,7 @@ def __len__(self): def __iter__(self): d = {} for mapping in reversed(self.maps): - d.update(mapping) # reuses stored hash values if possible + d.update(dict.fromkeys(mapping)) # reuses stored hash values if possible return iter(d) def __contains__(self, key): diff --git a/Lib/test/test_collections.py b/Lib/test/test_collections.py index 6aa897927228cc..057ec92015cf4f 100644 --- a/Lib/test/test_collections.py +++ b/Lib/test/test_collections.py @@ -195,6 +195,22 @@ def test_order_preservation(self): ('e', 55), ('f', 666), ('g', 777), ('h', 88888), ('i', 9999), ('j', 0)]) + def test_iter_not_calling_getitem_on_maps(self): + class DictWithGetItem(UserDict): + def __init__(self, *args, **kwds): + self.called = False + UserDict.__init__(self, *args, **kwds) + def __getitem__(self, item): + self.called = True + UserDict.__getitem__(self, item) + + d = DictWithGetItem(a=1) + c = ChainMap(d) + d.called = False + + set(c) # iterate over chain map + self.assertFalse(d.called, '__getitem__ was called') + def test_dict_coercion(self): d = ChainMap(dict(a=1, b=2), dict(b=20, c=30)) self.assertEqual(dict(d), dict(a=1, b=2, c=30)) diff --git a/Misc/NEWS.d/next/Library/2020-11-28-04-31-20.bpo-42487.iqtC4L.rst b/Misc/NEWS.d/next/Library/2020-11-28-04-31-20.bpo-42487.iqtC4L.rst new file mode 100644 index 00000000000000..8c67d747b614ee --- /dev/null +++ b/Misc/NEWS.d/next/Library/2020-11-28-04-31-20.bpo-42487.iqtC4L.rst @@ -0,0 +1 @@ +ChainMap.__iter__ no longer calls __getitem__ on underlying maps From aab93903347ec6d7f23dda2994dd26f6111d19d2 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 30 Nov 2020 13:21:08 -0800 Subject: [PATCH 0757/1314] bpo-42501: Revise the usage note for Enums with the choices (GH-23563) (GH-23573) --- Doc/library/argparse.rst | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/Doc/library/argparse.rst b/Doc/library/argparse.rst index 7a7a4cf94979a1..a32b99901a7b4e 100644 --- a/Doc/library/argparse.rst +++ b/Doc/library/argparse.rst @@ -1133,20 +1133,9 @@ container should match the type_ specified:: Any container can be passed as the *choices* value, so :class:`list` objects, :class:`set` objects, and custom containers are all supported. -This includes :class:`enum.Enum`, which could be used to restrain -argument's choices; if we reuse previous rock/paper/scissors game example, -this could be as follows:: - - >>> from enum import Enum - >>> class GameMove(Enum): - ... ROCK = 'rock' - ... PAPER = 'paper' - ... SCISSORS = 'scissors' - ... - >>> parser = argparse.ArgumentParser(prog='game.py') - >>> parser.add_argument('move', type=GameMove, choices=GameMove) - >>> parser.parse_args(['rock']) - Namespace(move=) + +Use of :class:`enum.Enum` is not recommended because it is difficult to +control its appearance in usage, help, and error messages. required From b2652f2d7e1f3b868e9bec6669b3f3f905257991 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 30 Nov 2020 14:34:43 -0800 Subject: [PATCH 0758/1314] bpo-42370: Check element before making mouse click in ttk tests (GH-23491) (cherry picked from commit b0b428510cfd604a8eef1f245f039331e671ea4a) Co-authored-by: Serhiy Storchaka --- Lib/tkinter/test/test_ttk/test_widgets.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/Lib/tkinter/test/test_ttk/test_widgets.py b/Lib/tkinter/test/test_ttk/test_widgets.py index 572e6daddf0084..157ef0e8f87bb5 100644 --- a/Lib/tkinter/test/test_ttk/test_widgets.py +++ b/Lib/tkinter/test/test_ttk/test_widgets.py @@ -435,11 +435,12 @@ def test_height(self): def _show_drop_down_listbox(self): width = self.combo.winfo_width() - self.combo.event_generate('', x=width - 5, y=5) - self.combo.event_generate('', x=width - 5, y=5) + x, y = width - 5, 5 + self.assertRegex(self.combo.identify(x, y), r'.*downarrow\Z') + self.combo.event_generate('', x=x, y=y) + self.combo.event_generate('', x=x, y=y) self.combo.update_idletasks() - def test_virtual_event(self): success = [] @@ -1085,6 +1086,7 @@ def test_traversal(self): self.nb.select(0) + self.assertEqual(self.nb.identify(5, 5), 'focus') simulate_mouse_click(self.nb, 5, 5) self.nb.focus_force() self.nb.event_generate('') @@ -1099,6 +1101,7 @@ def test_traversal(self): self.nb.tab(self.child1, text='a', underline=0) self.nb.enable_traversal() self.nb.focus_force() + self.assertEqual(self.nb.identify(5, 5), 'focus') simulate_mouse_click(self.nb, 5, 5) if sys.platform == 'darwin': self.nb.event_generate('') @@ -1129,6 +1132,7 @@ def _click_increment_arrow(self): height = self.spin.winfo_height() x = width - 5 y = height//2 - 5 + self.assertRegex(self.spin.identify(x, y), r'.*uparrow\Z') self.spin.event_generate('', x=x, y=y) self.spin.event_generate('', x=x, y=y) self.spin.update_idletasks() @@ -1138,6 +1142,7 @@ def _click_decrement_arrow(self): height = self.spin.winfo_height() x = width - 5 y = height//2 + 4 + self.assertRegex(self.spin.identify(x, y), r'.*downarrow\Z') self.spin.event_generate('', x=x, y=y) self.spin.event_generate('', x=x, y=y) self.spin.update_idletasks() @@ -1526,6 +1531,9 @@ def test_heading(self): def test_heading_callback(self): def simulate_heading_click(x, y): + if tcl_version >= (8, 6): + self.assertEqual(self.tv.identify_column(x), '#0') + self.assertEqual(self.tv.identify_region(x, y), 'heading') simulate_mouse_click(self.tv, x, y) self.tv.update() From ff51e5ec26168574761e128cc607b879d4d5aa50 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 30 Nov 2020 14:36:06 -0800 Subject: [PATCH 0759/1314] bpo-42508: Remove bogus idlelib.pyshell.ModifiedInterpreter attribute (GH-23570) (GH-23571) restart_subprocess is a method of self, the pyshell.InteractiveInterpreter instance. The latter does not have an interp attribute redundantly referring to itself. (The PyShell instance does have an interp attribute, referring to the InteractiveInterpreter instance.) (cherry picked from commit e41bfd15dd148627b4f39c2a5837bddd8894d345) Co-authored-by: Terry Jan Reedy --- Lib/idlelib/pyshell.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/idlelib/pyshell.py b/Lib/idlelib/pyshell.py index b69916dbe876ca..adc302883ae669 100755 --- a/Lib/idlelib/pyshell.py +++ b/Lib/idlelib/pyshell.py @@ -757,7 +757,7 @@ def runcommand(self, code): def runcode(self, code): "Override base class method" if self.tkconsole.executing: - self.interp.restart_subprocess() + self.restart_subprocess() self.checklinecache() debugger = self.debugger try: From 7e80c0f40e0458fd1b2c879c031594388fc6dea6 Mon Sep 17 00:00:00 2001 From: Julien Palard Date: Tue, 1 Dec 2020 08:58:36 +0100 Subject: [PATCH 0760/1314] [3.9] [doc] Fix smtplib and xml.dom.minidom mark-up (GH-22769) (GH-23380) --- Doc/library/smtplib.rst | 2 +- Doc/library/xml.dom.minidom.rst | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Doc/library/smtplib.rst b/Doc/library/smtplib.rst index a88e358eae5fde..c1a20fee6cf024 100644 --- a/Doc/library/smtplib.rst +++ b/Doc/library/smtplib.rst @@ -115,7 +115,7 @@ Protocol) and :rfc:`1869` (SMTP Service Extensions). If the *timeout* parameter is set to be zero, it will raise a :class:`ValueError` to prevent the creation of a non-blocking socket -.. class:: LMTP(host='', port=LMTP_PORT, local_hostname=None, +.. class:: LMTP(host='', port=LMTP_PORT, local_hostname=None, \ source_address=None[, timeout]) The LMTP protocol, which is very similar to ESMTP, is heavily based on the diff --git a/Doc/library/xml.dom.minidom.rst b/Doc/library/xml.dom.minidom.rst index 2c78cd939243a8..bf72c46561b7c7 100644 --- a/Doc/library/xml.dom.minidom.rst +++ b/Doc/library/xml.dom.minidom.rst @@ -132,7 +132,7 @@ module documentation. This section lists the differences between the API and ... # Work with dom. -.. method:: Node.writexml(writer, indent="", addindent="", newl="", +.. method:: Node.writexml(writer, indent="", addindent="", newl="", \ encoding=None, standalone=None) Write XML to the writer object. The writer receives texts but not bytes as input, @@ -174,7 +174,7 @@ module documentation. This section lists the differences between the API and The :meth:`toxml` method now preserves the attribute order specified by the user. -.. method:: Node.toprettyxml(indent="\\t", newl="\\n", encoding=None, +.. method:: Node.toprettyxml(indent="\\t", newl="\\n", encoding=None, \ standalone=None) Return a pretty-printed version of the document. *indent* specifies the From aef482f7cfd78b25ecc9c38805549c5593655ed7 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 1 Dec 2020 02:04:23 -0800 Subject: [PATCH 0761/1314] Fix bz2 examples markup (GH-23580) (cherry picked from commit 80a429eae95c15c2c2a6753376f2697c90c2b6b9) Co-authored-by: Andre Delfino --- Doc/library/bz2.rst | 8 -------- 1 file changed, 8 deletions(-) diff --git a/Doc/library/bz2.rst b/Doc/library/bz2.rst index 85cdc16a7d78d4..637baf49da1fc0 100644 --- a/Doc/library/bz2.rst +++ b/Doc/library/bz2.rst @@ -266,7 +266,6 @@ Below are some examples of typical usage of the :mod:`bz2` module. Using :func:`compress` and :func:`decompress` to demonstrate round-trip compression: >>> import bz2 - >>> data = b"""\ ... Donec rhoncus quis sapien sit amet molestie. Fusce scelerisque vel augue ... nec ullamcorper. Nam rutrum pretium placerat. Aliquam vel tristique lorem, @@ -275,11 +274,9 @@ Using :func:`compress` and :func:`decompress` to demonstrate round-trip compress ... Aliquam pharetra lacus non risus vehicula rutrum. Maecenas aliquam leo ... felis. Pellentesque semper nunc sit amet nibh ullamcorper, ac elementum ... dolor luctus. Curabitur lacinia mi ornare consectetur vestibulum.""" - >>> c = bz2.compress(data) >>> len(data) / len(c) # Data compression ratio 1.513595166163142 - >>> d = bz2.decompress(c) >>> data == d # Check equality to original object after round-trip True @@ -287,7 +284,6 @@ Using :func:`compress` and :func:`decompress` to demonstrate round-trip compress Using :class:`BZ2Compressor` for incremental compression: >>> import bz2 - >>> def gen_data(chunks=10, chunksize=1000): ... """Yield incremental blocks of chunksize bytes.""" ... for _ in range(chunks): @@ -310,7 +306,6 @@ while ordered, repetitive data usually yields a high compression ratio. Writing and reading a bzip2-compressed file in binary mode: >>> import bz2 - >>> data = b"""\ ... Donec rhoncus quis sapien sit amet molestie. Fusce scelerisque vel augue ... nec ullamcorper. Nam rutrum pretium placerat. Aliquam vel tristique lorem, @@ -319,14 +314,11 @@ Writing and reading a bzip2-compressed file in binary mode: ... Aliquam pharetra lacus non risus vehicula rutrum. Maecenas aliquam leo ... felis. Pellentesque semper nunc sit amet nibh ullamcorper, ac elementum ... dolor luctus. Curabitur lacinia mi ornare consectetur vestibulum.""" - >>> with bz2.open("myfile.bz2", "wb") as f: ... # Write compressed data to file ... unused = f.write(data) - >>> with bz2.open("myfile.bz2", "rb") as f: ... # Decompress data from file ... content = f.read() - >>> content == data # Check equality to original object after round-trip True From 4a44f53aa85c9400471ab084bc8fd8169065fc41 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 1 Dec 2020 02:53:42 -0800 Subject: [PATCH 0762/1314] [3.9] bpo-17852: Doc: Fix the tutorial about closing files (GH-23135) (GH-23527) Co-authored-by: Inada Naoki (cherry picked from commit c8aaf71dde4888864c0c351e2f935f87652c3d54) Co-authored-by: Volker-Weissmann <39418860+Volker-Weissmann@users.noreply.github.com> --- Doc/tutorial/inputoutput.rst | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/Doc/tutorial/inputoutput.rst b/Doc/tutorial/inputoutput.rst index 366a532e817afa..4e27cff83ce59f 100644 --- a/Doc/tutorial/inputoutput.rst +++ b/Doc/tutorial/inputoutput.rst @@ -329,11 +329,16 @@ equivalent :keyword:`try`\ -\ :keyword:`finally` blocks:: If you're not using the :keyword:`with` keyword, then you should call ``f.close()`` to close the file and immediately free up any system -resources used by it. If you don't explicitly close a file, Python's -garbage collector will eventually destroy the object and close the -open file for you, but the file may stay open for a while. Another -risk is that different Python implementations will do this clean-up at -different times. +resources used by it. + +.. warning:: + Calling ``f.write()`` without using the :keyword:`!with` keyword or calling + ``f.close()`` **might** result in the arguments + of ``f.write()`` not being completely written to the disk, even if the + program exits successfully. + +.. + See also https://bugs.python.org/issue17852 After a file object is closed, either by a :keyword:`with` statement or by calling ``f.close()``, attempts to use the file object will From ae48dd4db53f64f053a6ed6571d083c332d06ff7 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 1 Dec 2020 07:07:50 -0800 Subject: [PATCH 0763/1314] Add GCC pragmas to silence compiler warning about ffi_prep_closure (GH-23327) (GH-23590) (cherry picked from commit cce3f0b0c88eba98bc11abe703a444bee7880ff8) Co-authored-by: Pablo Galindo Co-authored-by: Pablo Galindo --- Modules/_ctypes/callbacks.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/Modules/_ctypes/callbacks.c b/Modules/_ctypes/callbacks.c index 39cace58294d58..19c77f4f57ef5a 100644 --- a/Modules/_ctypes/callbacks.c +++ b/Modules/_ctypes/callbacks.c @@ -426,15 +426,22 @@ CThunkObject *_ctypes_alloc_callback(PyObject *callable, PyErr_Format(PyExc_NotImplementedError, "ffi_prep_closure_loc() is missing"); goto error; #else -#ifdef MACOSX +#if defined(__clang__) || defined(MACOSX) #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wdeprecated-declarations" +#endif +#if defined(__GNUC__) + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wdeprecated-declarations" #endif result = ffi_prep_closure(p->pcl_write, &p->cif, closure_fcn, p); -#ifdef MACOSX +#if defined(__clang__) || defined(MACOSX) #pragma clang diagnostic pop #endif +#if defined(__GNUC__) + #pragma GCC diagnostic pop +#endif #endif } From d33f3347defa419ad18864fa3719ad8d668b78a0 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 1 Dec 2020 07:24:20 -0800 Subject: [PATCH 0764/1314] build(deps): bump actions/cache from v2.1.2 to v2.1.3 (23582) Bumps [actions/cache](https://github.com/actions/cache) from v2.1.2 to v2.1.3. - [Release notes](https://github.com/actions/cache/releases) - [Commits](https://github.com/actions/cache/compare/v2.1.2...0781355a23dac32fd3bac414512f4b903437991a) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> (cherry picked from commit a43fea88577c460eed7cc92a37b5fce787d6aab1) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/build.yml | 2 +- .github/workflows/coverage.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index deb0e67bedb902..3d7c9901a8e996 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -132,7 +132,7 @@ jobs: run: sudo ./.github/workflows/posix-deps-apt.sh - name: 'Restore OpenSSL build' id: cache-openssl - uses: actions/cache@v2.1.2 + uses: actions/cache@v2.1.3 with: path: ./multissl/openssl/${{ env.OPENSSL_VER }} key: ${{ runner.os }}-multissl-openssl-${{ env.OPENSSL_VER }} diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index d66c02b51b15e5..6092f41325ff27 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -32,7 +32,7 @@ jobs: run: sudo ./.github/workflows/posix-deps-apt.sh - name: 'Restore OpenSSL build' id: cache-openssl - uses: actions/cache@v2.1.2 + uses: actions/cache@v2.1.3 with: path: ./multissl/openssl/${{ env.OPENSSL_VER }} key: ${{ runner.os }}-multissl-openssl-${{ env.OPENSSL_VER }} From 0955f6863d726985fc9cfad004f242002a0efc80 Mon Sep 17 00:00:00 2001 From: Benjamin Peterson Date: Tue, 1 Dec 2020 09:30:03 -0600 Subject: [PATCH 0765/1314] [3.9] build(deps): bump actions/upload-artifact from v2.2.0 to v2.2.1 (GH-23597) Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from v2.2.0 to v2.2.1. - [Release notes](https://github.com/actions/upload-artifact/releases) - [Commits](https://github.com/actions/upload-artifact/compare/v2.2.0...726a6dcd0199f578459862705eed35cda05af50b) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> (cherry picked from commit 8acd0e0d4976e91500149ee189f369f2b83b7537) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/doc.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/doc.yml b/.github/workflows/doc.yml index 455ad02f7ed3ed..02e7c865cd5684 100644 --- a/.github/workflows/doc.yml +++ b/.github/workflows/doc.yml @@ -36,7 +36,7 @@ jobs: - name: 'Build documentation' run: xvfb-run make -C Doc/ PYTHON=../python SPHINXOPTS="-q -W -j4" doctest suspicious html - name: 'Upload' - uses: actions/upload-artifact@v2.2.0 + uses: actions/upload-artifact@v2.2.1 with: name: doc-html path: Doc/build/html From ed4614386f210964840daa1f7cbddbbd575f7a49 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 1 Dec 2020 07:54:54 -0800 Subject: [PATCH 0766/1314] bpo-37221: PyCode_New() didn't change in Python 3.8 (GH-23595) (cherry picked from commit 1867b462de427bcb8dfbcd256028410aea6ae929) Co-authored-by: Victor Stinner --- Doc/whatsnew/3.8.rst | 3 --- 1 file changed, 3 deletions(-) diff --git a/Doc/whatsnew/3.8.rst b/Doc/whatsnew/3.8.rst index 6a9fa341569465..0b4820f3333e13 100644 --- a/Doc/whatsnew/3.8.rst +++ b/Doc/whatsnew/3.8.rst @@ -2113,9 +2113,6 @@ Changes in the C API (Contributed by Antoine Pitrou in :issue:`32388`.) -* The :c:func:`PyCode_New` has a new parameter in the second position (*posonlyargcount*) - to support :pep:`570`, indicating the number of positional-only arguments. - * The functions :c:func:`PyNode_AddChild` and :c:func:`PyParser_AddToken` now accept two additional ``int`` arguments *end_lineno* and *end_col_offset*. From 9b34f34aa929941576a69a6f7de77f1fb0b96ed6 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 2 Dec 2020 14:01:23 -0800 Subject: [PATCH 0767/1314] bpo-42521: Add note about 'Python -d' only working on debug builds (GH-23607) (cherry picked from commit 99b594404d364b363c184f48338d6ee81bee26dd) Co-authored-by: Pablo Galindo --- Python/initconfig.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Python/initconfig.c b/Python/initconfig.c index e882a1fba53967..3caed385ef6af5 100644 --- a/Python/initconfig.c +++ b/Python/initconfig.c @@ -42,7 +42,8 @@ Options and arguments (and corresponding environment variables):\n\ and comparing bytes/bytearray with str. (-bb: issue errors)\n\ -B : don't write .pyc files on import; also PYTHONDONTWRITEBYTECODE=x\n\ -c cmd : program passed in as string (terminates option list)\n\ --d : debug output from parser; also PYTHONDEBUG=x\n\ +-d : turn on parser debugging output (for experts only, only works on\n\ + debug builds); also PYTHONDEBUG=x\n\ -E : ignore PYTHON* environment variables (such as PYTHONPATH)\n\ -h : print this help message and exit (also --help)\n\ "; From 09a698b4743c669983d606595a1b2daeff6c3cf8 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 2 Dec 2020 19:43:08 -0800 Subject: [PATCH 0768/1314] bpo-42504: fix for MACOSX_DEPLOYMENT_TARGET=11 (GH-23556) macOS releases numbering has changed as of macOS 11 Big Sur. Previously, major releases were of the form 10.x, 10.x+1, 10.x+2, etc; as of Big Sur, they are now x, x+1, etc, so, for example, 10.15, 10.15.1, ..., 10.15.7, 11, 11.0.1, 11.1, ..., 12, 12.1, etc. Allow Python to build with single-digit deployment target values. Patch provided by FX Coudert. (cherry picked from commit 5291639e611dc3f55a34666036f2c3424648ba50) Co-authored-by: FX Coudert --- Lib/distutils/spawn.py | 4 ++-- Lib/distutils/tests/test_build_ext.py | 10 +++++++--- Lib/test/test_posix.py | 2 +- .../macOS/2020-12-02-15-48-40.bpo-42504.RQmMOR.rst | 1 + setup.py | 2 +- 5 files changed, 12 insertions(+), 7 deletions(-) create mode 100644 Misc/NEWS.d/next/macOS/2020-12-02-15-48-40.bpo-42504.RQmMOR.rst diff --git a/Lib/distutils/spawn.py b/Lib/distutils/spawn.py index 0d1bd0391e6f11..f50edd2da97100 100644 --- a/Lib/distutils/spawn.py +++ b/Lib/distutils/spawn.py @@ -54,8 +54,8 @@ def spawn(cmd, search_path=1, verbose=0, dry_run=0): global _cfg_target, _cfg_target_split if _cfg_target is None: from distutils import sysconfig - _cfg_target = sysconfig.get_config_var( - 'MACOSX_DEPLOYMENT_TARGET') or '' + _cfg_target = str(sysconfig.get_config_var( + 'MACOSX_DEPLOYMENT_TARGET') or '') if _cfg_target: _cfg_target_split = [int(x) for x in _cfg_target.split('.')] if _cfg_target: diff --git a/Lib/distutils/tests/test_build_ext.py b/Lib/distutils/tests/test_build_ext.py index 5a32e039800f0c..1b034c93025213 100644 --- a/Lib/distutils/tests/test_build_ext.py +++ b/Lib/distutils/tests/test_build_ext.py @@ -455,7 +455,7 @@ def test_deployment_target_higher_ok(self): deptarget = sysconfig.get_config_var('MACOSX_DEPLOYMENT_TARGET') if deptarget: # increment the minor version number (i.e. 10.6 -> 10.7) - deptarget = [int(x) for x in deptarget.split('.')] + deptarget = [int(x) for x in str(deptarget).split('.')] deptarget[-1] += 1 deptarget = '.'.join(str(i) for i in deptarget) self._try_compile_deployment_target('<', deptarget) @@ -488,7 +488,7 @@ def _try_compile_deployment_target(self, operator, target): # get the deployment target that the interpreter was built with target = sysconfig.get_config_var('MACOSX_DEPLOYMENT_TARGET') - target = tuple(map(int, target.split('.')[0:2])) + target = tuple(map(int, str(target).split('.')[0:2])) # format the target value as defined in the Apple # Availability Macros. We can't use the macro names since # at least one value we test with will not exist yet. @@ -497,7 +497,11 @@ def _try_compile_deployment_target(self, operator, target): target = '%02d%01d0' % target else: # for 10.10 and beyond -> "10nn00" - target = '%02d%02d00' % target + if len(target) >= 2: + target = '%02d%02d00' % target + else: + # 11 and later can have no minor version (11 instead of 11.0) + target = '%02d0000' % target deptarget_ext = Extension( 'deptarget', [deptarget_c], diff --git a/Lib/test/test_posix.py b/Lib/test/test_posix.py index f4edb8bd9575f4..bfbcbab3b62f96 100644 --- a/Lib/test/test_posix.py +++ b/Lib/test/test_posix.py @@ -1045,7 +1045,7 @@ def test_getgroups(self): if sys.platform == 'darwin': import sysconfig dt = sysconfig.get_config_var('MACOSX_DEPLOYMENT_TARGET') or '10.0' - if tuple(int(n) for n in dt.split('.')[0:2]) < (10, 6): + if tuple(int(n) for n in str(dt).split('.')[0:2]) < (10, 6): raise unittest.SkipTest("getgroups(2) is broken prior to 10.6") # 'id -G' and 'os.getgroups()' should return the same diff --git a/Misc/NEWS.d/next/macOS/2020-12-02-15-48-40.bpo-42504.RQmMOR.rst b/Misc/NEWS.d/next/macOS/2020-12-02-15-48-40.bpo-42504.RQmMOR.rst new file mode 100644 index 00000000000000..c83bc2b9eeec5f --- /dev/null +++ b/Misc/NEWS.d/next/macOS/2020-12-02-15-48-40.bpo-42504.RQmMOR.rst @@ -0,0 +1 @@ +Fix build on macOS Big Sur when MACOSX_DEPLOYMENT_TARGET=11 \ No newline at end of file diff --git a/setup.py b/setup.py index 7432970a106919..bfe621d0b50da1 100644 --- a/setup.py +++ b/setup.py @@ -1012,7 +1012,7 @@ def detect_readline_curses(self): os_release = int(os.uname()[2].split('.')[0]) dep_target = sysconfig.get_config_var('MACOSX_DEPLOYMENT_TARGET') if (dep_target and - (tuple(int(n) for n in dep_target.split('.')[0:2]) + (tuple(int(n) for n in str(dep_target).split('.')[0:2]) < (10, 5) ) ): os_release = 8 if os_release < 9: From ae67db6b314e297a1b67ed15c0bb560b8ce5b856 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 3 Dec 2020 01:10:23 -0800 Subject: [PATCH 0769/1314] bpo-42328: Skip some tests with themes vista and xpnative on Windows 7 (GH-23612) (cherry picked from commit f3c3ea91a76526edff928c95b9c6767e077b7448) Co-authored-by: Serhiy Storchaka --- Lib/tkinter/test/test_ttk/test_style.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Lib/tkinter/test/test_ttk/test_style.py b/Lib/tkinter/test/test_ttk/test_style.py index 54e913311766f1..38d70d7a89077d 100644 --- a/Lib/tkinter/test/test_ttk/test_style.py +++ b/Lib/tkinter/test/test_ttk/test_style.py @@ -1,4 +1,5 @@ import unittest +import sys import tkinter from tkinter import ttk from test import support @@ -136,6 +137,10 @@ def test_configure_custom_copy(self): with self.subTest(theme=theme, name=name): if support.verbose >= 2: print('configure', theme, name, default) + if (theme in ('vista', 'xpnative') + and sys.getwindowsversion()[:2] == (6, 1)): + # Fails on the Windows 7 buildbot + continue newname = f'C.{name}' self.assertEqual(style.configure(newname), None) style.configure(newname, **default) @@ -158,6 +163,10 @@ def test_map_custom_copy(self): with self.subTest(theme=theme, name=name): if support.verbose >= 2: print('map', theme, name, default) + if (theme in ('vista', 'xpnative') + and sys.getwindowsversion()[:2] == (6, 1)): + # Fails on the Windows 7 buildbot + continue newname = f'C.{name}' self.assertEqual(style.map(newname), {}) style.map(newname, **default) From 9f26833cedd33439b11059d423f599982abeb180 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 3 Dec 2020 05:20:07 -0800 Subject: [PATCH 0770/1314] bpo-42553: Fix test_asyncio.test_call_later() (GH-23627) Fix test_asyncio.test_call_later() race condition: don't measure asyncio performance in the call_later() unit test. The test failed randomly on the CI. (cherry picked from commit 7e5e13d113798117d5ef25c5ffdbd0eb39420f98) Co-authored-by: Victor Stinner --- Lib/test/test_asyncio/test_events.py | 3 --- .../NEWS.d/next/Tests/2020-12-03-13-32-44.bpo-42553.2TRE2N.rst | 3 +++ 2 files changed, 3 insertions(+), 3 deletions(-) create mode 100644 Misc/NEWS.d/next/Tests/2020-12-03-13-32-44.bpo-42553.2TRE2N.rst diff --git a/Lib/test/test_asyncio/test_events.py b/Lib/test/test_asyncio/test_events.py index 92b1522e956c40..fa6c49d89da5cd 100644 --- a/Lib/test/test_asyncio/test_events.py +++ b/Lib/test/test_asyncio/test_events.py @@ -293,11 +293,8 @@ def callback(arg): self.loop.stop() self.loop.call_later(0.1, callback, 'hello world') - t0 = time.monotonic() self.loop.run_forever() - t1 = time.monotonic() self.assertEqual(results, ['hello world']) - self.assertTrue(0.08 <= t1-t0 <= 0.8, t1-t0) def test_call_soon(self): results = [] diff --git a/Misc/NEWS.d/next/Tests/2020-12-03-13-32-44.bpo-42553.2TRE2N.rst b/Misc/NEWS.d/next/Tests/2020-12-03-13-32-44.bpo-42553.2TRE2N.rst new file mode 100644 index 00000000000000..872214284728bc --- /dev/null +++ b/Misc/NEWS.d/next/Tests/2020-12-03-13-32-44.bpo-42553.2TRE2N.rst @@ -0,0 +1,3 @@ +Fix ``test_asyncio.test_call_later()`` race condition: don't measure asyncio +performance in the ``call_later()`` unit test. The test failed randomly on +the CI. From 3689c25a1010c2acdb05f1b1b0229f4766b4440a Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 3 Dec 2020 09:46:58 -0800 Subject: [PATCH 0771/1314] bpo-42523: Fix supported versions in "Using Python on Windows" (GH-23603) (cherry picked from commit db68544122f5a0c7b80f69c0e643049efa6699c6) Co-authored-by: Zackery Spytz --- Doc/using/windows.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/using/windows.rst b/Doc/using/windows.rst index 275495bc6d1292..d0c342e1dad868 100644 --- a/Doc/using/windows.rst +++ b/Doc/using/windows.rst @@ -23,8 +23,8 @@ available for application-local distributions. As specified in :pep:`11`, a Python release only supports a Windows platform while Microsoft considers the platform under extended support. This means that -Python |version| supports Windows Vista and newer. If you require Windows XP -support then please install Python 3.4. +Python |version| supports Windows 8.1 and newer. If you require Windows 7 +support, please install Python 3.8. There are a number of different installers available for Windows, each with certain benefits and downsides. From c7cf66d2fe1b85cc02153be6422dfc5e34811638 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 4 Dec 2020 07:47:44 -0800 Subject: [PATCH 0772/1314] bpo-41473: Reenable test_gdb on gdb 9.2 and newer (GH-23637) https://bugzilla.redhat.com/show_bug.cgi?id=1866884 is fixed in gdb 10.1 (failed to reproduce on gdb-10.1-1.fc34.aarch64). (cherry picked from commit 066394018a8463643cc63d933493f0afa99d72cc) Co-authored-by: Victor Stinner --- Lib/test/test_gdb.py | 5 ----- .../next/Tests/2020-12-04-11-47-09.bpo-41473.W_updK.rst | 3 +++ 2 files changed, 3 insertions(+), 5 deletions(-) create mode 100644 Misc/NEWS.d/next/Tests/2020-12-04-11-47-09.bpo-41473.W_updK.rst diff --git a/Lib/test/test_gdb.py b/Lib/test/test_gdb.py index 44cb9a0f07b75d..22c75bae987219 100644 --- a/Lib/test/test_gdb.py +++ b/Lib/test/test_gdb.py @@ -51,11 +51,6 @@ def get_gdb_version(): "embedding. Saw %s.%s:\n%s" % (gdb_major_version, gdb_minor_version, gdb_version)) -if (gdb_major_version, gdb_minor_version) >= (9, 2): - # gdb 9.2 on Fedora Rawhide is not reliable, see: - # * https://bugs.python.org/issue41473 - # * https://bugzilla.redhat.com/show_bug.cgi?id=1866884 - raise unittest.SkipTest("https://bugzilla.redhat.com/show_bug.cgi?id=1866884") if not sysconfig.is_python_build(): raise unittest.SkipTest("test_gdb only works on source builds at the moment.") diff --git a/Misc/NEWS.d/next/Tests/2020-12-04-11-47-09.bpo-41473.W_updK.rst b/Misc/NEWS.d/next/Tests/2020-12-04-11-47-09.bpo-41473.W_updK.rst new file mode 100644 index 00000000000000..9e0a375a9b7f25 --- /dev/null +++ b/Misc/NEWS.d/next/Tests/2020-12-04-11-47-09.bpo-41473.W_updK.rst @@ -0,0 +1,3 @@ +Reenable test_gdb on gdb 9.2 and newer: +https://bugzilla.redhat.com/show_bug.cgi?id=1866884 bug is fixed in gdb +10.1. From 81ac030d03bdaedd724603af6f89f9248a5f2700 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 4 Dec 2020 12:20:05 -0800 Subject: [PATCH 0773/1314] bpo-42116: Fix inspect.getsource handling of trailing comments (GH-23630) (cherry picked from commit 6e1eec71f59c344fb23c7977061dc2c97b77d51b) Co-authored-by: Irit Katriel --- Lib/inspect.py | 7 ++++++ Lib/test/inspect_fodder.py | 22 ++++++++++++++++++ Lib/test/test_inspect.py | 23 +++++++++++++++---- .../2020-12-03-15-42-32.bpo-42116.yIwroP.rst | 1 + 4 files changed, 49 insertions(+), 4 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2020-12-03-15-42-32.bpo-42116.yIwroP.rst diff --git a/Lib/inspect.py b/Lib/inspect.py index 887a3424057b6e..6ca91e401a5eae 100644 --- a/Lib/inspect.py +++ b/Lib/inspect.py @@ -926,6 +926,7 @@ def __init__(self): self.indecorator = False self.decoratorhasargs = False self.last = 1 + self.body_col0 = None def tokeneater(self, type, token, srowcol, erowcol, line): if not self.started and not self.indecorator: @@ -957,6 +958,8 @@ def tokeneater(self, type, token, srowcol, erowcol, line): elif self.passline: pass elif type == tokenize.INDENT: + if self.body_col0 is None and self.started: + self.body_col0 = erowcol[1] self.indent = self.indent + 1 self.passline = True elif type == tokenize.DEDENT: @@ -966,6 +969,10 @@ def tokeneater(self, type, token, srowcol, erowcol, line): # not e.g. for "if: else:" or "try: finally:" blocks) if self.indent <= 0: raise EndOfBlock + elif type == tokenize.COMMENT: + if self.body_col0 is not None and srowcol[1] >= self.body_col0: + # Include comments if indented at least as much as the block + self.last = srowcol[0] elif self.indent == 0 and type not in (tokenize.COMMENT, tokenize.NL): # any other token on the same indentation level end the previous # block as well, except the pseudo-tokens COMMENT and NL. diff --git a/Lib/test/inspect_fodder.py b/Lib/test/inspect_fodder.py index 96a0257bfdf03e..e1287a315901cf 100644 --- a/Lib/test/inspect_fodder.py +++ b/Lib/test/inspect_fodder.py @@ -91,3 +91,25 @@ def as_method_of(self, obj): custom_method = Callable().as_method_of(42) del Callable + +# line 95 +class WhichComments: + # line 97 + # before f + def f(self): + # line 100 + # start f + return 1 + # line 103 + # end f + # line 105 + # after f + + # before asyncf - line 108 + async def asyncf(self): + # start asyncf + return 2 + # end asyncf + # after asyncf - line 113 + # end of WhichComments - line 114 + # after WhichComments - line 115 diff --git a/Lib/test/test_inspect.py b/Lib/test/test_inspect.py index e3e2be52076c6a..05485a0bc05754 100644 --- a/Lib/test/test_inspect.py +++ b/Lib/test/test_inspect.py @@ -388,6 +388,7 @@ def test_getclasses(self): ('ParrotDroppings', mod.ParrotDroppings), ('StupidGit', mod.StupidGit), ('Tit', mod.MalodorousPervert), + ('WhichComments', mod.WhichComments), ]) tree = inspect.getclasstree([cls[1] for cls in classes]) self.assertEqual(tree, @@ -401,7 +402,8 @@ def test_getclasses(self): [(mod.FesteringGob, (mod.MalodorousPervert, mod.ParrotDroppings)) ] - ] + ], + (mod.WhichComments, (object,),) ] ]) tree = inspect.getclasstree([cls[1] for cls in classes], True) @@ -413,7 +415,8 @@ def test_getclasses(self): [(mod.FesteringGob, (mod.MalodorousPervert, mod.ParrotDroppings)) ] - ] + ], + (mod.WhichComments, (object,),) ] ]) @@ -644,6 +647,18 @@ def test_anonymous(self): # as argument to another function. self.assertSourceEqual(mod2.anonymous, 55, 55) +class TestBlockComments(GetSourceBase): + fodderModule = mod + + def test_toplevel_class(self): + self.assertSourceEqual(mod.WhichComments, 96, 114) + + def test_class_method(self): + self.assertSourceEqual(mod.WhichComments.f, 99, 104) + + def test_class_async_method(self): + self.assertSourceEqual(mod.WhichComments.asyncf, 109, 112) + class TestBuggyCases(GetSourceBase): fodderModule = mod2 @@ -4016,8 +4031,8 @@ def test_getsource_reload(self): def test_main(): run_unittest( - TestDecorators, TestRetrievingSourceCode, TestOneliners, TestBuggyCases, - TestInterpreterStack, TestClassesAndFunctions, TestPredicates, + TestDecorators, TestRetrievingSourceCode, TestOneliners, TestBlockComments, + TestBuggyCases, TestInterpreterStack, TestClassesAndFunctions, TestPredicates, TestGetcallargsFunctions, TestGetcallargsMethods, TestGetcallargsUnboundMethods, TestGetattrStatic, TestGetGeneratorState, TestNoEOL, TestSignatureObject, TestSignatureBind, TestParameterObject, diff --git a/Misc/NEWS.d/next/Library/2020-12-03-15-42-32.bpo-42116.yIwroP.rst b/Misc/NEWS.d/next/Library/2020-12-03-15-42-32.bpo-42116.yIwroP.rst new file mode 100644 index 00000000000000..febda89338ddc7 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2020-12-03-15-42-32.bpo-42116.yIwroP.rst @@ -0,0 +1 @@ +Fix handling of trailing comments by :func:`inspect.getsource`. \ No newline at end of file From 40b92f1cc06f9aaba813ae38266f424e0969b089 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 4 Dec 2020 12:57:31 -0800 Subject: [PATCH 0774/1314] [3.9] bpo-42482: remove reference to exc_traceback from TracebackException (GH-23531) (GH-23578) (cherry picked from commit 427613f005f0f412d12f0d775d2b609bae0ae1ad) Co-authored-by: Irit Katriel --- Lib/test/test_traceback.py | 22 +++++++++++++++++++ Lib/traceback.py | 5 ++--- .../2020-11-27-16-46-58.bpo-42482.EJC3sd.rst | 1 + 3 files changed, 25 insertions(+), 3 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2020-11-27-16-46-58.bpo-42482.EJC3sd.rst diff --git a/Lib/test/test_traceback.py b/Lib/test/test_traceback.py index d564f3040ea18a..8549ba2b75ad08 100644 --- a/Lib/test/test_traceback.py +++ b/Lib/test/test_traceback.py @@ -1103,6 +1103,18 @@ def test_context(self): self.assertEqual(exc_info[0], exc.exc_type) self.assertEqual(str(exc_info[1]), str(exc)) + def test_no_refs_to_exception_and_traceback_objects(self): + try: + 1/0 + except Exception: + exc_info = sys.exc_info() + + refcnt1 = sys.getrefcount(exc_info[1]) + refcnt2 = sys.getrefcount(exc_info[2]) + exc = traceback.TracebackException(*exc_info) + self.assertEqual(sys.getrefcount(exc_info[1]), refcnt1) + self.assertEqual(sys.getrefcount(exc_info[2]), refcnt2) + def test_comparison_basic(self): try: 1/0 @@ -1152,6 +1164,16 @@ def raise_with_locals(): exc7 = traceback.TracebackException(*exc_info, limit=-2, capture_locals=True) self.assertNotEqual(exc6, exc7) + def test_comparison_equivalent_exceptions_are_equal(self): + excs = [] + for _ in range(2): + try: + 1/0 + except: + excs.append(traceback.TracebackException(*sys.exc_info())) + self.assertEqual(excs[0], excs[1]) + self.assertEqual(list(excs[0].format()), list(excs[1].format())) + def test_unhashable(self): class UnhashableException(Exception): def __eq__(self, other): diff --git a/Lib/traceback.py b/Lib/traceback.py index a19e38718b1205..fb34de94893007 100644 --- a/Lib/traceback.py +++ b/Lib/traceback.py @@ -500,7 +500,6 @@ def __init__(self, exc_type, exc_value, exc_traceback, *, limit=None, _seen=_seen) else: context = None - self.exc_traceback = exc_traceback self.__cause__ = cause self.__context__ = context self.__suppress_context__ = \ @@ -617,7 +616,7 @@ def format(self, *, chain=True): not self.__suppress_context__): yield from self.__context__.format(chain=chain) yield _context_message - if self.exc_traceback is not None: + if self.stack: yield 'Traceback (most recent call last):\n' - yield from self.stack.format() + yield from self.stack.format() yield from self.format_exception_only() diff --git a/Misc/NEWS.d/next/Library/2020-11-27-16-46-58.bpo-42482.EJC3sd.rst b/Misc/NEWS.d/next/Library/2020-11-27-16-46-58.bpo-42482.EJC3sd.rst new file mode 100644 index 00000000000000..79afa654f352e9 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2020-11-27-16-46-58.bpo-42482.EJC3sd.rst @@ -0,0 +1 @@ +:class:`~traceback.TracebackException` no longer holds a reference to the exception's traceback object. Consequently, instances of TracebackException for equivalent but non-equal exceptions now compare as equal. \ No newline at end of file From d1f07419c7560ed3ba52ba4f667f4eec9b5fe95d Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 4 Dec 2020 14:41:58 -0800 Subject: [PATCH 0775/1314] bpo-17735: inspect.findsource now raises OSError when co_lineno is out of range (GH-23633) This can happen when a file was edited after it was imported. (cherry picked from commit 2e0760bb2edb595050aff82f236cd32b44d3dfb3) Co-authored-by: Irit Katriel --- Lib/inspect.py | 7 ++++++- Lib/test/test_inspect.py | 11 +++++++++++ .../Library/2020-12-03-22-22-24.bpo-17735.Qsaaue.rst | 4 ++++ 3 files changed, 21 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Library/2020-12-03-22-22-24.bpo-17735.Qsaaue.rst diff --git a/Lib/inspect.py b/Lib/inspect.py index 6ca91e401a5eae..18bed9028ed8ab 100644 --- a/Lib/inspect.py +++ b/Lib/inspect.py @@ -864,7 +864,12 @@ def findsource(object): lnum = object.co_firstlineno - 1 pat = re.compile(r'^(\s*def\s)|(\s*async\s+def\s)|(.*(? 0: - if pat.match(lines[lnum]): break + try: + line = lines[lnum] + except IndexError: + raise OSError('lineno is out of bounds') + if pat.match(line): + break lnum = lnum - 1 return lines, lnum raise OSError('could not find code object') diff --git a/Lib/test/test_inspect.py b/Lib/test/test_inspect.py index 05485a0bc05754..d9e26a30336676 100644 --- a/Lib/test/test_inspect.py +++ b/Lib/test/test_inspect.py @@ -710,6 +710,17 @@ def test_findsource_without_filename(self): self.assertRaises(IOError, inspect.findsource, co) self.assertRaises(IOError, inspect.getsource, co) + def test_findsource_with_out_of_bounds_lineno(self): + mod_len = len(inspect.getsource(mod)) + src = '\n' * 2* mod_len + "def f(): pass" + co = compile(src, mod.__file__, "exec") + g, l = {}, {} + eval(co, g, l) + func = l['f'] + self.assertEqual(func.__code__.co_firstlineno, 1+2*mod_len) + with self.assertRaisesRegex(IOError, "lineno is out of bounds"): + inspect.findsource(func) + def test_getsource_on_method(self): self.assertSourceEqual(mod2.ClassWithMethod.method, 118, 119) diff --git a/Misc/NEWS.d/next/Library/2020-12-03-22-22-24.bpo-17735.Qsaaue.rst b/Misc/NEWS.d/next/Library/2020-12-03-22-22-24.bpo-17735.Qsaaue.rst new file mode 100644 index 00000000000000..655781e3d2eddb --- /dev/null +++ b/Misc/NEWS.d/next/Library/2020-12-03-22-22-24.bpo-17735.Qsaaue.rst @@ -0,0 +1,4 @@ +:func:`inspect.findsource` now raises :exc:`OSError` instead of +:exc:`IndexError` when :attr:`co_lineno` of a code object is greater than the +file length. This can happen, for example, when a file is edited after it was +imported. PR by Irit Katriel. From 06002b3f0d4570424feef37103c7e9b7d16bd63d Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 4 Dec 2020 20:26:59 -0800 Subject: [PATCH 0776/1314] [3.9] bpo-41116: Fix setup.py test for macOS Tcl/Tk frameworks (GH-23649) (GH-23650) If no explicit macOS SDK was specified, setup.py should check for Tcl and TK frameworks in /Library/Frameworks; the previous commit inadvertently broke that test. (cherry picked from commit 29afab6c5f656f07ac85c9b2cf089631b2557a11) Co-authored-by: Ned Deily --- .../NEWS.d/next/macOS/2020-12-04-23-09-11.bpo-41116.mSbXyV.rst | 3 +++ setup.py | 3 ++- 2 files changed, 5 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/macOS/2020-12-04-23-09-11.bpo-41116.mSbXyV.rst diff --git a/Misc/NEWS.d/next/macOS/2020-12-04-23-09-11.bpo-41116.mSbXyV.rst b/Misc/NEWS.d/next/macOS/2020-12-04-23-09-11.bpo-41116.mSbXyV.rst new file mode 100644 index 00000000000000..2c8e5ea0297345 --- /dev/null +++ b/Misc/NEWS.d/next/macOS/2020-12-04-23-09-11.bpo-41116.mSbXyV.rst @@ -0,0 +1,3 @@ +If no explicit macOS SDK was specified, setup.py should check for Tcl and TK +frameworks in /Library/Frameworks; the previous commit inadvertently broke +that test. diff --git a/setup.py b/setup.py index bfe621d0b50da1..bd5f73692441cb 100644 --- a/setup.py +++ b/setup.py @@ -177,10 +177,11 @@ def macosx_sdk_root(): m = re.search(r'-isysroot\s*(\S+)', cflags) if m is not None: MACOS_SDK_ROOT = m.group(1) + MACOS_SDK_SPECIFIED = MACOS_SDK_ROOT != '/' else: MACOS_SDK_ROOT = _osx_support._default_sysroot( sysconfig.get_config_var('CC')) - MACOS_SDK_SPECIFIED = MACOS_SDK_ROOT != '/' + MACOS_SDK_SPECIFIED = False return MACOS_SDK_ROOT From b630ca7bc13ba9bdf95cd7dce0ac8e1578fb53a0 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 5 Dec 2020 07:26:37 -0800 Subject: [PATCH 0777/1314] [3.9] bpo-5054: CGIHTTPRequestHandler.run_cgi() HTTP_ACCEPT improperly parsed (GH-23638) (GH-23657) (cherry picked from commit da3d2abe6be9fcf18cac12ec5d7d9f1180d94b5e) Co-authored-by: Senthil Kumaran Automerge-Triggered-By: GH:orsenthil --- Lib/http/server.py | 7 +--- Lib/test/test_httpservers.py | 37 ++++++++++++++++++- .../2020-12-04-03-51-12.bpo-5054.53StYZ.rst | 5 +++ 3 files changed, 41 insertions(+), 8 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2020-12-04-03-51-12.bpo-5054.53StYZ.rst diff --git a/Lib/http/server.py b/Lib/http/server.py index fa204fbc15e3d7..def05f46be4f91 100644 --- a/Lib/http/server.py +++ b/Lib/http/server.py @@ -1123,12 +1123,7 @@ def run_cgi(self): referer = self.headers.get('referer') if referer: env['HTTP_REFERER'] = referer - accept = [] - for line in self.headers.getallmatchingheaders('accept'): - if line[:1] in "\t\n\r ": - accept.append(line.strip()) - else: - accept = accept + line[7:].split(',') + accept = self.headers.get_all('accept', ()) env['HTTP_ACCEPT'] = ','.join(accept) ua = self.headers.get('user-agent') if ua: diff --git a/Lib/test/test_httpservers.py b/Lib/test/test_httpservers.py index c442f5571a8682..8df0b5251f1ae3 100644 --- a/Lib/test/test_httpservers.py +++ b/Lib/test/test_httpservers.py @@ -3,7 +3,7 @@ Written by Cody A.W. Somerville , Josip Dzolonga, and Michael Otteneder for the 2007/08 GHOP contest. """ - +from collections import OrderedDict from http.server import BaseHTTPRequestHandler, HTTPServer, \ SimpleHTTPRequestHandler, CGIHTTPRequestHandler from http import server, HTTPStatus @@ -19,7 +19,7 @@ import email.message import email.utils import html -import http.client +import http, http.client import urllib.parse import tempfile import time @@ -586,6 +586,15 @@ def test_html_escape_filename(self): print(os.environ["%s"]) """ +cgi_file6 = """\ +#!%s +import os + +print("Content-type: text/plain") +print() +print(repr(os.environ)) +""" + @unittest.skipIf(hasattr(os, 'geteuid') and os.geteuid() == 0, "This test can't be run reliably as root (issue #13308).") @@ -664,6 +673,11 @@ def setUp(self): file5.write(cgi_file1 % self.pythonexe) os.chmod(self.file5_path, 0o777) + self.file6_path = os.path.join(self.cgi_dir, 'file6.py') + with open(self.file6_path, 'w', encoding='utf-8') as file6: + file6.write(cgi_file6 % self.pythonexe) + os.chmod(self.file6_path, 0o777) + os.chdir(self.parent_dir) def tearDown(self): @@ -683,6 +697,8 @@ def tearDown(self): os.remove(self.file4_path) if self.file5_path: os.remove(self.file5_path) + if self.file6_path: + os.remove(self.file6_path) os.rmdir(self.cgi_child_dir) os.rmdir(self.cgi_dir) os.rmdir(self.cgi_dir_in_sub_dir) @@ -816,6 +832,23 @@ def test_cgi_path_in_sub_directories(self): finally: CGIHTTPRequestHandler.cgi_directories.remove('/sub/dir/cgi-bin') + def test_accept(self): + browser_accept = \ + 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8' + tests = ( + ((('Accept', browser_accept),), browser_accept), + ((), ''), + # Hack case to get two values for the one header + ((('Accept', 'text/html'), ('ACCEPT', 'text/plain')), + 'text/html,text/plain'), + ) + for headers, expected in tests: + headers = OrderedDict(headers) + with self.subTest(headers): + res = self.request('/cgi-bin/file6.py', 'GET', headers=headers) + self.assertEqual(http.HTTPStatus.OK, res.status) + expected = f"'HTTP_ACCEPT': {expected!r}" + self.assertIn(expected.encode('ascii'), res.read()) class SocketlessRequestHandler(SimpleHTTPRequestHandler): diff --git a/Misc/NEWS.d/next/Library/2020-12-04-03-51-12.bpo-5054.53StYZ.rst b/Misc/NEWS.d/next/Library/2020-12-04-03-51-12.bpo-5054.53StYZ.rst new file mode 100644 index 00000000000000..ad8163c7c1d206 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2020-12-04-03-51-12.bpo-5054.53StYZ.rst @@ -0,0 +1,5 @@ +CGIHTTPRequestHandler.run_cgi() HTTP_ACCEPT improperly parsed. Replace the +special purpose getallmatchingheaders with generic get_all method and add +relevant tests. + +Original Patch by Martin Panter. Modified by Senthil Kumaran. From d5c029b1a9b47737efb8966f804d28b99a2de239 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 5 Dec 2020 08:24:38 -0800 Subject: [PATCH 0778/1314] bpo-42576: Raise TypeError when passing in keyword arguments to GenericAlias (GH-23656) Use `_PyArg_NoKeywords` instead of `_PyArg_NoKwnames` when checking the `kwds` tuple when creating `GenericAlias`. This fixes an interpreter crash when passing in keyword arguments to `GenericAlias`'s constructor. Needs backport to 3.9. Automerge-Triggered-By: GH:gvanrossum (cherry picked from commit 804d6893b801e8f30318afc38c20d4d0e6161db3) Co-authored-by: kj <28750310+Fidget-Spinner@users.noreply.github.com> --- Lib/test/test_genericalias.py | 5 +++++ .../2020-12-05-22-34-47.bpo-42576.lEeEl7.rst | 3 +++ Objects/genericaliasobject.c | 2 +- 3 files changed, 9 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2020-12-05-22-34-47.bpo-42576.lEeEl7.rst diff --git a/Lib/test/test_genericalias.py b/Lib/test/test_genericalias.py index 912fb33af1a21b..c113e538248e9c 100644 --- a/Lib/test/test_genericalias.py +++ b/Lib/test/test_genericalias.py @@ -302,6 +302,11 @@ def test_weakref(self): alias = t[int] self.assertEqual(ref(alias)(), alias) + def test_no_kwargs(self): + # bpo-42576 + with self.assertRaises(TypeError): + GenericAlias(bad=float) + if __name__ == "__main__": unittest.main() diff --git a/Misc/NEWS.d/next/Core and Builtins/2020-12-05-22-34-47.bpo-42576.lEeEl7.rst b/Misc/NEWS.d/next/Core and Builtins/2020-12-05-22-34-47.bpo-42576.lEeEl7.rst new file mode 100644 index 00000000000000..7290b47dcc15ca --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2020-12-05-22-34-47.bpo-42576.lEeEl7.rst @@ -0,0 +1,3 @@ +``types.GenericAlias`` will now raise a ``TypeError`` when attempting to +initialize with a keyword argument. Previously, this would cause the +interpreter to crash. Patch by Ken Jin. diff --git a/Objects/genericaliasobject.c b/Objects/genericaliasobject.c index 4b6c8c6ed8d1fa..c5a81a5c1aab22 100644 --- a/Objects/genericaliasobject.c +++ b/Objects/genericaliasobject.c @@ -566,7 +566,7 @@ static PyGetSetDef ga_properties[] = { static PyObject * ga_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { - if (!_PyArg_NoKwnames("GenericAlias", kwds)) { + if (!_PyArg_NoKeywords("GenericAlias", kwds)) { return NULL; } if (!_PyArg_CheckPositional("GenericAlias", PyTuple_GET_SIZE(args), 2, 2)) { From 8502d46e3649bedf6b58a30b0a4b6b726e32b84b Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 6 Dec 2020 09:00:57 -0800 Subject: [PATCH 0779/1314] [3.9] bpo-42576: Clarify only debug builds are affected in news (GH-23663) (GH-23666) (cherry picked from commit 6a7fb9d31bce8590e30c44458d1fc1da4539743d) Co-authored-by: kj <28750310+Fidget-Spinner@users.noreply.github.com> Automerge-Triggered-By: GH:gvanrossum --- .../Core and Builtins/2020-12-05-22-34-47.bpo-42576.lEeEl7.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Misc/NEWS.d/next/Core and Builtins/2020-12-05-22-34-47.bpo-42576.lEeEl7.rst b/Misc/NEWS.d/next/Core and Builtins/2020-12-05-22-34-47.bpo-42576.lEeEl7.rst index 7290b47dcc15ca..154c9d8a915de1 100644 --- a/Misc/NEWS.d/next/Core and Builtins/2020-12-05-22-34-47.bpo-42576.lEeEl7.rst +++ b/Misc/NEWS.d/next/Core and Builtins/2020-12-05-22-34-47.bpo-42576.lEeEl7.rst @@ -1,3 +1,4 @@ ``types.GenericAlias`` will now raise a ``TypeError`` when attempting to initialize with a keyword argument. Previously, this would cause the -interpreter to crash. Patch by Ken Jin. +interpreter to crash if the interpreter was compiled with debug symbols. +This does not affect interpreters compiled for release. Patch by Ken Jin. From 2a9a883d361d37b40fb0b0011dd300bb83ceb73c Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 6 Dec 2020 19:48:48 -0800 Subject: [PATCH 0780/1314] bpo-42508: Keep IDLE running on macOS (GH-23577) (GH-23669) Remove obsolete workaround that prevented running files with shortcuts when using new universal2 installers built on macOS 11. Ignore buggy 2nd run_module_event call. (cherry picked from commit 57e511361047895231f5ee7abfdfbbc60e11d2db) Co-authored-by: Terry Jan Reedy --- Lib/idlelib/NEWS.txt | 4 +++ Lib/idlelib/runscript.py | 26 +++++-------------- .../2020-11-30-19-46-05.bpo-42508.fE7w4M.rst | 3 +++ 3 files changed, 14 insertions(+), 19 deletions(-) create mode 100644 Misc/NEWS.d/next/IDLE/2020-11-30-19-46-05.bpo-42508.fE7w4M.rst diff --git a/Lib/idlelib/NEWS.txt b/Lib/idlelib/NEWS.txt index e257ee9fdeb32d..869be0a62b7dba 100644 --- a/Lib/idlelib/NEWS.txt +++ b/Lib/idlelib/NEWS.txt @@ -3,6 +3,10 @@ Released on 2020-12-07? ====================================== +bpo-42508: Keep IDLE running on macOS. Remove obsolete workaround +that prevented running files with shortcuts when using new universal2 +installers built on macOS 11. + bpo-42426: Fix reporting offset of the RE error in searchengine. bpo-42416: Get docstrings for IDLE calltips more often diff --git a/Lib/idlelib/runscript.py b/Lib/idlelib/runscript.py index a54108794ab595..028b0dbd21dfe6 100644 --- a/Lib/idlelib/runscript.py +++ b/Lib/idlelib/runscript.py @@ -11,6 +11,7 @@ """ import os import tabnanny +import time import tokenize import tkinter.messagebox as tkMessageBox @@ -42,9 +43,7 @@ def __init__(self, editwin): self.root = self.editwin.root # cli_args is list of strings that extends sys.argv self.cli_args = [] - - if macosx.isCocoaTk(): - self.editwin.text_frame.bind('<>', self._run_module_event) + self.perf = 0.0 # Workaround for macOS 11 Uni2; see bpo-42508. def check_module_event(self, event): if isinstance(self.editwin, outwin.OutputWindow): @@ -107,24 +106,10 @@ def checksyntax(self, filename): finally: shell.set_warning_stream(saved_stream) - def run_module_event(self, event): - if macosx.isCocoaTk(): - # Tk-Cocoa in MacOSX is broken until at least - # Tk 8.5.9, and without this rather - # crude workaround IDLE would hang when a user - # tries to run a module using the keyboard shortcut - # (the menu item works fine). - self.editwin.text_frame.after(200, - lambda: self.editwin.text_frame.event_generate( - '<>')) - return 'break' - else: - return self._run_module_event(event) - def run_custom_event(self, event): - return self._run_module_event(event, customize=True) + return self.run_module_event(event, customize=True) - def _run_module_event(self, event, *, customize=False): + def run_module_event(self, event, *, customize=False): """Run the module after setting up the environment. First check the syntax. Next get customization. If OK, make @@ -133,6 +118,8 @@ def _run_module_event(self, event, *, customize=False): module being executed and also add that directory to its sys.path if not already included. """ + if macosx.isCocoaTk() and (time.perf_counter() - self.perf < .05): + return 'break' if isinstance(self.editwin, outwin.OutputWindow): self.editwin.text.bell() return 'break' @@ -218,6 +205,7 @@ def errorbox(self, title, message): # XXX This should really be a function of EditorWindow... tkMessageBox.showerror(title, message, parent=self.editwin.text) self.editwin.text.focus_set() + self.perf = time.perf_counter() if __name__ == "__main__": diff --git a/Misc/NEWS.d/next/IDLE/2020-11-30-19-46-05.bpo-42508.fE7w4M.rst b/Misc/NEWS.d/next/IDLE/2020-11-30-19-46-05.bpo-42508.fE7w4M.rst new file mode 100644 index 00000000000000..b449351f7f458e --- /dev/null +++ b/Misc/NEWS.d/next/IDLE/2020-11-30-19-46-05.bpo-42508.fE7w4M.rst @@ -0,0 +1,3 @@ +Keep IDLE running on macOS. Remove obsolete workaround that prevented +running files with shortcuts when using new universal2 installers built +on macOS 11. From facca72eae3c0b59b4e89bab81c936dff10fb58a Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 6 Dec 2020 21:17:09 -0800 Subject: [PATCH 0781/1314] bpo-38843: Document behavior of default when the attribute is already set (GH-23653) (#23668) (cherry picked from commit 752cdf21eb2be0a26ea6a34a0de33a458459aead) Co-authored-by: Raymond Hettinger Co-authored-by: Raymond Hettinger --- Doc/library/argparse.rst | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/Doc/library/argparse.rst b/Doc/library/argparse.rst index a32b99901a7b4e..02cd70f4f71cd6 100644 --- a/Doc/library/argparse.rst +++ b/Doc/library/argparse.rst @@ -696,7 +696,7 @@ The add_argument() method * const_ - A constant value required by some action_ and nargs_ selections. * default_ - The value produced if the argument is absent from the - command line. + command line and if it is absent from the namespace object. * type_ - The type to which the command-line argument should be converted. @@ -1006,6 +1006,14 @@ was not present at the command line:: >>> parser.parse_args([]) Namespace(foo=42) +If the target namespace already has an attribute set, the action *default* +will not over write it:: + + >>> parser = argparse.ArgumentParser() + >>> parser.add_argument('--foo', default=42) + >>> parser.parse_args([], namespace=argparse.Namespace(foo=101)) + Namespace(foo=101) + If the ``default`` value is a string, the parser parses the value as if it were a command-line argument. In particular, the parser applies any type_ conversion argument, if provided, before setting the attribute on the From 1e5d33e9b9b8631b36f061103a30208b206fd03a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Langa?= Date: Mon, 7 Dec 2020 15:02:38 +0100 Subject: [PATCH 0782/1314] Python 3.9.1 --- Include/patchlevel.h | 6 +- Lib/pydoc_data/topics.py | 103 +++++++----- Misc/NEWS.d/3.9.1.rst | 150 ++++++++++++++++++ .../2020-12-05-22-34-47.bpo-42576.lEeEl7.rst | 4 - .../2020-11-30-19-46-05.bpo-42508.fE7w4M.rst | 3 - .../2020-07-09-11-32-28.bpo-12800.fNgWwx.rst | 4 - .../2020-08-19-20-17-51.bpo-34215._Cv8c-.rst | 2 - .../2020-11-19-10-44-41.bpo-42406.r9rNCj.rst | 3 - .../2020-11-27-16-46-58.bpo-42482.EJC3sd.rst | 1 - .../2020-11-28-04-31-20.bpo-42487.iqtC4L.rst | 1 - .../2020-12-03-15-42-32.bpo-42116.yIwroP.rst | 1 - .../2020-12-03-22-22-24.bpo-17735.Qsaaue.rst | 4 - .../2020-12-04-03-51-12.bpo-5054.53StYZ.rst | 5 - .../2020-12-03-13-32-44.bpo-42553.2TRE2N.rst | 3 - .../2020-12-04-11-47-09.bpo-41473.W_updK.rst | 3 - .../2020-12-02-15-48-40.bpo-42504.RQmMOR.rst | 1 - .../2020-12-04-23-09-11.bpo-41116.mSbXyV.rst | 3 - README.rst | 4 +- 18 files changed, 221 insertions(+), 80 deletions(-) create mode 100644 Misc/NEWS.d/3.9.1.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2020-12-05-22-34-47.bpo-42576.lEeEl7.rst delete mode 100644 Misc/NEWS.d/next/IDLE/2020-11-30-19-46-05.bpo-42508.fE7w4M.rst delete mode 100644 Misc/NEWS.d/next/Library/2020-07-09-11-32-28.bpo-12800.fNgWwx.rst delete mode 100644 Misc/NEWS.d/next/Library/2020-08-19-20-17-51.bpo-34215._Cv8c-.rst delete mode 100644 Misc/NEWS.d/next/Library/2020-11-19-10-44-41.bpo-42406.r9rNCj.rst delete mode 100644 Misc/NEWS.d/next/Library/2020-11-27-16-46-58.bpo-42482.EJC3sd.rst delete mode 100644 Misc/NEWS.d/next/Library/2020-11-28-04-31-20.bpo-42487.iqtC4L.rst delete mode 100644 Misc/NEWS.d/next/Library/2020-12-03-15-42-32.bpo-42116.yIwroP.rst delete mode 100644 Misc/NEWS.d/next/Library/2020-12-03-22-22-24.bpo-17735.Qsaaue.rst delete mode 100644 Misc/NEWS.d/next/Library/2020-12-04-03-51-12.bpo-5054.53StYZ.rst delete mode 100644 Misc/NEWS.d/next/Tests/2020-12-03-13-32-44.bpo-42553.2TRE2N.rst delete mode 100644 Misc/NEWS.d/next/Tests/2020-12-04-11-47-09.bpo-41473.W_updK.rst delete mode 100644 Misc/NEWS.d/next/macOS/2020-12-02-15-48-40.bpo-42504.RQmMOR.rst delete mode 100644 Misc/NEWS.d/next/macOS/2020-12-04-23-09-11.bpo-41116.mSbXyV.rst diff --git a/Include/patchlevel.h b/Include/patchlevel.h index 09db42f19fd760..0b5d280bd4fd4b 100644 --- a/Include/patchlevel.h +++ b/Include/patchlevel.h @@ -19,11 +19,11 @@ #define PY_MAJOR_VERSION 3 #define PY_MINOR_VERSION 9 #define PY_MICRO_VERSION 1 -#define PY_RELEASE_LEVEL PY_RELEASE_LEVEL_GAMMA -#define PY_RELEASE_SERIAL 1 +#define PY_RELEASE_LEVEL PY_RELEASE_LEVEL_FINAL +#define PY_RELEASE_SERIAL 0 /* Version as a string */ -#define PY_VERSION "3.9.1rc1+" +#define PY_VERSION "3.9.1" /*--end constants--*/ /* Version as a single 4-byte hex number, e.g. 0x010502B2 == 1.5.2b2. diff --git a/Lib/pydoc_data/topics.py b/Lib/pydoc_data/topics.py index 6411c8cd6be757..d8dd8c536aa708 100644 --- a/Lib/pydoc_data/topics.py +++ b/Lib/pydoc_data/topics.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -# Autogenerated by Sphinx on Tue Nov 24 17:42:56 2020 +# Autogenerated by Sphinx on Mon Dec 7 15:00:07 2020 topics = {'assert': 'The "assert" statement\n' '**********************\n' '\n' @@ -5307,24 +5307,23 @@ 'for the\n' 'conversion. The alternate form is defined differently for ' 'different\n' - 'types. This option is only valid for integer, float, ' - 'complex and\n' - 'Decimal types. For integers, when binary, octal, or ' - 'hexadecimal output\n' - 'is used, this option adds the prefix respective "\'0b\'", ' - '"\'0o\'", or\n' - '"\'0x\'" to the output value. For floats, complex and ' - 'Decimal the\n' - 'alternate form causes the result of the conversion to ' - 'always contain a\n' - 'decimal-point character, even if no digits follow it. ' - 'Normally, a\n' - 'decimal-point character appears in the result of these ' - 'conversions\n' - 'only if a digit follows it. In addition, for "\'g\'" and ' - '"\'G\'"\n' - 'conversions, trailing zeros are not removed from the ' - 'result.\n' + 'types. This option is only valid for integer, float and ' + 'complex\n' + 'types. For integers, when binary, octal, or hexadecimal ' + 'output is\n' + 'used, this option adds the prefix respective "\'0b\'", ' + '"\'0o\'", or "\'0x\'"\n' + 'to the output value. For float and complex the alternate ' + 'form causes\n' + 'the result of the conversion to always contain a ' + 'decimal-point\n' + 'character, even if no digits follow it. Normally, a ' + 'decimal-point\n' + 'character appears in the result of these conversions only ' + 'if a digit\n' + 'follows it. In addition, for "\'g\'" and "\'G\'" ' + 'conversions, trailing\n' + 'zeros are not removed from the result.\n' '\n' 'The "\',\'" option signals the use of a comma for a ' 'thousands separator.\n' @@ -5462,9 +5461,8 @@ 'the integer\n' 'to a floating point number before formatting.\n' '\n' - 'The available presentation types for floating point and ' - 'decimal values\n' - 'are:\n' + 'The available presentation types for "float" and "Decimal" ' + 'values are:\n' '\n' ' ' '+-----------+------------------------------------------------------------+\n' @@ -5473,24 +5471,50 @@ '|\n' ' ' '|===========|============================================================|\n' - ' | "\'e\'" | Exponent notation. Prints the number in ' - 'scientific |\n' - ' | | notation using the letter ‘e’ to indicate ' - 'the exponent. |\n' - ' | | The default precision is ' - '"6". |\n' + ' | "\'e\'" | Scientific notation. For a given ' + 'precision "p", formats |\n' + ' | | the number in scientific notation with the ' + 'letter ‘e’ |\n' + ' | | separating the coefficient from the ' + 'exponent. The |\n' + ' | | coefficient has one digit before and "p" ' + 'digits after the |\n' + ' | | decimal point, for a total of "p + 1" ' + 'significant digits. |\n' + ' | | With no precision given, uses a precision ' + 'of "6" digits |\n' + ' | | after the decimal point for "float", and ' + 'shows all |\n' + ' | | coefficient digits for "Decimal". If no ' + 'digits follow the |\n' + ' | | decimal point, the decimal point is also ' + 'removed unless |\n' + ' | | the "#" option is ' + 'used. |\n' ' ' '+-----------+------------------------------------------------------------+\n' - ' | "\'E\'" | Exponent notation. Same as "\'e\'" ' - 'except it uses an upper |\n' + ' | "\'E\'" | Scientific notation. Same as "\'e\'" ' + 'except it uses an upper |\n' ' | | case ‘E’ as the separator ' 'character. |\n' ' ' '+-----------+------------------------------------------------------------+\n' - ' | "\'f\'" | Fixed-point notation. Displays the ' - 'number as a fixed-point |\n' - ' | | number. The default precision is ' - '"6". |\n' + ' | "\'f\'" | Fixed-point notation. For a given ' + 'precision "p", formats |\n' + ' | | the number as a decimal number with ' + 'exactly "p" digits |\n' + ' | | following the decimal point. With no ' + 'precision given, uses |\n' + ' | | a precision of "6" digits after the ' + 'decimal point for |\n' + ' | | "float", and uses a precision large enough ' + 'to show all |\n' + ' | | coefficient digits for "Decimal". If no ' + 'digits follow the |\n' + ' | | decimal point, the decimal point is also ' + 'removed unless |\n' + ' | | the "#" option is ' + 'used. |\n' ' ' '+-----------+------------------------------------------------------------+\n' ' | "\'F\'" | Fixed-point notation. Same as "\'f\'", ' @@ -5536,9 +5560,14 @@ ' | | regardless of the precision. A precision ' 'of "0" is |\n' ' | | treated as equivalent to a precision of ' - '"1". The default |\n' - ' | | precision is ' - '"6". |\n' + '"1". With no |\n' + ' | | precision given, uses a precision of "6" ' + 'significant |\n' + ' | | digits for "float", and shows all ' + 'coefficient digits for |\n' + ' | | ' + '"Decimal". ' + '|\n' ' ' '+-----------+------------------------------------------------------------+\n' ' | "\'G\'" | General format. Same as "\'g\'" except ' diff --git a/Misc/NEWS.d/3.9.1.rst b/Misc/NEWS.d/3.9.1.rst new file mode 100644 index 00000000000000..3942753a60e291 --- /dev/null +++ b/Misc/NEWS.d/3.9.1.rst @@ -0,0 +1,150 @@ +.. bpo: 42576 +.. date: 2020-12-05-22-34-47 +.. nonce: lEeEl7 +.. release date: 2020-12-07 +.. section: Core and Builtins + +``types.GenericAlias`` will now raise a ``TypeError`` when attempting to +initialize with a keyword argument. Previously, this would cause the +interpreter to crash if the interpreter was compiled with debug symbols. +This does not affect interpreters compiled for release. Patch by Ken Jin. + +.. + +.. bpo: 5054 +.. date: 2020-12-04-03-51-12 +.. nonce: 53StYZ +.. section: Library + +CGIHTTPRequestHandler.run_cgi() HTTP_ACCEPT improperly parsed. Replace the +special purpose getallmatchingheaders with generic get_all method and add +relevant tests. + +Original Patch by Martin Panter. Modified by Senthil Kumaran. + +.. + +.. bpo: 17735 +.. date: 2020-12-03-22-22-24 +.. nonce: Qsaaue +.. section: Library + +:func:`inspect.findsource` now raises :exc:`OSError` instead of +:exc:`IndexError` when :attr:`co_lineno` of a code object is greater than +the file length. This can happen, for example, when a file is edited after +it was imported. PR by Irit Katriel. + +.. + +.. bpo: 42116 +.. date: 2020-12-03-15-42-32 +.. nonce: yIwroP +.. section: Library + +Fix handling of trailing comments by :func:`inspect.getsource`. + +.. + +.. bpo: 42487 +.. date: 2020-11-28-04-31-20 +.. nonce: iqtC4L +.. section: Library + +ChainMap.__iter__ no longer calls __getitem__ on underlying maps + +.. + +.. bpo: 42482 +.. date: 2020-11-27-16-46-58 +.. nonce: EJC3sd +.. section: Library + +:class:`~traceback.TracebackException` no longer holds a reference to the +exception's traceback object. Consequently, instances of TracebackException +for equivalent but non-equal exceptions now compare as equal. + +.. + +.. bpo: 42406 +.. date: 2020-11-19-10-44-41 +.. nonce: r9rNCj +.. section: Library + +We fixed an issue in `pickle.whichmodule` in which importing +`multiprocessing` could change the how pickle identifies which module an +object belongs to, potentially breaking the unpickling of those objects. + +.. + +.. bpo: 34215 +.. date: 2020-08-19-20-17-51 +.. nonce: _Cv8c- +.. section: Library + +Clarify the error message for :exc:`asyncio.IncompleteReadError` when +``expected`` is ``None``. + +.. + +.. bpo: 12800 +.. date: 2020-07-09-11-32-28 +.. nonce: fNgWwx +.. section: Library + +Extracting a symlink from a tarball should succeed and overwrite the symlink +if it already exists. The fix is to remove the existing file or symlink +before extraction. Based on patch by Chris AtLee, Jeffrey Kintscher, and +Senthil Kumaran. + +.. + +.. bpo: 41473 +.. date: 2020-12-04-11-47-09 +.. nonce: W_updK +.. section: Tests + +Reenable test_gdb on gdb 9.2 and newer: +https://bugzilla.redhat.com/show_bug.cgi?id=1866884 bug is fixed in gdb +10.1. + +.. + +.. bpo: 42553 +.. date: 2020-12-03-13-32-44 +.. nonce: 2TRE2N +.. section: Tests + +Fix ``test_asyncio.test_call_later()`` race condition: don't measure asyncio +performance in the ``call_later()`` unit test. The test failed randomly on +the CI. + +.. + +.. bpo: 41116 +.. date: 2020-12-04-23-09-11 +.. nonce: mSbXyV +.. section: macOS + +If no explicit macOS SDK was specified, setup.py should check for Tcl and TK +frameworks in /Library/Frameworks; the previous commit inadvertently broke +that test. + +.. + +.. bpo: 42504 +.. date: 2020-12-02-15-48-40 +.. nonce: RQmMOR +.. section: macOS + +Fix build on macOS Big Sur when MACOSX_DEPLOYMENT_TARGET=11 + +.. + +.. bpo: 42508 +.. date: 2020-11-30-19-46-05 +.. nonce: fE7w4M +.. section: IDLE + +Keep IDLE running on macOS. Remove obsolete workaround that prevented +running files with shortcuts when using new universal2 installers built on +macOS 11. diff --git a/Misc/NEWS.d/next/Core and Builtins/2020-12-05-22-34-47.bpo-42576.lEeEl7.rst b/Misc/NEWS.d/next/Core and Builtins/2020-12-05-22-34-47.bpo-42576.lEeEl7.rst deleted file mode 100644 index 154c9d8a915de1..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2020-12-05-22-34-47.bpo-42576.lEeEl7.rst +++ /dev/null @@ -1,4 +0,0 @@ -``types.GenericAlias`` will now raise a ``TypeError`` when attempting to -initialize with a keyword argument. Previously, this would cause the -interpreter to crash if the interpreter was compiled with debug symbols. -This does not affect interpreters compiled for release. Patch by Ken Jin. diff --git a/Misc/NEWS.d/next/IDLE/2020-11-30-19-46-05.bpo-42508.fE7w4M.rst b/Misc/NEWS.d/next/IDLE/2020-11-30-19-46-05.bpo-42508.fE7w4M.rst deleted file mode 100644 index b449351f7f458e..00000000000000 --- a/Misc/NEWS.d/next/IDLE/2020-11-30-19-46-05.bpo-42508.fE7w4M.rst +++ /dev/null @@ -1,3 +0,0 @@ -Keep IDLE running on macOS. Remove obsolete workaround that prevented -running files with shortcuts when using new universal2 installers built -on macOS 11. diff --git a/Misc/NEWS.d/next/Library/2020-07-09-11-32-28.bpo-12800.fNgWwx.rst b/Misc/NEWS.d/next/Library/2020-07-09-11-32-28.bpo-12800.fNgWwx.rst deleted file mode 100644 index fdd7c5e74f33a3..00000000000000 --- a/Misc/NEWS.d/next/Library/2020-07-09-11-32-28.bpo-12800.fNgWwx.rst +++ /dev/null @@ -1,4 +0,0 @@ -Extracting a symlink from a tarball should succeed and overwrite the symlink -if it already exists. The fix is to remove the existing file or symlink -before extraction. Based on patch by Chris AtLee, Jeffrey Kintscher, and -Senthil Kumaran. diff --git a/Misc/NEWS.d/next/Library/2020-08-19-20-17-51.bpo-34215._Cv8c-.rst b/Misc/NEWS.d/next/Library/2020-08-19-20-17-51.bpo-34215._Cv8c-.rst deleted file mode 100644 index 4d91678948f40a..00000000000000 --- a/Misc/NEWS.d/next/Library/2020-08-19-20-17-51.bpo-34215._Cv8c-.rst +++ /dev/null @@ -1,2 +0,0 @@ -Clarify the error message for :exc:`asyncio.IncompleteReadError` when -``expected`` is ``None``. diff --git a/Misc/NEWS.d/next/Library/2020-11-19-10-44-41.bpo-42406.r9rNCj.rst b/Misc/NEWS.d/next/Library/2020-11-19-10-44-41.bpo-42406.r9rNCj.rst deleted file mode 100644 index c157df138a5ea0..00000000000000 --- a/Misc/NEWS.d/next/Library/2020-11-19-10-44-41.bpo-42406.r9rNCj.rst +++ /dev/null @@ -1,3 +0,0 @@ -We fixed an issue in `pickle.whichmodule` in which importing -`multiprocessing` could change the how pickle identifies which module an -object belongs to, potentially breaking the unpickling of those objects. diff --git a/Misc/NEWS.d/next/Library/2020-11-27-16-46-58.bpo-42482.EJC3sd.rst b/Misc/NEWS.d/next/Library/2020-11-27-16-46-58.bpo-42482.EJC3sd.rst deleted file mode 100644 index 79afa654f352e9..00000000000000 --- a/Misc/NEWS.d/next/Library/2020-11-27-16-46-58.bpo-42482.EJC3sd.rst +++ /dev/null @@ -1 +0,0 @@ -:class:`~traceback.TracebackException` no longer holds a reference to the exception's traceback object. Consequently, instances of TracebackException for equivalent but non-equal exceptions now compare as equal. \ No newline at end of file diff --git a/Misc/NEWS.d/next/Library/2020-11-28-04-31-20.bpo-42487.iqtC4L.rst b/Misc/NEWS.d/next/Library/2020-11-28-04-31-20.bpo-42487.iqtC4L.rst deleted file mode 100644 index 8c67d747b614ee..00000000000000 --- a/Misc/NEWS.d/next/Library/2020-11-28-04-31-20.bpo-42487.iqtC4L.rst +++ /dev/null @@ -1 +0,0 @@ -ChainMap.__iter__ no longer calls __getitem__ on underlying maps diff --git a/Misc/NEWS.d/next/Library/2020-12-03-15-42-32.bpo-42116.yIwroP.rst b/Misc/NEWS.d/next/Library/2020-12-03-15-42-32.bpo-42116.yIwroP.rst deleted file mode 100644 index febda89338ddc7..00000000000000 --- a/Misc/NEWS.d/next/Library/2020-12-03-15-42-32.bpo-42116.yIwroP.rst +++ /dev/null @@ -1 +0,0 @@ -Fix handling of trailing comments by :func:`inspect.getsource`. \ No newline at end of file diff --git a/Misc/NEWS.d/next/Library/2020-12-03-22-22-24.bpo-17735.Qsaaue.rst b/Misc/NEWS.d/next/Library/2020-12-03-22-22-24.bpo-17735.Qsaaue.rst deleted file mode 100644 index 655781e3d2eddb..00000000000000 --- a/Misc/NEWS.d/next/Library/2020-12-03-22-22-24.bpo-17735.Qsaaue.rst +++ /dev/null @@ -1,4 +0,0 @@ -:func:`inspect.findsource` now raises :exc:`OSError` instead of -:exc:`IndexError` when :attr:`co_lineno` of a code object is greater than the -file length. This can happen, for example, when a file is edited after it was -imported. PR by Irit Katriel. diff --git a/Misc/NEWS.d/next/Library/2020-12-04-03-51-12.bpo-5054.53StYZ.rst b/Misc/NEWS.d/next/Library/2020-12-04-03-51-12.bpo-5054.53StYZ.rst deleted file mode 100644 index ad8163c7c1d206..00000000000000 --- a/Misc/NEWS.d/next/Library/2020-12-04-03-51-12.bpo-5054.53StYZ.rst +++ /dev/null @@ -1,5 +0,0 @@ -CGIHTTPRequestHandler.run_cgi() HTTP_ACCEPT improperly parsed. Replace the -special purpose getallmatchingheaders with generic get_all method and add -relevant tests. - -Original Patch by Martin Panter. Modified by Senthil Kumaran. diff --git a/Misc/NEWS.d/next/Tests/2020-12-03-13-32-44.bpo-42553.2TRE2N.rst b/Misc/NEWS.d/next/Tests/2020-12-03-13-32-44.bpo-42553.2TRE2N.rst deleted file mode 100644 index 872214284728bc..00000000000000 --- a/Misc/NEWS.d/next/Tests/2020-12-03-13-32-44.bpo-42553.2TRE2N.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix ``test_asyncio.test_call_later()`` race condition: don't measure asyncio -performance in the ``call_later()`` unit test. The test failed randomly on -the CI. diff --git a/Misc/NEWS.d/next/Tests/2020-12-04-11-47-09.bpo-41473.W_updK.rst b/Misc/NEWS.d/next/Tests/2020-12-04-11-47-09.bpo-41473.W_updK.rst deleted file mode 100644 index 9e0a375a9b7f25..00000000000000 --- a/Misc/NEWS.d/next/Tests/2020-12-04-11-47-09.bpo-41473.W_updK.rst +++ /dev/null @@ -1,3 +0,0 @@ -Reenable test_gdb on gdb 9.2 and newer: -https://bugzilla.redhat.com/show_bug.cgi?id=1866884 bug is fixed in gdb -10.1. diff --git a/Misc/NEWS.d/next/macOS/2020-12-02-15-48-40.bpo-42504.RQmMOR.rst b/Misc/NEWS.d/next/macOS/2020-12-02-15-48-40.bpo-42504.RQmMOR.rst deleted file mode 100644 index c83bc2b9eeec5f..00000000000000 --- a/Misc/NEWS.d/next/macOS/2020-12-02-15-48-40.bpo-42504.RQmMOR.rst +++ /dev/null @@ -1 +0,0 @@ -Fix build on macOS Big Sur when MACOSX_DEPLOYMENT_TARGET=11 \ No newline at end of file diff --git a/Misc/NEWS.d/next/macOS/2020-12-04-23-09-11.bpo-41116.mSbXyV.rst b/Misc/NEWS.d/next/macOS/2020-12-04-23-09-11.bpo-41116.mSbXyV.rst deleted file mode 100644 index 2c8e5ea0297345..00000000000000 --- a/Misc/NEWS.d/next/macOS/2020-12-04-23-09-11.bpo-41116.mSbXyV.rst +++ /dev/null @@ -1,3 +0,0 @@ -If no explicit macOS SDK was specified, setup.py should check for Tcl and TK -frameworks in /Library/Frameworks; the previous commit inadvertently broke -that test. diff --git a/README.rst b/README.rst index 18dd74caf23a6c..a9ab26056c588a 100644 --- a/README.rst +++ b/README.rst @@ -1,5 +1,5 @@ -This is Python version 3.9.1rc1 -=============================== +This is Python version 3.9.1 +============================ .. image:: https://travis-ci.org/python/cpython.svg?branch=3.9 :alt: CPython build status on Travis CI From e9a6dcdefabb6c19074566f4ee0e02daaf57be18 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 7 Dec 2020 09:56:44 -0800 Subject: [PATCH 0783/1314] bpo-39825: Fixes sysconfig.get_config_var('EXT_SUFFIX') on Windows to match distutils (GH-22088) (cherry picked from commit c0afb7fa0ebd1c0e95c0760bbe75a99a8dd12ea6) Co-authored-by: Matti Picus --- Lib/sysconfig.py | 3 ++- Lib/test/test_sysconfig.py | 4 +++- .../next/Library/2020-10-20-08-28-26.bpo-39825.n6KnG0.rst | 5 +++++ 3 files changed, 10 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2020-10-20-08-28-26.bpo-39825.n6KnG0.rst diff --git a/Lib/sysconfig.py b/Lib/sysconfig.py index bf04ac541e6b02..59da8e529025d2 100644 --- a/Lib/sysconfig.py +++ b/Lib/sysconfig.py @@ -424,10 +424,11 @@ def _init_posix(vars): def _init_non_posix(vars): """Initialize the module as appropriate for NT""" # set basic install directories + import _imp vars['LIBDEST'] = get_path('stdlib') vars['BINLIBDEST'] = get_path('platstdlib') vars['INCLUDEPY'] = get_path('include') - vars['EXT_SUFFIX'] = '.pyd' + vars['EXT_SUFFIX'] = _imp.extension_suffixes()[0] vars['EXE'] = '.exe' vars['VERSION'] = _PY_VERSION_SHORT_NO_DOT vars['BINDIR'] = os.path.dirname(_safe_realpath(sys.executable)) diff --git a/Lib/test/test_sysconfig.py b/Lib/test/test_sysconfig.py index 44e44bf5ea995f..0ca5c9390dbb9a 100644 --- a/Lib/test/test_sysconfig.py +++ b/Lib/test/test_sysconfig.py @@ -358,10 +358,12 @@ def test_SO_value(self): @unittest.skipIf(sysconfig.get_config_var('EXT_SUFFIX') is None, 'EXT_SUFFIX required for this test') - def test_SO_in_vars(self): + def test_EXT_SUFFIX_in_vars(self): + import _imp vars = sysconfig.get_config_vars() self.assertIsNotNone(vars['SO']) self.assertEqual(vars['SO'], vars['EXT_SUFFIX']) + self.assertEqual(vars['EXT_SUFFIX'], _imp.extension_suffixes()[0]) @unittest.skipUnless(sys.platform == 'linux' and hasattr(sys.implementation, '_multiarch'), diff --git a/Misc/NEWS.d/next/Library/2020-10-20-08-28-26.bpo-39825.n6KnG0.rst b/Misc/NEWS.d/next/Library/2020-10-20-08-28-26.bpo-39825.n6KnG0.rst new file mode 100644 index 00000000000000..c337731f435843 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2020-10-20-08-28-26.bpo-39825.n6KnG0.rst @@ -0,0 +1,5 @@ +Windows: Change ``sysconfig.get_config_var('EXT_SUFFIX')`` to the expected +full ``platform_tag.extension`` format. Previously it was hard-coded to +``.pyd``, now it is compatible with ``distutils.sysconfig`` and will result +in something like ``.cp38-win_amd64.pyd``. This brings windows into +conformance with the other platforms. From 60463e8e4f79e5b5e96dc43fb83ded373b489e33 Mon Sep 17 00:00:00 2001 From: Brandt Bucher Date: Mon, 7 Dec 2020 12:07:48 -0800 Subject: [PATCH 0784/1314] bpo-42536: GC track recycled tuples (GH-23623) (GH-23651) Several built-in and standard library types now ensure that their internal result tuples are always tracked by the garbage collector: - collections.OrderedDict.items - dict.items - enumerate - functools.reduce - itertools.combinations - itertools.combinations_with_replacement - itertools.permutations - itertools.product - itertools.zip_longest - zip Previously, they could have become untracked by a prior garbage collection. (cherry picked from commit 226a012d1cd61f42ecd3056c554922f359a1a35d) --- Lib/test/test_builtin.py | 13 +++++ Lib/test/test_dict.py | 19 ++++++++ Lib/test/test_enumerate.py | 13 +++++ Lib/test/test_itertools.py | 47 +++++++++++++++++++ Lib/test/test_ordered_dict.py | 11 +++++ .../2020-12-02-20-23-31.bpo-42536.Kx3ZOu.rst | 26 ++++++++++ Modules/_functoolsmodule.c | 6 +++ Modules/itertoolsmodule.c | 26 ++++++++++ Objects/dictobject.c | 10 ++++ Objects/enumobject.c | 11 +++++ Objects/odictobject.c | 5 ++ Python/bltinmodule.c | 5 ++ 12 files changed, 192 insertions(+) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2020-12-02-20-23-31.bpo-42536.Kx3ZOu.rst diff --git a/Lib/test/test_builtin.py b/Lib/test/test_builtin.py index 4df1b95bca79af..d009f57e47e05a 100644 --- a/Lib/test/test_builtin.py +++ b/Lib/test/test_builtin.py @@ -6,6 +6,7 @@ import collections import decimal import fractions +import gc import io import locale import os @@ -1606,6 +1607,18 @@ def __iter__(self): self.assertIs(cm.exception, exception) + @support.cpython_only + def test_zip_result_gc(self): + # bpo-42536: zip's tuple-reuse speed trick breaks the GC's assumptions + # about what can be untracked. Make sure we re-track result tuples + # whenever we reuse them. + it = zip([[]]) + gc.collect() + # That GC collection probably untracked the recycled internal result + # tuple, which is initialized to (None,). Make sure it's re-tracked when + # it's mutated and returned from __next__: + self.assertTrue(gc.is_tracked(next(it))) + def test_format(self): # Test the basic machinery of the format() builtin. Don't test # the specifics of the various formatters diff --git a/Lib/test/test_dict.py b/Lib/test/test_dict.py index 6b8596fff6a9f7..b10c07534ddb21 100644 --- a/Lib/test/test_dict.py +++ b/Lib/test/test_dict.py @@ -1422,6 +1422,25 @@ def items(self): d = CustomReversedDict(pairs) self.assertEqual(pairs[::-1], list(dict(d).items())) + @support.cpython_only + def test_dict_items_result_gc(self): + # bpo-42536: dict.items's tuple-reuse speed trick breaks the GC's + # assumptions about what can be untracked. Make sure we re-track result + # tuples whenever we reuse them. + it = iter({None: []}.items()) + gc.collect() + # That GC collection probably untracked the recycled internal result + # tuple, which is initialized to (None, None). Make sure it's re-tracked + # when it's mutated and returned from __next__: + self.assertTrue(gc.is_tracked(next(it))) + + @support.cpython_only + def test_dict_items_result_gc(self): + # Same as test_dict_items_result_gc above, but reversed. + it = reversed({None: []}.items()) + gc.collect() + self.assertTrue(gc.is_tracked(next(it))) + class CAPITest(unittest.TestCase): diff --git a/Lib/test/test_enumerate.py b/Lib/test/test_enumerate.py index 5785cb46492ef7..906bfc21a26aed 100644 --- a/Lib/test/test_enumerate.py +++ b/Lib/test/test_enumerate.py @@ -2,6 +2,7 @@ import operator import sys import pickle +import gc from test import support @@ -134,6 +135,18 @@ def test_tuple_reuse(self): self.assertEqual(len(set(map(id, list(enumerate(self.seq))))), len(self.seq)) self.assertEqual(len(set(map(id, enumerate(self.seq)))), min(1,len(self.seq))) + @support.cpython_only + def test_enumerate_result_gc(self): + # bpo-42536: enumerate's tuple-reuse speed trick breaks the GC's + # assumptions about what can be untracked. Make sure we re-track result + # tuples whenever we reuse them. + it = self.enum([[]]) + gc.collect() + # That GC collection probably untracked the recycled internal result + # tuple, which is initialized to (None, None). Make sure it's re-tracked + # when it's mutated and returned from __next__: + self.assertTrue(gc.is_tracked(next(it))) + class MyEnum(enumerate): pass diff --git a/Lib/test/test_itertools.py b/Lib/test/test_itertools.py index 702cf0820316b1..71012642849198 100644 --- a/Lib/test/test_itertools.py +++ b/Lib/test/test_itertools.py @@ -12,6 +12,8 @@ import sys import struct import threading +import gc + maxsize = support.MAX_Py_ssize_t minsize = -maxsize-1 @@ -1554,6 +1556,51 @@ def test_StopIteration(self): self.assertRaises(StopIteration, next, f(lambda x:x, [])) self.assertRaises(StopIteration, next, f(lambda x:x, StopNow())) + @support.cpython_only + def test_combinations_result_gc(self): + # bpo-42536: combinations's tuple-reuse speed trick breaks the GC's + # assumptions about what can be untracked. Make sure we re-track result + # tuples whenever we reuse them. + it = combinations([None, []], 1) + next(it) + gc.collect() + # That GC collection probably untracked the recycled internal result + # tuple, which has the value (None,). Make sure it's re-tracked when + # it's mutated and returned from __next__: + self.assertTrue(gc.is_tracked(next(it))) + + @support.cpython_only + def test_combinations_with_replacement_result_gc(self): + # Ditto for combinations_with_replacement. + it = combinations_with_replacement([None, []], 1) + next(it) + gc.collect() + self.assertTrue(gc.is_tracked(next(it))) + + @support.cpython_only + def test_permutations_result_gc(self): + # Ditto for permutations. + it = permutations([None, []], 1) + next(it) + gc.collect() + self.assertTrue(gc.is_tracked(next(it))) + + @support.cpython_only + def test_product_result_gc(self): + # Ditto for product. + it = product([None, []]) + next(it) + gc.collect() + self.assertTrue(gc.is_tracked(next(it))) + + @support.cpython_only + def test_zip_longest_result_gc(self): + # Ditto for zip_longest. + it = zip_longest([[]]) + gc.collect() + self.assertTrue(gc.is_tracked(next(it))) + + class TestExamples(unittest.TestCase): def test_accumulate(self): diff --git a/Lib/test/test_ordered_dict.py b/Lib/test/test_ordered_dict.py index fdea44e4d85965..9df4efbfffa22d 100644 --- a/Lib/test/test_ordered_dict.py +++ b/Lib/test/test_ordered_dict.py @@ -697,6 +697,17 @@ def test_merge_operator(self): with self.assertRaises(ValueError): a |= "BAD" + @support.cpython_only + def test_ordered_dict_items_result_gc(self): + # bpo-42536: OrderedDict.items's tuple-reuse speed trick breaks the GC's + # assumptions about what can be untracked. Make sure we re-track result + # tuples whenever we reuse them. + it = iter(self.OrderedDict({None: []}).items()) + gc.collect() + # That GC collection probably untracked the recycled internal result + # tuple, which is initialized to (None, None). Make sure it's re-tracked + # when it's mutated and returned from __next__: + self.assertTrue(gc.is_tracked(next(it))) class PurePythonOrderedDictTests(OrderedDictTests, unittest.TestCase): diff --git a/Misc/NEWS.d/next/Core and Builtins/2020-12-02-20-23-31.bpo-42536.Kx3ZOu.rst b/Misc/NEWS.d/next/Core and Builtins/2020-12-02-20-23-31.bpo-42536.Kx3ZOu.rst new file mode 100644 index 00000000000000..6ccacab1f64f68 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2020-12-02-20-23-31.bpo-42536.Kx3ZOu.rst @@ -0,0 +1,26 @@ +Several built-in and standard library types now ensure that their internal +result tuples are always tracked by the :term:`garbage collector +`: + +- :meth:`collections.OrderedDict.items() ` + +- :meth:`dict.items` + +- :func:`enumerate` + +- :func:`functools.reduce` + +- :func:`itertools.combinations` + +- :func:`itertools.combinations_with_replacement` + +- :func:`itertools.permutations` + +- :func:`itertools.product` + +- :func:`itertools.zip_longest` + +- :func:`zip` + +Previously, they could have become untracked by a prior garbage collection. +Patch by Brandt Bucher. diff --git a/Modules/_functoolsmodule.c b/Modules/_functoolsmodule.c index d158d3bae157b2..42764a181d26ba 100644 --- a/Modules/_functoolsmodule.c +++ b/Modules/_functoolsmodule.c @@ -1,4 +1,5 @@ #include "Python.h" +#include "pycore_object.h" // _PyObject_GC_TRACK #include "pycore_pystate.h" // _PyThreadState_GET() #include "pycore_tupleobject.h" #include "structmember.h" // PyMemberDef @@ -673,6 +674,11 @@ functools_reduce(PyObject *self, PyObject *args) if ((result = PyObject_Call(func, args, NULL)) == NULL) { goto Fail; } + // bpo-42536: The GC may have untracked this args tuple. Since we're + // recycling it, make sure it's tracked again: + if (!_PyObject_GC_IS_TRACKED(args)) { + _PyObject_GC_TRACK(args); + } } } diff --git a/Modules/itertoolsmodule.c b/Modules/itertoolsmodule.c index 18fcebdf25b465..95ef8d79a16533 100644 --- a/Modules/itertoolsmodule.c +++ b/Modules/itertoolsmodule.c @@ -2,6 +2,7 @@ #define PY_SSIZE_T_CLEAN #include "Python.h" #include "pycore_tupleobject.h" +#include "pycore_object.h" // _PyObject_GC_TRACK() #include // offsetof() /* Itertools module written and maintained @@ -2245,6 +2246,11 @@ product_next(productobject *lz) lz->result = result; Py_DECREF(old_result); } + // bpo-42536: The GC may have untracked this result tuple. Since we're + // recycling it, make sure it's tracked again: + else if (!_PyObject_GC_IS_TRACKED(result)) { + _PyObject_GC_TRACK(result); + } /* Now, we've got the only copy so we can update it in-place */ assert (npools==0 || Py_REFCNT(result) == 1); @@ -2568,6 +2574,11 @@ combinations_next(combinationsobject *co) co->result = result; Py_DECREF(old_result); } + // bpo-42536: The GC may have untracked this result tuple. Since we're + // recycling it, make sure it's tracked again: + else if (!_PyObject_GC_IS_TRACKED(result)) { + _PyObject_GC_TRACK(result); + } /* Now, we've got the only copy so we can update it in-place * CPython's empty tuple is a singleton and cached in * PyTuple's freelist. @@ -2902,6 +2913,11 @@ cwr_next(cwrobject *co) co->result = result; Py_DECREF(old_result); } + // bpo-42536: The GC may have untracked this result tuple. Since we're + // recycling it, make sure it's tracked again: + else if (!_PyObject_GC_IS_TRACKED(result)) { + _PyObject_GC_TRACK(result); + } /* Now, we've got the only copy so we can update it in-place CPython's empty tuple is a singleton and cached in PyTuple's freelist. */ assert(r == 0 || Py_REFCNT(result) == 1); @@ -3246,6 +3262,11 @@ permutations_next(permutationsobject *po) po->result = result; Py_DECREF(old_result); } + // bpo-42536: The GC may have untracked this result tuple. Since we're + // recycling it, make sure it's tracked again: + else if (!_PyObject_GC_IS_TRACKED(result)) { + _PyObject_GC_TRACK(result); + } /* Now, we've got the only copy so we can update it in-place */ assert(r == 0 || Py_REFCNT(result) == 1); @@ -4515,6 +4536,11 @@ zip_longest_next(ziplongestobject *lz) PyTuple_SET_ITEM(result, i, item); Py_DECREF(olditem); } + // bpo-42536: The GC may have untracked this result tuple. Since we're + // recycling it, make sure it's tracked again: + if (!_PyObject_GC_IS_TRACKED(result)) { + _PyObject_GC_TRACK(result); + } } else { result = PyTuple_New(tuplesize); if (result == NULL) diff --git a/Objects/dictobject.c b/Objects/dictobject.c index faee6bc901eeba..8a056530a45459 100644 --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -3861,6 +3861,11 @@ dictiter_iternextitem(dictiterobject *di) Py_INCREF(result); Py_DECREF(oldkey); Py_DECREF(oldvalue); + // bpo-42536: The GC may have untracked this result tuple. Since we're + // recycling it, make sure it's tracked again: + if (!_PyObject_GC_IS_TRACKED(result)) { + _PyObject_GC_TRACK(result); + } } else { result = PyTuple_New(2); @@ -3976,6 +3981,11 @@ dictreviter_iternext(dictiterobject *di) Py_INCREF(result); Py_DECREF(oldkey); Py_DECREF(oldvalue); + // bpo-42536: The GC may have untracked this result tuple. Since + // we're recycling it, make sure it's tracked again: + if (!_PyObject_GC_IS_TRACKED(result)) { + _PyObject_GC_TRACK(result); + } } else { result = PyTuple_New(2); diff --git a/Objects/enumobject.c b/Objects/enumobject.c index 4a83bb45aa6678..bdd0ea5f3971be 100644 --- a/Objects/enumobject.c +++ b/Objects/enumobject.c @@ -1,6 +1,7 @@ /* enumerate object */ #include "Python.h" +#include "pycore_object.h" // _PyObject_GC_TRACK() #include "clinic/enumobject.c.h" @@ -130,6 +131,11 @@ enum_next_long(enumobject *en, PyObject* next_item) PyTuple_SET_ITEM(result, 1, next_item); Py_DECREF(old_index); Py_DECREF(old_item); + // bpo-42536: The GC may have untracked this result tuple. Since we're + // recycling it, make sure it's tracked again: + if (!_PyObject_GC_IS_TRACKED(result)) { + _PyObject_GC_TRACK(result); + } return result; } result = PyTuple_New(2); @@ -175,6 +181,11 @@ enum_next(enumobject *en) PyTuple_SET_ITEM(result, 1, next_item); Py_DECREF(old_index); Py_DECREF(old_item); + // bpo-42536: The GC may have untracked this result tuple. Since we're + // recycling it, make sure it's tracked again: + if (!_PyObject_GC_IS_TRACKED(result)) { + _PyObject_GC_TRACK(result); + } return result; } result = PyTuple_New(2); diff --git a/Objects/odictobject.c b/Objects/odictobject.c index d5bf499575d097..b9f2169a72a8ac 100644 --- a/Objects/odictobject.c +++ b/Objects/odictobject.c @@ -1817,6 +1817,11 @@ odictiter_iternext(odictiterobject *di) Py_INCREF(result); Py_DECREF(PyTuple_GET_ITEM(result, 0)); /* borrowed */ Py_DECREF(PyTuple_GET_ITEM(result, 1)); /* borrowed */ + // bpo-42536: The GC may have untracked this result tuple. Since we're + // recycling it, make sure it's tracked again: + if (!_PyObject_GC_IS_TRACKED(result)) { + _PyObject_GC_TRACK(result); + } } else { result = PyTuple_New(2); diff --git a/Python/bltinmodule.c b/Python/bltinmodule.c index 199b09c4d8c41e..614012df9b12a2 100644 --- a/Python/bltinmodule.c +++ b/Python/bltinmodule.c @@ -2619,6 +2619,11 @@ zip_next(zipobject *lz) PyTuple_SET_ITEM(result, i, item); Py_DECREF(olditem); } + // bpo-42536: The GC may have untracked this result tuple. Since we're + // recycling it, make sure it's tracked again: + if (!_PyObject_GC_IS_TRACKED(result)) { + _PyObject_GC_TRACK(result); + } } else { result = PyTuple_New(tuplesize); if (result == NULL) From be52ca45d9eb9c3e8941e46ddc67a210f0f4c6fa Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 7 Dec 2020 15:51:16 -0800 Subject: [PATCH 0785/1314] bpo-41889: [Enum] fix multiple-inheritance regression (GH-22487) (GH-23673) (cherry picked from commit c266736ec1f9ebef38b134ceb4832df015711b38) --- Lib/enum.py | 11 +++++--- Lib/test/test_enum.py | 26 +++++++++++++++++++ .../2020-10-01-16-17-11.bpo-41889.qLkNh8.rst | 1 + 3 files changed, 35 insertions(+), 3 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2020-10-01-16-17-11.bpo-41889.qLkNh8.rst diff --git a/Lib/enum.py b/Lib/enum.py index ebadd9f662a138..3ce205d48fc2ab 100644 --- a/Lib/enum.py +++ b/Lib/enum.py @@ -145,8 +145,9 @@ def __new__(metacls, cls, bases, classdict): for key in ignore: classdict.pop(key, None) member_type, first_enum = metacls._get_mixins_(cls, bases) - __new__, save_new, use_args = metacls._find_new_(classdict, member_type, - first_enum) + __new__, save_new, use_args = metacls._find_new_( + classdict, member_type, first_enum, + ) # save enum items into separate mapping so they don't get baked into # the new class @@ -500,12 +501,16 @@ def _find_data_type(bases): for base in chain.__mro__: if base is object: continue + elif issubclass(base, Enum): + if base._member_type_ is not object: + data_types.append(base._member_type_) + break elif '__new__' in base.__dict__: if issubclass(base, Enum): continue data_types.append(candidate or base) break - elif not issubclass(base, Enum): + else: candidate = base if len(data_types) > 1: raise TypeError('%r: too many data types: %r' % (class_name, data_types)) diff --git a/Lib/test/test_enum.py b/Lib/test/test_enum.py index 0e6b1b16ca3238..cd73d26e63e229 100644 --- a/Lib/test/test_enum.py +++ b/Lib/test/test_enum.py @@ -1998,6 +1998,32 @@ class Decision2(MyEnum): REVERT_ALL = "REVERT_ALL" RETRY = "RETRY" + def test_multiple_mixin_inherited(self): + class MyInt(int): + def __new__(cls, value): + return super().__new__(cls, value) + + class HexMixin: + def __repr__(self): + return hex(self) + + class MyIntEnum(HexMixin, MyInt, enum.Enum): + pass + + class Foo(MyIntEnum): + TEST = 1 + self.assertTrue(isinstance(Foo.TEST, MyInt)) + self.assertEqual(repr(Foo.TEST), "0x1") + + class Fee(MyIntEnum): + TEST = 1 + def __new__(cls, value): + value += 1 + member = int.__new__(cls, value) + member._value_ = value + return member + self.assertEqual(Fee.TEST, 2) + def test_empty_globals(self): # bpo-35717: sys._getframe(2).f_globals['__name__'] fails with KeyError # when using compile and exec because f_globals is empty diff --git a/Misc/NEWS.d/next/Library/2020-10-01-16-17-11.bpo-41889.qLkNh8.rst b/Misc/NEWS.d/next/Library/2020-10-01-16-17-11.bpo-41889.qLkNh8.rst new file mode 100644 index 00000000000000..768865ae62116d --- /dev/null +++ b/Misc/NEWS.d/next/Library/2020-10-01-16-17-11.bpo-41889.qLkNh8.rst @@ -0,0 +1 @@ +Enum: fix regression involving inheriting a multiply-inherited enum From 170dec3598ec945c3f32ce053737f378c2ed1edc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Langa?= Date: Tue, 8 Dec 2020 03:09:53 +0100 Subject: [PATCH 0786/1314] Post 3.9.1 --- Include/patchlevel.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Include/patchlevel.h b/Include/patchlevel.h index 0b5d280bd4fd4b..253421378be4aa 100644 --- a/Include/patchlevel.h +++ b/Include/patchlevel.h @@ -23,7 +23,7 @@ #define PY_RELEASE_SERIAL 0 /* Version as a string */ -#define PY_VERSION "3.9.1" +#define PY_VERSION "3.9.1+" /*--end constants--*/ /* Version as a single 4-byte hex number, e.g. 0x010502B2 == 1.5.2b2. From f0e42ae03c41ec32fcb3064772f46ff7f2c5ff3b Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Tue, 8 Dec 2020 16:16:05 +0100 Subject: [PATCH 0787/1314] bpo-32381: Fix PyRun_SimpleFileExFlags() encoding (GH-23642) (GH-23692) Fix encoding name when running a ".pyc" file on Windows: PyRun_SimpleFileExFlags() now uses the correct encoding to decode the filename. * Add pyrun_file() subfunction. * Add pyrun_simple_file() subfunction. * PyRun_SimpleFileExFlags() now calls _Py_fopen_obj() rather than _Py_fopen(). (cherry picked from commit b6d98c10fff6f320f8fdf595c3f9a05d8be4e31d) --- .../2020-12-04-17-17-44.bpo-32381.NY5t2S.rst | 3 + Python/pythonrun.c | 224 +++++++++++------- 2 files changed, 135 insertions(+), 92 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2020-12-04-17-17-44.bpo-32381.NY5t2S.rst diff --git a/Misc/NEWS.d/next/Core and Builtins/2020-12-04-17-17-44.bpo-32381.NY5t2S.rst b/Misc/NEWS.d/next/Core and Builtins/2020-12-04-17-17-44.bpo-32381.NY5t2S.rst new file mode 100644 index 00000000000000..f4d84f9d848d4f --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2020-12-04-17-17-44.bpo-32381.NY5t2S.rst @@ -0,0 +1,3 @@ +Fix encoding name when running a ``.pyc`` file on Windows: +:c:func:`PyRun_SimpleFileExFlags()` now uses the correct encoding to decode +the filename. diff --git a/Python/pythonrun.c b/Python/pythonrun.c index 70748dc584f0bc..04540989f30433 100644 --- a/Python/pythonrun.c +++ b/Python/pythonrun.c @@ -64,11 +64,15 @@ extern Py_EXPORTED_SYMBOL grammar _PyParser_Grammar; /* From graminit.c */ static void flush_io(void); static PyObject *run_mod(mod_ty, PyObject *, PyObject *, PyObject *, PyCompilerFlags *, PyArena *); -static PyObject *run_pyc_file(FILE *, const char *, PyObject *, PyObject *, +static PyObject *run_pyc_file(FILE *, PyObject *, PyObject *, PyCompilerFlags *); static void err_input(perrdetail *); static void err_free(perrdetail *); static int PyRun_InteractiveOneObjectEx(FILE *, PyObject *, PyCompilerFlags *); +static PyObject* pyrun_file(FILE *fp, PyObject *filename, int start, + PyObject *globals, PyObject *locals, int closeit, + PyCompilerFlags *flags); + /* Parse input from a file and execute it */ int @@ -310,82 +314,89 @@ PyRun_InteractiveOneFlags(FILE *fp, const char *filename_str, PyCompilerFlags *f the file type, and, if we may close it, at the first few bytes. */ static int -maybe_pyc_file(FILE *fp, const char* filename, const char* ext, int closeit) +maybe_pyc_file(FILE *fp, PyObject *filename, int closeit) { - if (strcmp(ext, ".pyc") == 0) + PyObject *ext = PyUnicode_FromString(".pyc"); + if (ext == NULL) { + return -1; + } + Py_ssize_t endswith = PyUnicode_Tailmatch(filename, ext, 0, PY_SSIZE_T_MAX, +1); + Py_DECREF(ext); + if (endswith) { return 1; + } /* Only look into the file if we are allowed to close it, since it then should also be seekable. */ - if (closeit) { - /* Read only two bytes of the magic. If the file was opened in - text mode, the bytes 3 and 4 of the magic (\r\n) might not - be read as they are on disk. */ - unsigned int halfmagic = PyImport_GetMagicNumber() & 0xFFFF; - unsigned char buf[2]; - /* Mess: In case of -x, the stream is NOT at its start now, - and ungetc() was used to push back the first newline, - which makes the current stream position formally undefined, - and a x-platform nightmare. - Unfortunately, we have no direct way to know whether -x - was specified. So we use a terrible hack: if the current - stream position is not 0, we assume -x was specified, and - give up. Bug 132850 on SourceForge spells out the - hopelessness of trying anything else (fseek and ftell - don't work predictably x-platform for text-mode files). - */ - int ispyc = 0; - if (ftell(fp) == 0) { - if (fread(buf, 1, 2, fp) == 2 && - ((unsigned int)buf[1]<<8 | buf[0]) == halfmagic) - ispyc = 1; - rewind(fp); - } - return ispyc; + if (!closeit) { + return 0; } - return 0; + + /* Read only two bytes of the magic. If the file was opened in + text mode, the bytes 3 and 4 of the magic (\r\n) might not + be read as they are on disk. */ + unsigned int halfmagic = PyImport_GetMagicNumber() & 0xFFFF; + unsigned char buf[2]; + /* Mess: In case of -x, the stream is NOT at its start now, + and ungetc() was used to push back the first newline, + which makes the current stream position formally undefined, + and a x-platform nightmare. + Unfortunately, we have no direct way to know whether -x + was specified. So we use a terrible hack: if the current + stream position is not 0, we assume -x was specified, and + give up. Bug 132850 on SourceForge spells out the + hopelessness of trying anything else (fseek and ftell + don't work predictably x-platform for text-mode files). + */ + int ispyc = 0; + if (ftell(fp) == 0) { + if (fread(buf, 1, 2, fp) == 2 && + ((unsigned int)buf[1]<<8 | buf[0]) == halfmagic) + ispyc = 1; + rewind(fp); + } + return ispyc; } + static int -set_main_loader(PyObject *d, const char *filename, const char *loader_name) +set_main_loader(PyObject *d, PyObject *filename, const char *loader_name) { - PyObject *filename_obj, *bootstrap, *loader_type = NULL, *loader; - int result = 0; - - filename_obj = PyUnicode_DecodeFSDefault(filename); - if (filename_obj == NULL) - return -1; PyInterpreterState *interp = _PyInterpreterState_GET(); - bootstrap = PyObject_GetAttrString(interp->importlib, - "_bootstrap_external"); - if (bootstrap != NULL) { - loader_type = PyObject_GetAttrString(bootstrap, loader_name); - Py_DECREF(bootstrap); + PyObject *bootstrap = PyObject_GetAttrString(interp->importlib, + "_bootstrap_external"); + if (bootstrap == NULL) { + return -1; } + + PyObject *loader_type = PyObject_GetAttrString(bootstrap, loader_name); + Py_DECREF(bootstrap); if (loader_type == NULL) { - Py_DECREF(filename_obj); return -1; } - loader = PyObject_CallFunction(loader_type, "sN", "__main__", filename_obj); + + PyObject *loader = PyObject_CallFunction(loader_type, + "sO", "__main__", filename); Py_DECREF(loader_type); if (loader == NULL) { return -1; } + if (PyDict_SetItemString(d, "__loader__", loader) < 0) { - result = -1; + Py_DECREF(loader); + return -1; } Py_DECREF(loader); - return result; + return 0; } -int -PyRun_SimpleFileExFlags(FILE *fp, const char *filename, int closeit, - PyCompilerFlags *flags) + +static int +pyrun_simple_file(FILE *fp, PyObject *filename, int closeit, + PyCompilerFlags *flags) { PyObject *m, *d, *v; - const char *ext; int set_file_name = 0, ret = -1; - size_t len; m = PyImport_AddModule("__main__"); if (m == NULL) @@ -393,29 +404,29 @@ PyRun_SimpleFileExFlags(FILE *fp, const char *filename, int closeit, Py_INCREF(m); d = PyModule_GetDict(m); if (PyDict_GetItemString(d, "__file__") == NULL) { - PyObject *f; - f = PyUnicode_DecodeFSDefault(filename); - if (f == NULL) - goto done; - if (PyDict_SetItemString(d, "__file__", f) < 0) { - Py_DECREF(f); + if (PyDict_SetItemString(d, "__file__", filename) < 0) { goto done; } if (PyDict_SetItemString(d, "__cached__", Py_None) < 0) { - Py_DECREF(f); goto done; } set_file_name = 1; - Py_DECREF(f); } - len = strlen(filename); - ext = filename + len - (len > 4 ? 4 : 0); - if (maybe_pyc_file(fp, filename, ext, closeit)) { + + int pyc = maybe_pyc_file(fp, filename, closeit); + if (pyc < 0) { + goto done; + } + + if (pyc) { FILE *pyc_fp; /* Try to run a pyc file. First, re-open in binary */ - if (closeit) + if (closeit) { fclose(fp); - if ((pyc_fp = _Py_fopen(filename, "rb")) == NULL) { + } + + pyc_fp = _Py_fopen_obj(filename, "rb"); + if (pyc_fp == NULL) { fprintf(stderr, "python: Can't reopen .pyc file\n"); goto done; } @@ -426,17 +437,17 @@ PyRun_SimpleFileExFlags(FILE *fp, const char *filename, int closeit, fclose(pyc_fp); goto done; } - v = run_pyc_file(pyc_fp, filename, d, d, flags); + v = run_pyc_file(pyc_fp, d, d, flags); } else { /* When running from stdin, leave __main__.__loader__ alone */ - if (strcmp(filename, "") != 0 && + if (PyUnicode_CompareWithASCIIString(filename, "") != 0 && set_main_loader(d, filename, "SourceFileLoader") < 0) { fprintf(stderr, "python: failed to set __main__.__loader__\n"); ret = -1; goto done; } - v = PyRun_FileExFlags(fp, filename, Py_file_input, d, d, - closeit, flags); + v = pyrun_file(fp, filename, Py_file_input, d, d, + closeit, flags); } flush_io(); if (v == NULL) { @@ -459,6 +470,21 @@ PyRun_SimpleFileExFlags(FILE *fp, const char *filename, int closeit, return ret; } + +int +PyRun_SimpleFileExFlags(FILE *fp, const char *filename, int closeit, + PyCompilerFlags *flags) +{ + PyObject *filename_obj = PyUnicode_DecodeFSDefault(filename); + if (filename_obj == NULL) { + return -1; + } + int res = pyrun_simple_file(fp, filename_obj, closeit, flags); + Py_DECREF(filename_obj); + return res; +} + + int PyRun_SimpleStringFlags(const char *command, PyCompilerFlags *flags) { @@ -1081,24 +1107,18 @@ PyRun_StringFlags(const char *str, int start, PyObject *globals, return ret; } -PyObject * -PyRun_FileExFlags(FILE *fp, const char *filename_str, int start, PyObject *globals, - PyObject *locals, int closeit, PyCompilerFlags *flags) + +static PyObject * +pyrun_file(FILE *fp, PyObject *filename, int start, PyObject *globals, + PyObject *locals, int closeit, PyCompilerFlags *flags) { - PyObject *ret = NULL; + PyArena *arena = PyArena_New(); + if (arena == NULL) { + return NULL; + } + mod_ty mod; - PyArena *arena = NULL; - PyObject *filename; int use_peg = _PyInterpreterState_GET()->config._use_peg_parser; - - filename = PyUnicode_DecodeFSDefault(filename_str); - if (filename == NULL) - goto exit; - - arena = PyArena_New(); - if (arena == NULL) - goto exit; - if (use_peg) { mod = PyPegen_ASTFromFileObject(fp, filename, start, NULL, NULL, NULL, flags, NULL, arena); @@ -1108,20 +1128,40 @@ PyRun_FileExFlags(FILE *fp, const char *filename_str, int start, PyObject *globa flags, NULL, arena); } - if (closeit) + if (closeit) { fclose(fp); - if (mod == NULL) { - goto exit; } - ret = run_mod(mod, filename, globals, locals, flags, arena); -exit: - Py_XDECREF(filename); - if (arena != NULL) - PyArena_Free(arena); + PyObject *ret; + if (mod != NULL) { + ret = run_mod(mod, filename, globals, locals, flags, arena); + } + else { + ret = NULL; + } + PyArena_Free(arena); + return ret; } + +PyObject * +PyRun_FileExFlags(FILE *fp, const char *filename, int start, PyObject *globals, + PyObject *locals, int closeit, PyCompilerFlags *flags) +{ + PyObject *filename_obj = PyUnicode_DecodeFSDefault(filename); + if (filename_obj == NULL) { + return NULL; + } + + PyObject *res = pyrun_file(fp, filename_obj, start, globals, + locals, closeit, flags); + Py_DECREF(filename_obj); + return res; + +} + + static void flush_io(void) { @@ -1202,8 +1242,8 @@ run_mod(mod_ty mod, PyObject *filename, PyObject *globals, PyObject *locals, } static PyObject * -run_pyc_file(FILE *fp, const char *filename, PyObject *globals, - PyObject *locals, PyCompilerFlags *flags) +run_pyc_file(FILE *fp, PyObject *globals, PyObject *locals, + PyCompilerFlags *flags) { PyThreadState *tstate = _PyThreadState_GET(); PyCodeObject *co; From a3a4bf3b8dc79e4ec4f24f59bd1e9e2a75229112 Mon Sep 17 00:00:00 2001 From: Terry Jan Reedy Date: Tue, 8 Dec 2020 13:00:13 -0500 Subject: [PATCH 0788/1314] [3.9] bpo-41910: move news entry (GH-23697) --- Misc/NEWS.d/3.9.1rc1.rst | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/Misc/NEWS.d/3.9.1rc1.rst b/Misc/NEWS.d/3.9.1rc1.rst index 0524f85e7a73bd..ac4bf36f5c2173 100644 --- a/Misc/NEWS.d/3.9.1rc1.rst +++ b/Misc/NEWS.d/3.9.1rc1.rst @@ -149,15 +149,6 @@ failure, run the parser a second time with those enabled. .. -.. bpo: 41910 -.. date: 2020-10-21-14-40-54 -.. nonce: CzBMit -.. section: Core and Builtins - -Document the default implementation of `object.__eq__`. - -.. - .. bpo: 42057 .. date: 2020-10-20-11-36-14 .. nonce: BI-OoV @@ -561,6 +552,15 @@ Document __format__ functionality for IP addresses. .. +.. bpo: 41910 +.. date: 2020-10-21-14-40-54 +.. nonce: CzBMit +.. section: Documentation + +Document the default implementation of `object.__eq__`. + +.. + .. bpo: 42010 .. date: 2020-10-21-02-21-14 .. nonce: 76vJ0u From 14eaa7d75282d8458455c41e9e871c56db8b9a10 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 8 Dec 2020 11:52:24 -0800 Subject: [PATCH 0789/1314] bpo-41907: [Enum] fix format() behavior for IntFlag (GH-22497) (GH-23703) (cherry picked from commit 37440eef7f9a0c27e13fc9ce0850574bb00688b0) --- Lib/enum.py | 2 +- Lib/test/test_enum.py | 14 ++++++++++++++ .../2020-10-02-10-19-49.bpo-41907.wiIEsz.rst | 1 + 3 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Library/2020-10-02-10-19-49.bpo-41907.wiIEsz.rst diff --git a/Lib/enum.py b/Lib/enum.py index 3ce205d48fc2ab..c277309881eb0f 100644 --- a/Lib/enum.py +++ b/Lib/enum.py @@ -657,7 +657,7 @@ def __format__(self, format_spec): # the value # pure Enum branch, or branch with __str__ explicitly overridden - str_overridden = type(self).__str__ != Enum.__str__ + str_overridden = type(self).__str__ not in (Enum.__str__, Flag.__str__) if self._member_type_ is object or str_overridden: cls = str val = str(self) diff --git a/Lib/test/test_enum.py b/Lib/test/test_enum.py index cd73d26e63e229..ccc2cbe1ec14b5 100644 --- a/Lib/test/test_enum.py +++ b/Lib/test/test_enum.py @@ -570,12 +570,15 @@ def hello(self): class Test1Enum(MyMethodEnum, int, MyStrEnum): One = 1 Two = 2 + self.assertTrue(Test1Enum._member_type_ is int) self.assertEqual(str(Test1Enum.One), 'MyStr') + self.assertEqual(format(Test1Enum.One, ''), 'MyStr') # class Test2Enum(MyStrEnum, MyMethodEnum): One = 1 Two = 2 self.assertEqual(str(Test2Enum.One), 'MyStr') + self.assertEqual(format(Test1Enum.One, ''), 'MyStr') def test_inherited_data_type(self): class HexInt(int): @@ -2170,6 +2173,11 @@ def test_repr(self): self.assertEqual(repr(~(Open.RO | Open.CE)), '') self.assertEqual(repr(~(Open.WO | Open.CE)), '') + def test_format(self): + Perm = self.Perm + self.assertEqual(format(Perm.R, ''), 'Perm.R') + self.assertEqual(format(Perm.R | Perm.X, ''), 'Perm.R|X') + def test_or(self): Perm = self.Perm for i in Perm: @@ -2503,6 +2511,7 @@ class Color(IntFlag): def test_type(self): Perm = self.Perm + self.assertTrue(Perm._member_type_ is int) Open = self.Open for f in Perm: self.assertTrue(isinstance(f, Perm)) @@ -2582,6 +2591,11 @@ def test_repr(self): self.assertEqual(repr(~(Open.WO | Open.CE)), '') self.assertEqual(repr(Open(~4)), '') + def test_format(self): + Perm = self.Perm + self.assertEqual(format(Perm.R, ''), '4') + self.assertEqual(format(Perm.R | Perm.X, ''), '5') + def test_or(self): Perm = self.Perm for i in Perm: diff --git a/Misc/NEWS.d/next/Library/2020-10-02-10-19-49.bpo-41907.wiIEsz.rst b/Misc/NEWS.d/next/Library/2020-10-02-10-19-49.bpo-41907.wiIEsz.rst new file mode 100644 index 00000000000000..aa337b38046e61 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2020-10-02-10-19-49.bpo-41907.wiIEsz.rst @@ -0,0 +1 @@ +fix `format()` behavior for `IntFlag` From 4b37228823fecb73fe70dc009e696a7805b0833f Mon Sep 17 00:00:00 2001 From: Ethan Furman Date: Tue, 8 Dec 2020 14:29:02 -0800 Subject: [PATCH 0790/1314] [3.9] [Enum] reformat and add doc strings (GH-23705). (GH-23707) * [3.9] [Enum] reformat and add doc strings (GH-23705). --- Lib/enum.py | 178 +++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 127 insertions(+), 51 deletions(-) diff --git a/Lib/enum.py b/Lib/enum.py index c277309881eb0f..b14da088f33bf3 100644 --- a/Lib/enum.py +++ b/Lib/enum.py @@ -10,31 +10,41 @@ def _is_descriptor(obj): - """Returns True if obj is a descriptor, False otherwise.""" + """ + Returns True if obj is a descriptor, False otherwise. + """ return ( hasattr(obj, '__get__') or hasattr(obj, '__set__') or - hasattr(obj, '__delete__')) - + hasattr(obj, '__delete__') + ) def _is_dunder(name): - """Returns True if a __dunder__ name, False otherwise.""" - return (len(name) > 4 and + """ + Returns True if a __dunder__ name, False otherwise. + """ + return ( + len(name) > 4 and name[:2] == name[-2:] == '__' and name[2] != '_' and - name[-3] != '_') - + name[-3] != '_' + ) def _is_sunder(name): - """Returns True if a _sunder_ name, False otherwise.""" - return (len(name) > 2 and + """ + Returns True if a _sunder_ name, False otherwise. + """ + return ( + len(name) > 2 and name[0] == name[-1] == '_' and name[1:2] != '_' and - name[-2:-1] != '_') - + name[-2:-1] != '_' + ) def _make_class_unpicklable(cls): - """Make the given class un-picklable.""" + """ + Make the given class un-picklable. + """ def _break_on_call_reduce(self, proto): raise TypeError('%r cannot be pickled' % self) cls.__reduce_ex__ = _break_on_call_reduce @@ -49,11 +59,11 @@ class auto: class _EnumDict(dict): - """Track enum member order and ensure member names are not reused. + """ + Track enum member order and ensure member names are not reused. EnumMeta will use the names found in self._member_names as the enumeration member names. - """ def __init__(self): super().__init__() @@ -63,13 +73,13 @@ def __init__(self): self._auto_called = False def __setitem__(self, key, value): - """Changes anything not dundered or not a descriptor. + """ + Changes anything not dundered or not a descriptor. If an enum member name is used twice, an error is raised; duplicate values are not checked for. Single underscore (sunder) names are reserved. - """ if _is_sunder(key): if key not in ( @@ -90,7 +100,10 @@ def __setitem__(self, key, value): self._ignore = value already = set(value) & set(self._member_names) if already: - raise ValueError('_ignore_ cannot specify already set names: %r' % (already, )) + raise ValueError( + '_ignore_ cannot specify already set names: %r' + % (already, ) + ) elif _is_dunder(key): if key == '__order__': key = '_order_' @@ -105,7 +118,12 @@ def __setitem__(self, key, value): raise TypeError('%r already defined as: %r' % (key, self[key])) if isinstance(value, auto): if value.value == _auto_null: - value.value = self._generate_next_value(key, 1, len(self._member_names), self._last_values[:]) + value.value = self._generate_next_value( + key, + 1, + len(self._member_names), + self._last_values[:], + ) self._auto_called = True value = value.value self._member_names.append(key) @@ -118,9 +136,10 @@ def __setitem__(self, key, value): # This is also why there are checks in EnumMeta like `if Enum is not None` Enum = None - class EnumMeta(type): - """Metaclass for Enum""" + """ + Metaclass for Enum + """ @classmethod def __prepare__(metacls, cls, bases): # check that previous enum members do not exist @@ -130,7 +149,9 @@ def __prepare__(metacls, cls, bases): # inherit previous flags and _generate_next_value_ function member_type, first_enum = metacls._get_mixins_(cls, bases) if first_enum is not None: - enum_dict['_generate_next_value_'] = getattr(first_enum, '_generate_next_value_', None) + enum_dict['_generate_next_value_'] = getattr( + first_enum, '_generate_next_value_', None, + ) return enum_dict def __new__(metacls, cls, bases, classdict): @@ -176,9 +197,11 @@ def __new__(metacls, cls, bases, classdict): # save DynamicClassAttribute attributes from super classes so we know # if we can take the shortcut of storing members in the class dict - dynamic_attributes = {k for c in enum_class.mro() - for k, v in c.__dict__.items() - if isinstance(v, DynamicClassAttribute)} + dynamic_attributes = { + k for c in enum_class.mro() + for k, v in c.__dict__.items() + if isinstance(v, DynamicClassAttribute) + } # Reverse value->name map for hashable values. enum_class._value2member_map_ = {} @@ -288,7 +311,8 @@ def __bool__(self): return True def __call__(cls, value, names=None, *, module=None, qualname=None, type=None, start=1): - """Either returns an existing member, or creates a new enum class. + """ + Either returns an existing member, or creates a new enum class. This method is used both when an enum class is given a value to match to an enumeration member (i.e. Color(3)) and for the functional API @@ -310,12 +334,18 @@ def __call__(cls, value, names=None, *, module=None, qualname=None, type=None, s not correct, unpickling will fail in some circumstances. `type`, if set, will be mixed in as the first base class. - """ if names is None: # simple value lookup return cls.__new__(cls, value) # otherwise, functional API: we're creating a new Enum type - return cls._create_(value, names, module=module, qualname=qualname, type=type, start=start) + return cls._create_( + value, + names, + module=module, + qualname=qualname, + type=type, + start=start, + ) def __contains__(cls, member): if not isinstance(member, Enum): @@ -328,22 +358,23 @@ def __delattr__(cls, attr): # nicer error message when someone tries to delete an attribute # (see issue19025). if attr in cls._member_map_: - raise AttributeError( - "%s: cannot delete Enum member." % cls.__name__) + raise AttributeError("%s: cannot delete Enum member." % cls.__name__) super().__delattr__(attr) def __dir__(self): - return (['__class__', '__doc__', '__members__', '__module__'] + - self._member_names_) + return ( + ['__class__', '__doc__', '__members__', '__module__'] + + self._member_names_ + ) def __getattr__(cls, name): - """Return the enum member matching `name` + """ + Return the enum member matching `name` We use __getattr__ instead of descriptors or inserting into the enum class' __dict__ in order to support `name` and `value` being both properties for enum members (which live in the class' __dict__) and enum members themselves. - """ if _is_dunder(name): raise AttributeError(name) @@ -356,6 +387,9 @@ def __getitem__(cls, name): return cls._member_map_[name] def __iter__(cls): + """ + Returns members in definition order. + """ return (cls._member_map_[name] for name in cls._member_names_) def __len__(cls): @@ -363,11 +397,11 @@ def __len__(cls): @property def __members__(cls): - """Returns a mapping of member name->value. + """ + Returns a mapping of member name->value. This mapping lists all enum members, including aliases. Note that this is a read-only view of the internal mapping. - """ return MappingProxyType(cls._member_map_) @@ -375,15 +409,18 @@ def __repr__(cls): return "" % cls.__name__ def __reversed__(cls): + """ + Returns members in reverse definition order. + """ return (cls._member_map_[name] for name in reversed(cls._member_names_)) def __setattr__(cls, name, value): - """Block attempts to reassign Enum members. + """ + Block attempts to reassign Enum members. A simple assignment to the class namespace only changes one of the several possible ways to get an Enum member from the Enum class, resulting in an inconsistent Enumeration. - """ member_map = cls.__dict__.get('_member_map_', {}) if name in member_map: @@ -391,7 +428,8 @@ def __setattr__(cls, name, value): super().__setattr__(name, value) def _create_(cls, class_name, names, *, module=None, qualname=None, type=None, start=1): - """Convenience method to create a new Enum class. + """ + Convenience method to create a new Enum class. `names` can be: @@ -400,7 +438,6 @@ def _create_(cls, class_name, names, *, module=None, qualname=None, type=None, s * An iterable of member names. Values are incremented by 1 from `start`. * An iterable of (member name, value) pairs. * A mapping of member name -> value pairs. - """ metacls = cls.__class__ bases = (cls, ) if type is None else (type, cls) @@ -481,15 +518,18 @@ def _check_for_existing_members(class_name, bases): for chain in bases: for base in chain.__mro__: if issubclass(base, Enum) and base._member_names_: - raise TypeError("%s: cannot extend enumeration %r" % (class_name, base.__name__)) + raise TypeError( + "%s: cannot extend enumeration %r" + % (class_name, base.__name__) + ) @staticmethod def _get_mixins_(class_name, bases): - """Returns the type for creating enum members, and the first inherited + """ + Returns the type for creating enum members, and the first inherited enum class. bases: the tuple of bases that was given to __new__ - """ if not bases: return object, Enum @@ -532,12 +572,12 @@ def _find_data_type(bases): @staticmethod def _find_new_(classdict, member_type, first_enum): - """Returns the __new__ to be used for creating the enum members. + """ + Returns the __new__ to be used for creating the enum members. classdict: the class dictionary given to __new__ member_type: the data type whose __new__ will be used by default first_enum: enumeration to check for an overriding __new__ - """ # now find the correct __new__, checking to see of one was defined # by the user; also check earlier enum classes in case a __new__ was @@ -577,10 +617,10 @@ def _find_new_(classdict, member_type, first_enum): class Enum(metaclass=EnumMeta): - """Generic enumeration. + """ + Generic enumeration. Derive from this class to define new enumerations. - """ def __new__(cls, value): # all enum instances are actually created during class construction @@ -623,6 +663,14 @@ def __new__(cls, value): raise exc def _generate_next_value_(name, start, count, last_values): + """ + Generate the next value when not given. + + name: the name of the member + start: the initial start value or None + count: the number of existing members + last_value: the last value assigned or None + """ for last_value in reversed(last_values): try: return last_value + 1 @@ -643,6 +691,9 @@ def __str__(self): return "%s.%s" % (self.__class__.__name__, self._name_) def __dir__(self): + """ + Returns all members and all public methods + """ added_behavior = [ m for cls in self.__class__.mro() @@ -652,6 +703,9 @@ def __dir__(self): return (['__class__', '__doc__', '__module__'] + added_behavior) def __format__(self, format_spec): + """ + Returns format using actual value type unless __str__ has been overridden. + """ # mixed-in Enums should use the mixed-in type's __format__, otherwise # we can get strange results with the Enum name showing up instead of # the value @@ -699,7 +753,9 @@ def _reduce_ex_by_name(self, proto): return self.name class Flag(Enum): - """Support for flags""" + """ + Support for flags + """ def _generate_next_value_(name, start, count, last_values): """ @@ -722,6 +778,9 @@ def _generate_next_value_(name, start, count, last_values): @classmethod def _missing_(cls, value): + """ + Returns member (possibly creating it) if one can be found for value. + """ original_value = value if value < 0: value = ~value @@ -751,6 +810,9 @@ def _create_pseudo_member_(cls, value): return pseudo_member def __contains__(self, other): + """ + Returns True if self has at least the same flags set as other. + """ if not isinstance(other, self.__class__): raise TypeError( "unsupported operand type(s) for 'in': '%s' and '%s'" % ( @@ -809,10 +871,15 @@ def __invert__(self): class IntFlag(int, Flag): - """Support for integer-based Flags""" + """ + Support for integer-based Flags + """ @classmethod def _missing_(cls, value): + """ + Returns member (possibly creating it) if one can be found for value. + """ if not isinstance(value, int): raise ValueError("%r is not a valid %s" % (value, cls.__qualname__)) new_member = cls._create_pseudo_member_(value) @@ -820,6 +887,9 @@ def _missing_(cls, value): @classmethod def _create_pseudo_member_(cls, value): + """ + Create a composite member iff value contains only members. + """ pseudo_member = cls._value2member_map_.get(value, None) if pseudo_member is None: need_to_create = [value] @@ -874,11 +944,15 @@ def __invert__(self): def _high_bit(value): - """returns index of highest bit, or -1 if value is zero or negative""" + """ + returns index of highest bit, or -1 if value is zero or negative + """ return value.bit_length() - 1 def unique(enumeration): - """Class decorator for enumerations ensuring unique member values.""" + """ + Class decorator for enumerations ensuring unique member values. + """ duplicates = [] for name, member in enumeration.__members__.items(): if name != member.name: @@ -891,7 +965,9 @@ def unique(enumeration): return enumeration def _decompose(flag, value): - """Extract all members from the value.""" + """ + Extract all members from the value. + """ # _decompose is only called if the value is not named not_covered = value negative = value < 0 From c1a3f9a9cbf5cf96ced5a2b16572cba7be964377 Mon Sep 17 00:00:00 2001 From: Andre Delfino Date: Thu, 10 Dec 2020 11:20:04 -0300 Subject: [PATCH 0791/1314] [3.9] [doc] Link to issue regarding logging.disable level param default value GH-23732 (cherry picked from commit 2a35137328154aa2513649dcf0bbef02c998e27c) Co-authored-by: Andre Delfino --- Doc/library/logging.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/library/logging.rst b/Doc/library/logging.rst index 7267f812cc1925..e63475d3b5a024 100644 --- a/Doc/library/logging.rst +++ b/Doc/library/logging.rst @@ -1089,8 +1089,8 @@ functions. suitable value. .. versionchanged:: 3.7 - The *level* parameter was defaulted to level ``CRITICAL``. See Issue - #28524 for more information about this change. + The *level* parameter was defaulted to level ``CRITICAL``. See + :issue:`28524` for more information about this change. .. function:: addLevelName(level, levelName) From be9e4402db64564f7bf0fedb3769cead46c0d4c4 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 12 Dec 2020 20:24:31 -0800 Subject: [PATCH 0792/1314] [3.9] bpo-41879: Doc: Fix description of async for statement (GH-23548) (GH-23749) Fix the wording in the documentation of `async for` to correctly describe asynchronous iterables. This fix is relevant for version 3.7 onward. (cherry picked from commit 4b8cdfcb22fbeaab9d954cb693a7fb3362a382b6) Co-authored-by: Nick Gaya --- Doc/reference/compound_stmts.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Doc/reference/compound_stmts.rst b/Doc/reference/compound_stmts.rst index b4e06e5b10d5af..2cae2f86d34f71 100644 --- a/Doc/reference/compound_stmts.rst +++ b/Doc/reference/compound_stmts.rst @@ -799,12 +799,12 @@ The :keyword:`!async for` statement .. productionlist:: python-grammar async_for_stmt: "async" `for_stmt` -An :term:`asynchronous iterable` is able to call asynchronous code in its -*iter* implementation, and :term:`asynchronous iterator` can call asynchronous -code in its *next* method. +An :term:`asynchronous iterable` provides an ``__aiter__`` method that directly +returns an :term:`asynchronous iterator`, which can call asynchronous code in +its ``__anext__`` method. The ``async for`` statement allows convenient iteration over asynchronous -iterators. +iterables. The following code:: From 3dcdbdeb4833e45430ccc9cb3432f779a6fd8c94 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 13 Dec 2020 14:01:00 -0800 Subject: [PATCH 0793/1314] bpo-42598: Fix implicit function declarations in configure (GH-23690) (GH-23756) This is invalid in C99 and later and is an error with some compilers (e.g. clang in Xcode 12), and can thus cause configure checks to produce incorrect results. (cherry picked from commit 674fa0a740151e0416c9383f127b16014e805990) Co-authored-by: Joshua Root --- .../Build/2020-12-13-14-43-10.bpo-42598.7ipr5H.rst | 2 ++ configure | 13 +++++++------ configure.ac | 13 +++++++------ 3 files changed, 16 insertions(+), 12 deletions(-) create mode 100644 Misc/NEWS.d/next/Build/2020-12-13-14-43-10.bpo-42598.7ipr5H.rst diff --git a/Misc/NEWS.d/next/Build/2020-12-13-14-43-10.bpo-42598.7ipr5H.rst b/Misc/NEWS.d/next/Build/2020-12-13-14-43-10.bpo-42598.7ipr5H.rst new file mode 100644 index 00000000000000..7dafc105c45ea9 --- /dev/null +++ b/Misc/NEWS.d/next/Build/2020-12-13-14-43-10.bpo-42598.7ipr5H.rst @@ -0,0 +1,2 @@ +Fix implicit function declarations in configure which could have resulted in +incorrect configuration checks. Patch contributed by Joshua Root. diff --git a/configure b/configure index 2d379feb4b7bf0..ed969c55b35ab6 100755 --- a/configure +++ b/configure @@ -11072,10 +11072,10 @@ else main() { pthread_attr_t attr; pthread_t id; - if (pthread_attr_init(&attr)) exit(-1); - if (pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM)) exit(-1); - if (pthread_create(&id, &attr, foo, NULL)) exit(-1); - exit(0); + if (pthread_attr_init(&attr)) return (-1); + if (pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM)) return (-1); + if (pthread_create(&id, &attr, foo, NULL)) return (-1); + return (0); } _ACEOF if ac_fn_c_try_run "$LINENO"; then : @@ -15083,7 +15083,7 @@ else int main() { /* Success: exit code 0 */ - exit((((wchar_t) -1) < ((wchar_t) 0)) ? 0 : 1); + return ((((wchar_t) -1) < ((wchar_t) 0)) ? 0 : 1); } _ACEOF @@ -15464,7 +15464,7 @@ else int main() { - exit(((-1)>>3 == -1) ? 0 : 1); + return (((-1)>>3 == -1) ? 0 : 1); } _ACEOF @@ -15934,6 +15934,7 @@ else /* end confdefs.h. */ #include +#include int main() { diff --git a/configure.ac b/configure.ac index c968d149c22d44..c74e348e077fb7 100644 --- a/configure.ac +++ b/configure.ac @@ -3313,10 +3313,10 @@ if test "$posix_threads" = "yes"; then main() { pthread_attr_t attr; pthread_t id; - if (pthread_attr_init(&attr)) exit(-1); - if (pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM)) exit(-1); - if (pthread_create(&id, &attr, foo, NULL)) exit(-1); - exit(0); + if (pthread_attr_init(&attr)) return (-1); + if (pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM)) return (-1); + if (pthread_create(&id, &attr, foo, NULL)) return (-1); + return (0); }]])], [ac_cv_pthread_system_supported=yes], [ac_cv_pthread_system_supported=no], @@ -4725,7 +4725,7 @@ then int main() { /* Success: exit code 0 */ - exit((((wchar_t) -1) < ((wchar_t) 0)) ? 0 : 1); + return ((((wchar_t) -1) < ((wchar_t) 0)) ? 0 : 1); } ]])], [ac_cv_wchar_t_signed=yes], @@ -4847,7 +4847,7 @@ AC_CACHE_VAL(ac_cv_rshift_extends_sign, [ AC_RUN_IFELSE([AC_LANG_SOURCE([[ int main() { - exit(((-1)>>3 == -1) ? 0 : 1); + return (((-1)>>3 == -1) ? 0 : 1); } ]])], [ac_cv_rshift_extends_sign=yes], @@ -4994,6 +4994,7 @@ AC_MSG_CHECKING(for broken poll()) AC_CACHE_VAL(ac_cv_broken_poll, AC_RUN_IFELSE([AC_LANG_SOURCE([[ #include +#include int main() { From 14f2a124e20081b8981c8d6165dbd78d11b6808c Mon Sep 17 00:00:00 2001 From: Karthikeyan Singaravelan Date: Mon, 14 Dec 2020 11:19:16 +0530 Subject: [PATCH 0794/1314] [3.9] bpo-42532: Check if NonCallableMock's spec_arg is not None instead of call its __bool__ function (GH-23613) (GH-23676) Check if NonCallableMock's spec_arg is not None instead of call its __bool__ function (cherry picked from commit c598a04dd29b89ad072245ddaf738badcfb41ac7) Co-authored-by: idanw206 <31290383+idanw206@users.noreply.github.com> --- Lib/unittest/mock.py | 2 +- Lib/unittest/test/testmock/testmock.py | 10 ++++++++++ .../Library/2020-12-02-07-37-59.bpo-42532.ObNep_.rst | 1 + 3 files changed, 12 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Library/2020-12-02-07-37-59.bpo-42532.ObNep_.rst diff --git a/Lib/unittest/mock.py b/Lib/unittest/mock.py index b495a5f6ccc017..f03c88baca671b 100644 --- a/Lib/unittest/mock.py +++ b/Lib/unittest/mock.py @@ -406,7 +406,7 @@ def __new__(cls, /, *args, **kw): # Check if spec is an async object or function bound_args = _MOCK_SIG.bind_partial(cls, *args, **kw).arguments spec_arg = bound_args.get('spec_set', bound_args.get('spec')) - if spec_arg and _is_async_obj(spec_arg): + if spec_arg is not None and _is_async_obj(spec_arg): bases = (AsyncMockMixin, cls) new = type(cls.__name__, bases, {'__doc__': cls.__doc__}) instance = _safe_super(NonCallableMock, cls).__new__(new) diff --git a/Lib/unittest/test/testmock/testmock.py b/Lib/unittest/test/testmock/testmock.py index ce674e713e99cd..f9307245307b9b 100644 --- a/Lib/unittest/test/testmock/testmock.py +++ b/Lib/unittest/test/testmock/testmock.py @@ -2156,6 +2156,16 @@ def trace(frame, event, arg): # pragma: no cover obj = mock(spec=Something) self.assertIsInstance(obj, Something) + def test_bool_not_called_when_passing_spec_arg(self): + class Something: + def __init__(self): + self.obj_with_bool_func = unittest.mock.MagicMock() + + obj = Something() + with unittest.mock.patch.object(obj, 'obj_with_bool_func', autospec=True): pass + + self.assertEqual(obj.obj_with_bool_func.__bool__.call_count, 0) + if __name__ == '__main__': unittest.main() diff --git a/Misc/NEWS.d/next/Library/2020-12-02-07-37-59.bpo-42532.ObNep_.rst b/Misc/NEWS.d/next/Library/2020-12-02-07-37-59.bpo-42532.ObNep_.rst new file mode 100644 index 00000000000000..7465cb8e2e3d7b --- /dev/null +++ b/Misc/NEWS.d/next/Library/2020-12-02-07-37-59.bpo-42532.ObNep_.rst @@ -0,0 +1 @@ +Remove unexpected call of ``__bool__`` when passing a ``spec_arg`` argument to a Mock. From 33b3fedd43e10e5a227ec8b7d251496e7cad4717 Mon Sep 17 00:00:00 2001 From: kj <28750310+Fidget-Spinner@users.noreply.github.com> Date: Tue, 15 Dec 2020 00:30:45 +0800 Subject: [PATCH 0795/1314] [3.9] bpo-42195: Ensure consistency of Callable's __args__ in collections.abc and typing (GH-23765) Backport of GH-23060. --- Lib/_collections_abc.py | 76 ++++++++++++++++++- Lib/collections/abc.py | 1 + Lib/test/test_genericalias.py | 58 +++++++++++++- Lib/test/test_typing.py | 8 -- Lib/typing.py | 31 +++++--- .../2020-11-20-00-57-47.bpo-42195.HeqcpS.rst | 11 +++ Objects/genericaliasobject.c | 60 ++++++++++----- 7 files changed, 202 insertions(+), 43 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2020-11-20-00-57-47.bpo-42195.HeqcpS.rst diff --git a/Lib/_collections_abc.py b/Lib/_collections_abc.py index 36cd9930003475..cec19ec47349be 100644 --- a/Lib/_collections_abc.py +++ b/Lib/_collections_abc.py @@ -10,6 +10,10 @@ import sys GenericAlias = type(list[int]) +EllipsisType = type(...) +def _f(): pass +FunctionType = type(_f) +del _f __all__ = ["Awaitable", "Coroutine", "AsyncIterable", "AsyncIterator", "AsyncGenerator", @@ -409,6 +413,76 @@ def __subclasshook__(cls, C): return NotImplemented +class _CallableGenericAlias(GenericAlias): + """ Represent `Callable[argtypes, resulttype]`. + + This sets ``__args__`` to a tuple containing the flattened``argtypes`` + followed by ``resulttype``. + + Example: ``Callable[[int, str], float]`` sets ``__args__`` to + ``(int, str, float)``. + """ + + __slots__ = () + + def __new__(cls, origin, args): + try: + return cls.__create_ga(origin, args) + except TypeError as exc: + import warnings + warnings.warn(f'{str(exc)} ' + f'(This will raise a TypeError in Python 3.10.)', + DeprecationWarning) + return GenericAlias(origin, args) + + @classmethod + def __create_ga(cls, origin, args): + if not isinstance(args, tuple) or len(args) != 2: + raise TypeError( + "Callable must be used as Callable[[arg, ...], result].") + t_args, t_result = args + if isinstance(t_args, list): + ga_args = tuple(t_args) + (t_result,) + # This relaxes what t_args can be on purpose to allow things like + # PEP 612 ParamSpec. Responsibility for whether a user is using + # Callable[...] properly is deferred to static type checkers. + else: + ga_args = args + return super().__new__(cls, origin, ga_args) + + def __repr__(self): + if len(self.__args__) == 2 and self.__args__[0] is Ellipsis: + return super().__repr__() + return (f'collections.abc.Callable' + f'[[{", ".join([_type_repr(a) for a in self.__args__[:-1]])}], ' + f'{_type_repr(self.__args__[-1])}]') + + def __reduce__(self): + args = self.__args__ + if not (len(args) == 2 and args[0] is Ellipsis): + args = list(args[:-1]), args[-1] + return _CallableGenericAlias, (Callable, args) + + +def _type_repr(obj): + """Return the repr() of an object, special-casing types (internal helper). + + Copied from :mod:`typing` since collections.abc + shouldn't depend on that module. + """ + if isinstance(obj, GenericAlias): + return repr(obj) + if isinstance(obj, type): + if obj.__module__ == 'builtins': + return obj.__qualname__ + return f'{obj.__module__}.{obj.__qualname__}' + if obj is Ellipsis: + return '...' + if isinstance(obj, FunctionType): + return obj.__name__ + return repr(obj) + + class Callable(metaclass=ABCMeta): __slots__ = () @@ -423,7 +497,7 @@ def __subclasshook__(cls, C): return _check_methods(C, "__call__") return NotImplemented - __class_getitem__ = classmethod(GenericAlias) + __class_getitem__ = classmethod(_CallableGenericAlias) ### SETS ### diff --git a/Lib/collections/abc.py b/Lib/collections/abc.py index 891600d16bee9e..86ca8b8a8414b3 100644 --- a/Lib/collections/abc.py +++ b/Lib/collections/abc.py @@ -1,2 +1,3 @@ from _collections_abc import * from _collections_abc import __all__ +from _collections_abc import _CallableGenericAlias diff --git a/Lib/test/test_genericalias.py b/Lib/test/test_genericalias.py index c113e538248e9c..5de13fe6d2f68c 100644 --- a/Lib/test/test_genericalias.py +++ b/Lib/test/test_genericalias.py @@ -62,7 +62,6 @@ class BaseTest(unittest.TestCase): Iterable, Iterator, Reversible, Container, Collection, - Callable, Mailbox, _PartialFile, ContextVar, Token, Field, @@ -307,6 +306,63 @@ def test_no_kwargs(self): with self.assertRaises(TypeError): GenericAlias(bad=float) + def test_subclassing_types_genericalias(self): + class SubClass(GenericAlias): ... + alias = SubClass(list, int) + class Bad(GenericAlias): + def __new__(cls, *args, **kwargs): + super().__new__(cls, *args, **kwargs) + + self.assertEqual(alias, list[int]) + with self.assertRaises(TypeError): + Bad(list, int, bad=int) + + def test_abc_callable(self): + # A separate test is needed for Callable since it uses a subclass of + # GenericAlias. + alias = Callable[[int, str], float] + with self.subTest("Testing subscription"): + self.assertIs(alias.__origin__, Callable) + self.assertEqual(alias.__args__, (int, str, float)) + self.assertEqual(alias.__parameters__, ()) + + with self.subTest("Testing instance checks"): + self.assertIsInstance(alias, GenericAlias) + + with self.subTest("Testing weakref"): + self.assertEqual(ref(alias)(), alias) + + with self.subTest("Testing pickling"): + s = pickle.dumps(alias) + loaded = pickle.loads(s) + self.assertEqual(alias.__origin__, loaded.__origin__) + self.assertEqual(alias.__args__, loaded.__args__) + self.assertEqual(alias.__parameters__, loaded.__parameters__) + + with self.subTest("Testing TypeVar substitution"): + C1 = Callable[[int, T], T] + C2 = Callable[[K, T], V] + C3 = Callable[..., T] + self.assertEqual(C1[str], Callable[[int, str], str]) + self.assertEqual(C2[int, float, str], Callable[[int, float], str]) + self.assertEqual(C3[int], Callable[..., int]) + + with self.subTest("Testing type erasure"): + class C1(Callable): + def __call__(self): + return None + a = C1[[int], T] + self.assertIs(a().__class__, C1) + self.assertEqual(a().__orig_class__, C1[[int], T]) + + # bpo-42195 + with self.subTest("Testing collections.abc.Callable's consistency " + "with typing.Callable"): + c1 = typing.Callable[[int, str], dict] + c2 = Callable[[int, str], dict] + self.assertEqual(c1.__args__, c2.__args__) + self.assertEqual(hash(c1.__args__), hash(c2.__args__)) + if __name__ == "__main__": unittest.main() diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index 13cf20eee09ab1..04dd6df6a9cc40 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -450,14 +450,6 @@ def test_cannot_instantiate(self): type(c)() def test_callable_wrong_forms(self): - with self.assertRaises(TypeError): - Callable[[...], int] - with self.assertRaises(TypeError): - Callable[(), int] - with self.assertRaises(TypeError): - Callable[[()], int] - with self.assertRaises(TypeError): - Callable[[int, 1], 2] with self.assertRaises(TypeError): Callable[int] diff --git a/Lib/typing.py b/Lib/typing.py index f5316ab8a5f538..1d6584db5afb28 100644 --- a/Lib/typing.py +++ b/Lib/typing.py @@ -118,6 +118,15 @@ # legitimate imports of those modules. +def _type_convert(arg): + """For converting None to type(None), and strings to ForwardRef.""" + if arg is None: + return type(None) + if isinstance(arg, str): + return ForwardRef(arg) + return arg + + def _type_check(arg, msg, is_argument=True): """Check that the argument is a type, and return it (internal helper). @@ -134,10 +143,7 @@ def _type_check(arg, msg, is_argument=True): if is_argument: invalid_generic_forms = invalid_generic_forms + (ClassVar, Final) - if arg is None: - return type(None) - if isinstance(arg, str): - return ForwardRef(arg) + arg = _type_convert(arg) if (isinstance(arg, _GenericAlias) and arg.__origin__ in invalid_generic_forms): raise TypeError(f"{arg} is not valid as type argument") @@ -859,13 +865,13 @@ def __getitem__(self, params): raise TypeError("Callable must be used as " "Callable[[arg, ...], result].") args, result = params - if args is Ellipsis: - params = (Ellipsis, result) - else: - if not isinstance(args, list): - raise TypeError(f"Callable[args, result]: args must be a list." - f" Got {args}") + # This relaxes what args can be on purpose to allow things like + # PEP 612 ParamSpec. Responsibility for whether a user is using + # Callable[...] properly is deferred to static type checkers. + if isinstance(args, list): params = (tuple(args), result) + else: + params = (args, result) return self.__getitem_inner__(params) @_tp_cache @@ -875,8 +881,9 @@ def __getitem_inner__(self, params): result = _type_check(result, msg) if args is Ellipsis: return self.copy_with((_TypingEllipsis, result)) - msg = "Callable[[arg, ...], result]: each arg must be a type." - args = tuple(_type_check(arg, msg) for arg in args) + if not isinstance(args, tuple): + args = (args,) + args = tuple(_type_convert(arg) for arg in args) params = args + (result,) return self.copy_with(params) diff --git a/Misc/NEWS.d/next/Core and Builtins/2020-11-20-00-57-47.bpo-42195.HeqcpS.rst b/Misc/NEWS.d/next/Core and Builtins/2020-11-20-00-57-47.bpo-42195.HeqcpS.rst new file mode 100644 index 00000000000000..636d4165a63897 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2020-11-20-00-57-47.bpo-42195.HeqcpS.rst @@ -0,0 +1,11 @@ +The ``__args__`` of the parameterized generics for :data:`typing.Callable` +and :class:`collections.abc.Callable` are now consistent. The ``__args__`` +for :class:`collections.abc.Callable` are now flattened while +:data:`typing.Callable`'s have not changed. To allow this change, +:class:`types.GenericAlias` can now be subclassed and +``collections.abc.Callable``'s ``__class_getitem__`` will now return a subclass +of ``types.GenericAlias``. Tests for typing were also updated to not subclass +things like ``Callable[..., T]`` as that is not a valid base class. Finally, +both types no longer validate their ``argtypes``, in +``Callable[[argtypes], resulttype]`` to prepare for :pep:`612`. Patch by Ken Jin. + diff --git a/Objects/genericaliasobject.c b/Objects/genericaliasobject.c index c5a81a5c1aab22..945d20593c7c90 100644 --- a/Objects/genericaliasobject.c +++ b/Objects/genericaliasobject.c @@ -428,8 +428,8 @@ ga_getattro(PyObject *self, PyObject *name) static PyObject * ga_richcompare(PyObject *a, PyObject *b, int op) { - if (!Py_IS_TYPE(a, &Py_GenericAliasType) || - !Py_IS_TYPE(b, &Py_GenericAliasType) || + if (!PyObject_TypeCheck(a, &Py_GenericAliasType) || + !PyObject_TypeCheck(b, &Py_GenericAliasType) || (op != Py_EQ && op != Py_NE)) { Py_RETURN_NOTIMPLEMENTED; @@ -563,6 +563,29 @@ static PyGetSetDef ga_properties[] = { {0} }; +/* A helper function to create GenericAlias' args tuple and set its attributes. + * Returns 1 on success, 0 on failure. + */ +static inline int +setup_ga(gaobject *alias, PyObject *origin, PyObject *args) { + if (!PyTuple_Check(args)) { + args = PyTuple_Pack(1, args); + if (args == NULL) { + return 0; + } + } + else { + Py_INCREF(args); + } + + Py_INCREF(origin); + alias->origin = origin; + alias->args = args; + alias->parameters = NULL; + alias->weakreflist = NULL; + return 1; +} + static PyObject * ga_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { @@ -574,7 +597,15 @@ ga_new(PyTypeObject *type, PyObject *args, PyObject *kwds) } PyObject *origin = PyTuple_GET_ITEM(args, 0); PyObject *arguments = PyTuple_GET_ITEM(args, 1); - return Py_GenericAlias(origin, arguments); + gaobject *self = (gaobject *)type->tp_alloc(type, 0); + if (self == NULL) { + return NULL; + } + if (!setup_ga(self, origin, arguments)) { + type->tp_free((PyObject *)self); + return NULL; + } + return (PyObject *)self; } // TODO: @@ -594,7 +625,7 @@ PyTypeObject Py_GenericAliasType = { .tp_hash = ga_hash, .tp_call = ga_call, .tp_getattro = ga_getattro, - .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_BASETYPE, .tp_traverse = ga_traverse, .tp_richcompare = ga_richcompare, .tp_weaklistoffset = offsetof(gaobject, weakreflist), @@ -609,27 +640,14 @@ PyTypeObject Py_GenericAliasType = { PyObject * Py_GenericAlias(PyObject *origin, PyObject *args) { - if (!PyTuple_Check(args)) { - args = PyTuple_Pack(1, args); - if (args == NULL) { - return NULL; - } - } - else { - Py_INCREF(args); - } - gaobject *alias = PyObject_GC_New(gaobject, &Py_GenericAliasType); if (alias == NULL) { - Py_DECREF(args); return NULL; } - - Py_INCREF(origin); - alias->origin = origin; - alias->args = args; - alias->parameters = NULL; - alias->weakreflist = NULL; + if (!setup_ga(alias, origin, args)) { + PyObject_GC_Del((PyObject *)alias); + return NULL; + } _PyObject_GC_TRACK(alias); return (PyObject *)alias; } From 20bc40ef44b820733848d5838e803b5fe4350b93 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 14 Dec 2020 09:38:03 -0800 Subject: [PATCH 0796/1314] bpo-36541: Add lib2to3 grammar PEP-570 pos-only arg parsing (GH-23759) Add positional only args support to lib2to3 pgen2. This adds 3.8's PEP-570 support to lib2to3's pgen2. lib2to3, while being deprecated is still used by things to parse all versions of Python code today. We need it to support parsing modern 3.8 and 3.9 constructs. Also add tests for complex *expr and **expr's. (cherry picked from commit 42c9f0fd0a5e67d4ae0022bfd7370cb9725a5b01) Co-authored-by: Gregory P. Smith --- Lib/lib2to3/Grammar.txt | 52 ++++++++++++++++--- Lib/lib2to3/tests/test_parser.py | 31 +++++++++++ .../2020-12-14-08-23-57.bpo-36541.qdEtZv.rst | 2 + 3 files changed, 79 insertions(+), 6 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2020-12-14-08-23-57.bpo-36541.qdEtZv.rst diff --git a/Lib/lib2to3/Grammar.txt b/Lib/lib2to3/Grammar.txt index e007dc188af503..fa7b15061d941c 100644 --- a/Lib/lib2to3/Grammar.txt +++ b/Lib/lib2to3/Grammar.txt @@ -18,15 +18,55 @@ decorated: decorators (classdef | funcdef | async_funcdef) async_funcdef: ASYNC funcdef funcdef: 'def' NAME parameters ['->' test] ':' suite parameters: '(' [typedargslist] ')' -typedargslist: ((tfpdef ['=' test] ',')* - ('*' [tname] (',' tname ['=' test])* [',' ['**' tname [',']]] | '**' tname [',']) - | tfpdef ['=' test] (',' tfpdef ['=' test])* [',']) + +# The following definition for typedarglist is equivalent to this set of rules: +# +# arguments = argument (',' argument)* +# argument = tfpdef ['=' test] +# kwargs = '**' tname [','] +# args = '*' [tname] +# kwonly_kwargs = (',' argument)* [',' [kwargs]] +# args_kwonly_kwargs = args kwonly_kwargs | kwargs +# poskeyword_args_kwonly_kwargs = arguments [',' [args_kwonly_kwargs]] +# typedargslist_no_posonly = poskeyword_args_kwonly_kwargs | args_kwonly_kwargs +# typedarglist = arguments ',' '/' [',' [typedargslist_no_posonly]])|(typedargslist_no_posonly)" +# +# It needs to be fully expanded to allow our LL(1) parser to work on it. + +typedargslist: tfpdef ['=' test] (',' tfpdef ['=' test])* ',' '/' [ + ',' [((tfpdef ['=' test] ',')* ('*' [tname] (',' tname ['=' test])* + [',' ['**' tname [',']]] | '**' tname [',']) + | tfpdef ['=' test] (',' tfpdef ['=' test])* [','])] + ] | ((tfpdef ['=' test] ',')* ('*' [tname] (',' tname ['=' test])* + [',' ['**' tname [',']]] | '**' tname [',']) + | tfpdef ['=' test] (',' tfpdef ['=' test])* [',']) + tname: NAME [':' test] tfpdef: tname | '(' tfplist ')' tfplist: tfpdef (',' tfpdef)* [','] -varargslist: ((vfpdef ['=' test] ',')* - ('*' [vname] (',' vname ['=' test])* [',' ['**' vname [',']]] | '**' vname [',']) - | vfpdef ['=' test] (',' vfpdef ['=' test])* [',']) + +# The following definition for varargslist is equivalent to this set of rules: +# +# arguments = argument (',' argument )* +# argument = vfpdef ['=' test] +# kwargs = '**' vname [','] +# args = '*' [vname] +# kwonly_kwargs = (',' argument )* [',' [kwargs]] +# args_kwonly_kwargs = args kwonly_kwargs | kwargs +# poskeyword_args_kwonly_kwargs = arguments [',' [args_kwonly_kwargs]] +# vararglist_no_posonly = poskeyword_args_kwonly_kwargs | args_kwonly_kwargs +# varargslist = arguments ',' '/' [','[(vararglist_no_posonly)]] | (vararglist_no_posonly) +# +# It needs to be fully expanded to allow our LL(1) parser to work on it. + +varargslist: vfpdef ['=' test ](',' vfpdef ['=' test])* ',' '/' [',' [ + ((vfpdef ['=' test] ',')* ('*' [vname] (',' vname ['=' test])* + [',' ['**' vname [',']]] | '**' vname [',']) + | vfpdef ['=' test] (',' vfpdef ['=' test])* [',']) + ]] | ((vfpdef ['=' test] ',')* + ('*' [vname] (',' vname ['=' test])* [',' ['**' vname [',']]]| '**' vname [',']) + | vfpdef ['=' test] (',' vfpdef ['=' test])* [',']) + vname: NAME vfpdef: vname | '(' vfplist ')' vfplist: vfpdef (',' vfpdef)* [','] diff --git a/Lib/lib2to3/tests/test_parser.py b/Lib/lib2to3/tests/test_parser.py index ba2bb787332edd..d5db66b9b1e7b9 100644 --- a/Lib/lib2to3/tests/test_parser.py +++ b/Lib/lib2to3/tests/test_parser.py @@ -272,6 +272,12 @@ def test_dict_display_1(self): def test_dict_display_2(self): self.validate("""{**{}, 3:4, **{5:6, 7:8}}""") + def test_complex_star_expression(self): + self.validate("func(* [] or [1])") + + def test_complex_double_star_expression(self): + self.validate("func(**{1: 3} if False else {x: x for x in range(3)})") + def test_argument_unpacking_1(self): self.validate("""f(a, *b, *c, d)""") @@ -630,6 +636,7 @@ def test_multiline_str_literals(self): class TestNamedAssignments(GrammarTest): + """Also known as the walrus operator.""" def test_named_assignment_if(self): driver.parse_string("if f := x(): pass\n") @@ -644,6 +651,30 @@ def test_named_assignment_listcomp(self): driver.parse_string("[(lastNum := num) == 1 for num in [1, 2, 3]]\n") +class TestPositionalOnlyArgs(GrammarTest): + + def test_one_pos_only_arg(self): + driver.parse_string("def one_pos_only_arg(a, /): pass\n") + + def test_all_markers(self): + driver.parse_string( + "def all_markers(a, b=2, /, c, d=4, *, e=5, f): pass\n") + + def test_all_with_args_and_kwargs(self): + driver.parse_string( + """def all_markers_with_args_and_kwargs( + aa, b, /, _cc, d, *args, e, f_f, **kwargs, + ): + pass\n""") + + def test_lambda_soup(self): + driver.parse_string( + "lambda a, b, /, c, d, *args, e, f, **kw: kw\n") + + def test_only_positional_or_keyword(self): + driver.parse_string("def func(a,b,/,*,g,e=3): pass\n") + + class TestPickleableException(unittest.TestCase): def test_ParseError(self): err = ParseError('msg', 2, None, (1, 'context')) diff --git a/Misc/NEWS.d/next/Library/2020-12-14-08-23-57.bpo-36541.qdEtZv.rst b/Misc/NEWS.d/next/Library/2020-12-14-08-23-57.bpo-36541.qdEtZv.rst new file mode 100644 index 00000000000000..5678d8c595ca08 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2020-12-14-08-23-57.bpo-36541.qdEtZv.rst @@ -0,0 +1,2 @@ +Fixed lib2to3.pgen2 to be able to parse PEP-570 positional only argument +syntax. From dbb00062dc3afb12c41c87564e6faefe60766b01 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 14 Dec 2020 14:33:27 -0800 Subject: [PATCH 0797/1314] bpo-42059: Fix required/optional keys for TypedDict(..., total=False) (GH-22736) (GH-23747) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit (cherry picked from commit 67b769f5157c9dad1c7dd6b24e067b9fdab5b35d) Co-authored-by: Alex Grönholm --- Lib/test/test_typing.py | 4 ++++ Lib/typing.py | 4 ++-- .../next/Library/2020-10-17-12-42-08.bpo-42059.ZGMZ3D.rst | 1 + 3 files changed, 7 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2020-10-17-12-42-08.bpo-42059.ZGMZ3D.rst diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index 04dd6df6a9cc40..3b3aa29de7221d 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -3891,10 +3891,14 @@ def test_total(self): self.assertEqual(D(), {}) self.assertEqual(D(x=1), {'x': 1}) self.assertEqual(D.__total__, False) + self.assertEqual(D.__required_keys__, frozenset()) + self.assertEqual(D.__optional_keys__, {'x'}) self.assertEqual(Options(), {}) self.assertEqual(Options(log_level=2), {'log_level': 2}) self.assertEqual(Options.__total__, False) + self.assertEqual(Options.__required_keys__, frozenset()) + self.assertEqual(Options.__optional_keys__, {'log_level', 'log_path'}) def test_optional_keys(self): class Point2Dor3D(Point2D, total=False): diff --git a/Lib/typing.py b/Lib/typing.py index 1d6584db5afb28..81e4a2fa403b9a 100644 --- a/Lib/typing.py +++ b/Lib/typing.py @@ -1987,14 +1987,14 @@ class body be required. raise TypeError("TypedDict takes either a dict or keyword arguments," " but not both") - ns = {'__annotations__': dict(fields), '__total__': total} + ns = {'__annotations__': dict(fields)} try: # Setting correct module is necessary to make typed dict classes pickleable. ns['__module__'] = sys._getframe(1).f_globals.get('__name__', '__main__') except (AttributeError, ValueError): pass - return _TypedDictMeta(typename, (), ns) + return _TypedDictMeta(typename, (), ns, total=total) _TypedDict = type.__new__(_TypedDictMeta, 'TypedDict', (), {}) TypedDict.__mro_entries__ = lambda bases: (_TypedDict,) diff --git a/Misc/NEWS.d/next/Library/2020-10-17-12-42-08.bpo-42059.ZGMZ3D.rst b/Misc/NEWS.d/next/Library/2020-10-17-12-42-08.bpo-42059.ZGMZ3D.rst new file mode 100644 index 00000000000000..3f18824fe65987 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2020-10-17-12-42-08.bpo-42059.ZGMZ3D.rst @@ -0,0 +1 @@ +:class:`typing.TypedDict` types created using the alternative call-style syntax now correctly respect the ``total`` keyword argument when setting their ``__required_keys__`` and ``__optional_keys__`` class attributes. From 33cbb04986d0dabb9c542edc52bb4ea6106d3a81 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 14 Dec 2020 14:43:43 -0800 Subject: [PATCH 0798/1314] bpo-40084: Enum - dir() includes member attributes (GH-19219) (cherry picked from commit 68526fe258da8c01196fd7cf48e8e5f1280bf8fd) Co-authored-by: Angelin BOOZ <9497359+lem2clide@users.noreply.github.com> --- Lib/enum.py | 2 +- Lib/test/test_enum.py | 12 ++++++++++++ Lib/test/test_httplib.py | 6 +++++- Misc/ACKS | 1 + .../Library/2020-03-29-21-32-00.bpo-40084.MCYwcv.rst | 1 + 5 files changed, 20 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2020-03-29-21-32-00.bpo-40084.MCYwcv.rst diff --git a/Lib/enum.py b/Lib/enum.py index b14da088f33bf3..35210c993325db 100644 --- a/Lib/enum.py +++ b/Lib/enum.py @@ -699,7 +699,7 @@ def __dir__(self): for cls in self.__class__.mro() for m in cls.__dict__ if m[0] != '_' and m not in self._member_map_ - ] + ] + [m for m in self.__dict__ if m[0] != '_'] return (['__class__', '__doc__', '__module__'] + added_behavior) def __format__(self, format_spec): diff --git a/Lib/test/test_enum.py b/Lib/test/test_enum.py index ccc2cbe1ec14b5..dca668a9046f36 100644 --- a/Lib/test/test_enum.py +++ b/Lib/test/test_enum.py @@ -215,6 +215,18 @@ class SubEnum(SuperEnum): set(['__class__', '__doc__', '__module__', 'name', 'value', 'invisible']), ) + def test_dir_on_sub_with_behavior_including_instance_dict_on_super(self): + # see issue40084 + class SuperEnum(IntEnum): + def __new__(cls, value, description=""): + obj = int.__new__(cls, value) + obj._value_ = value + obj.description = description + return obj + class SubEnum(SuperEnum): + sample = 5 + self.assertTrue({'description'} <= set(dir(SubEnum.sample))) + def test_enum_in_enum_out(self): Season = self.Season self.assertIs(Season(Season.WINTER), Season.WINTER) diff --git a/Lib/test/test_httplib.py b/Lib/test/test_httplib.py index ed125893d6d072..28943f02564fb0 100644 --- a/Lib/test/test_httplib.py +++ b/Lib/test/test_httplib.py @@ -1,5 +1,5 @@ import errno -from http import client +from http import client, HTTPStatus import io import itertools import os @@ -516,6 +516,10 @@ def _parse_chunked(self, data): class BasicTest(TestCase): + def test_dir_with_added_behavior_on_status(self): + # see issue40084 + self.assertTrue({'description', 'name', 'phrase', 'value'} <= set(dir(HTTPStatus(404)))) + def test_status_lines(self): # Test HTTP status lines diff --git a/Misc/ACKS b/Misc/ACKS index 12a5ac1410a770..ebf12c9a9f1dcf 100644 --- a/Misc/ACKS +++ b/Misc/ACKS @@ -192,6 +192,7 @@ Gawain Bolton Carl Friedrich Bolz-Tereick Forest Bond Gregory Bond +Angelin Booz Médéric Boquien Matias Bordese Jonas Borgström diff --git a/Misc/NEWS.d/next/Library/2020-03-29-21-32-00.bpo-40084.MCYwcv.rst b/Misc/NEWS.d/next/Library/2020-03-29-21-32-00.bpo-40084.MCYwcv.rst new file mode 100644 index 00000000000000..65ff4ce36e82ea --- /dev/null +++ b/Misc/NEWS.d/next/Library/2020-03-29-21-32-00.bpo-40084.MCYwcv.rst @@ -0,0 +1 @@ +Fix ``Enum.__dir__``: dir(Enum.member) now includes attributes as well as methods. From 6b2ed385094839c1920b934f07d946bf049a3770 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Tue, 15 Dec 2020 00:31:54 +0100 Subject: [PATCH 0799/1314] bpo-42591: Export missing Py_FrozenMain() symbol (GH-23730) (GH-23734) Export the Py_FrozenMain() function: fix a Python 3.9.0 regression. Python 3.9 uses -fvisibility=hidden and the function was not exported explicitly and so not exported. (cherry picked from commit b5c7b38f5ebbc84b5b80192db1743d3e1cdcf4c5) --- Include/pylifecycle.h | 2 ++ .../NEWS.d/next/C API/2020-12-10-10-43-03.bpo-42591.CXNY8G.rst | 3 +++ 2 files changed, 5 insertions(+) create mode 100644 Misc/NEWS.d/next/C API/2020-12-10-10-43-03.bpo-42591.CXNY8G.rst diff --git a/Include/pylifecycle.h b/Include/pylifecycle.h index c5368b3c5edaa0..783fcb455eb528 100644 --- a/Include/pylifecycle.h +++ b/Include/pylifecycle.h @@ -32,6 +32,8 @@ PyAPI_FUNC(void) _Py_NO_RETURN Py_Exit(int); /* Bootstrap __main__ (defined in Modules/main.c) */ PyAPI_FUNC(int) Py_Main(int argc, wchar_t **argv); +PyAPI_FUNC(int) Py_FrozenMain(int argc, char **argv); + PyAPI_FUNC(int) Py_BytesMain(int argc, char **argv); /* In pathconfig.c */ diff --git a/Misc/NEWS.d/next/C API/2020-12-10-10-43-03.bpo-42591.CXNY8G.rst b/Misc/NEWS.d/next/C API/2020-12-10-10-43-03.bpo-42591.CXNY8G.rst new file mode 100644 index 00000000000000..3519859f7be89d --- /dev/null +++ b/Misc/NEWS.d/next/C API/2020-12-10-10-43-03.bpo-42591.CXNY8G.rst @@ -0,0 +1,3 @@ +Export the :c:func:`Py_FrozenMain` function: fix a Python 3.9.0 regression. +Python 3.9 uses ``-fvisibility=hidden`` and the function was not exported +explicitly and so not exported. From aba12b67c18b17bb727a0d50dd0653e38cb64dc8 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 14 Dec 2020 15:56:58 -0800 Subject: [PATCH 0800/1314] [3.9] bpo-42517: [Enum] deprecate private name members (GH-23722) (GH-23748) private names will raise a DeprecationWarning; in 3.10 they will become normal attributes --- Doc/library/enum.rst | 9 ++++++++ Lib/enum.py | 22 +++++++++++++++++++ Lib/test/test_enum.py | 18 +++++++++++++++ .../2020-12-09-10-59-16.bpo-42517.FKEVcZ.rst | 2 ++ 4 files changed, 51 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2020-12-09-10-59-16.bpo-42517.FKEVcZ.rst diff --git a/Doc/library/enum.rst b/Doc/library/enum.rst index a3c51655576ba5..4ecca209d87b3d 100644 --- a/Doc/library/enum.rst +++ b/Doc/library/enum.rst @@ -1121,6 +1121,15 @@ and raise an error if the two do not match:: In Python 2 code the :attr:`_order_` attribute is necessary as definition order is lost before it can be recorded. + +_Private__names +""""""""""""""" + +Private names will be normal attributes in Python 3.10 instead of either an error +or a member (depending on if the name ends with an underscore). Using these names +in 3.9 will issue a :exc:`DeprecationWarning`. + + ``Enum`` member type """""""""""""""""""" diff --git a/Lib/enum.py b/Lib/enum.py index 35210c993325db..46b5435b7c8e06 100644 --- a/Lib/enum.py +++ b/Lib/enum.py @@ -41,6 +41,19 @@ def _is_sunder(name): name[-2:-1] != '_' ) +def _is_private(cls_name, name): + # do not use `re` as `re` imports `enum` + pattern = '_%s__' % (cls_name, ) + if ( + len(name) >= 5 + and name.startswith(pattern) + and name[len(pattern)] != '_' + and (name[-1] != '_' or name[-2] != '_') + ): + return True + else: + return False + def _make_class_unpicklable(cls): """ Make the given class un-picklable. @@ -81,6 +94,14 @@ def __setitem__(self, key, value): Single underscore (sunder) names are reserved. """ + if _is_private(self._cls_name, key): + import warnings + warnings.warn( + "private variables, such as %r, will be normal attributes in 3.10" + % (key, ), + DeprecationWarning, + stacklevel=2, + ) if _is_sunder(key): if key not in ( '_order_', '_create_pseudo_member_', @@ -146,6 +167,7 @@ def __prepare__(metacls, cls, bases): metacls._check_for_existing_members(cls, bases) # create the namespace dict enum_dict = _EnumDict() + enum_dict._cls_name = cls # inherit previous flags and _generate_next_value_ function member_type, first_enum = metacls._get_mixins_(cls, bases) if first_enum is not None: diff --git a/Lib/test/test_enum.py b/Lib/test/test_enum.py index dca668a9046f36..f7f8522bda4f35 100644 --- a/Lib/test/test_enum.py +++ b/Lib/test/test_enum.py @@ -1147,6 +1147,7 @@ def test_multiple_mixin_mro(self): class auto_enum(type(Enum)): def __new__(metacls, cls, bases, classdict): temp = type(classdict)() + temp._cls_name = cls names = set(classdict._member_names) i = 0 for k in classdict._member_names: @@ -2049,6 +2050,23 @@ def test_empty_globals(self): exec(code, global_ns, local_ls) + @unittest.skipUnless( + sys.version_info[:2] == (3, 9), + 'private variables are now normal attributes', + ) + def test_warning_for_private_variables(self): + with self.assertWarns(DeprecationWarning): + class Private(Enum): + __corporal = 'Radar' + self.assertEqual(Private._Private__corporal.value, 'Radar') + try: + with self.assertWarns(DeprecationWarning): + class Private(Enum): + __major_ = 'Hoolihan' + except ValueError: + pass + + class TestOrder(unittest.TestCase): def test_same_members(self): diff --git a/Misc/NEWS.d/next/Library/2020-12-09-10-59-16.bpo-42517.FKEVcZ.rst b/Misc/NEWS.d/next/Library/2020-12-09-10-59-16.bpo-42517.FKEVcZ.rst new file mode 100644 index 00000000000000..e99294d9430d1a --- /dev/null +++ b/Misc/NEWS.d/next/Library/2020-12-09-10-59-16.bpo-42517.FKEVcZ.rst @@ -0,0 +1,2 @@ +Enum: private names will raise a DeprecationWarning; in 3.10 they will +become normal attributes From 9d1fff1fcd5332f0ba7f72d0e0f9f66b47ec4e8d Mon Sep 17 00:00:00 2001 From: Ethan Furman Date: Mon, 14 Dec 2020 18:41:34 -0800 Subject: [PATCH 0801/1314] [3.9] bpo-42567: [Enum] call __init_subclass__ after members are added (GH-23714) (GH-23772) When creating an Enum, `type.__new__` calls `__init_subclass__`, but at that point the members have not been added. This patch suppresses the initial call, then manually calls the ancestor `__init_subclass__` before returning the new Enum class. (cherry picked from commit 6bd94de168b58ac9358277ed6f200490ab26c174) --- Lib/enum.py | 32 +++++++- Lib/test/test_enum.py | 73 ++++++++++++++++++- .../2020-12-08-22-43-35.bpo-42678.ba9ktU.rst | 1 + 3 files changed, 103 insertions(+), 3 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2020-12-08-22-43-35.bpo-42678.ba9ktU.rst diff --git a/Lib/enum.py b/Lib/enum.py index 46b5435b7c8e06..88c951f4f12b46 100644 --- a/Lib/enum.py +++ b/Lib/enum.py @@ -9,6 +9,14 @@ ] +class _NoInitSubclass: + """ + temporary base class to suppress calling __init_subclass__ + """ + @classmethod + def __init_subclass__(cls, **kwds): + pass + def _is_descriptor(obj): """ Returns True if obj is a descriptor, False otherwise. @@ -176,7 +184,7 @@ def __prepare__(metacls, cls, bases): ) return enum_dict - def __new__(metacls, cls, bases, classdict): + def __new__(metacls, cls, bases, classdict, **kwds): # an Enum class is final once enumeration items have been defined; it # cannot be mixed with other types (int, float, etc.) if it has an # inherited __new__ unless a new __new__ is defined (or the resulting @@ -211,8 +219,22 @@ def __new__(metacls, cls, bases, classdict): if '__doc__' not in classdict: classdict['__doc__'] = 'An enumeration.' + # postpone calling __init_subclass__ + if '__init_subclass__' in classdict and classdict['__init_subclass__'] is None: + raise TypeError('%s.__init_subclass__ cannot be None') + # remove current __init_subclass__ so previous one can be found with getattr + new_init_subclass = classdict.pop('__init_subclass__', None) # create our new Enum type - enum_class = super().__new__(metacls, cls, bases, classdict) + if bases: + bases = (_NoInitSubclass, ) + bases + enum_class = type.__new__(metacls, cls, bases, classdict) + enum_class.__bases__ = enum_class.__bases__[1:] #or (object, ) + else: + enum_class = type.__new__(metacls, cls, bases, classdict) + old_init_subclass = getattr(enum_class, '__init_subclass__', None) + # and restore the new one (if there was one) + if new_init_subclass is not None: + enum_class.__init_subclass__ = classmethod(new_init_subclass) enum_class._member_names_ = [] # names in definition order enum_class._member_map_ = {} # name->value map enum_class._member_type_ = member_type @@ -324,6 +346,9 @@ def __new__(metacls, cls, bases, classdict): if _order_ != enum_class._member_names_: raise TypeError('member order does not match _order_') + # finally, call parents' __init_subclass__ + if Enum is not None and old_init_subclass is not None: + old_init_subclass(**kwds) return enum_class def __bool__(self): @@ -701,6 +726,9 @@ def _generate_next_value_(name, start, count, last_values): else: return start + def __init_subclass__(cls, **kwds): + super().__init_subclass__(**kwds) + @classmethod def _missing_(cls, value): return None diff --git a/Lib/test/test_enum.py b/Lib/test/test_enum.py index f7f8522bda4f35..0868c30347216d 100644 --- a/Lib/test/test_enum.py +++ b/Lib/test/test_enum.py @@ -2049,7 +2049,6 @@ def test_empty_globals(self): local_ls = {} exec(code, global_ns, local_ls) - @unittest.skipUnless( sys.version_info[:2] == (3, 9), 'private variables are now normal attributes', @@ -2066,6 +2065,42 @@ class Private(Enum): except ValueError: pass + def test_init_subclass(self): + class MyEnum(Enum): + def __init_subclass__(cls, **kwds): + super(MyEnum, cls).__init_subclass__(**kwds) + self.assertFalse(cls.__dict__.get('_test', False)) + cls._test1 = 'MyEnum' + # + class TheirEnum(MyEnum): + def __init_subclass__(cls, **kwds): + super().__init_subclass__(**kwds) + cls._test2 = 'TheirEnum' + class WhoseEnum(TheirEnum): + def __init_subclass__(cls, **kwds): + pass + class NoEnum(WhoseEnum): + ONE = 1 + self.assertEqual(TheirEnum.__dict__['_test1'], 'MyEnum') + self.assertEqual(WhoseEnum.__dict__['_test1'], 'MyEnum') + self.assertEqual(WhoseEnum.__dict__['_test2'], 'TheirEnum') + self.assertFalse(NoEnum.__dict__.get('_test1', False)) + self.assertFalse(NoEnum.__dict__.get('_test2', False)) + # + class OurEnum(MyEnum): + def __init_subclass__(cls, **kwds): + cls._test2 = 'OurEnum' + class WhereEnum(OurEnum): + def __init_subclass__(cls, **kwds): + pass + class NeverEnum(WhereEnum): + ONE = 'one' + self.assertEqual(OurEnum.__dict__['_test1'], 'MyEnum') + self.assertFalse(WhereEnum.__dict__.get('_test1', False)) + self.assertEqual(WhereEnum.__dict__['_test2'], 'OurEnum') + self.assertFalse(NeverEnum.__dict__.get('_test1', False)) + self.assertFalse(NeverEnum.__dict__.get('_test2', False)) + class TestOrder(unittest.TestCase): @@ -2516,6 +2551,42 @@ def cycle_enum(): 'at least one thread failed while creating composite members') self.assertEqual(256, len(seen), 'too many composite members created') + def test_init_subclass(self): + class MyEnum(Flag): + def __init_subclass__(cls, **kwds): + super().__init_subclass__(**kwds) + self.assertFalse(cls.__dict__.get('_test', False)) + cls._test1 = 'MyEnum' + # + class TheirEnum(MyEnum): + def __init_subclass__(cls, **kwds): + super(TheirEnum, cls).__init_subclass__(**kwds) + cls._test2 = 'TheirEnum' + class WhoseEnum(TheirEnum): + def __init_subclass__(cls, **kwds): + pass + class NoEnum(WhoseEnum): + ONE = 1 + self.assertEqual(TheirEnum.__dict__['_test1'], 'MyEnum') + self.assertEqual(WhoseEnum.__dict__['_test1'], 'MyEnum') + self.assertEqual(WhoseEnum.__dict__['_test2'], 'TheirEnum') + self.assertFalse(NoEnum.__dict__.get('_test1', False)) + self.assertFalse(NoEnum.__dict__.get('_test2', False)) + # + class OurEnum(MyEnum): + def __init_subclass__(cls, **kwds): + cls._test2 = 'OurEnum' + class WhereEnum(OurEnum): + def __init_subclass__(cls, **kwds): + pass + class NeverEnum(WhereEnum): + ONE = 1 + self.assertEqual(OurEnum.__dict__['_test1'], 'MyEnum') + self.assertFalse(WhereEnum.__dict__.get('_test1', False)) + self.assertEqual(WhereEnum.__dict__['_test2'], 'OurEnum') + self.assertFalse(NeverEnum.__dict__.get('_test1', False)) + self.assertFalse(NeverEnum.__dict__.get('_test2', False)) + class TestIntFlag(unittest.TestCase): """Tests of the IntFlags.""" diff --git a/Misc/NEWS.d/next/Library/2020-12-08-22-43-35.bpo-42678.ba9ktU.rst b/Misc/NEWS.d/next/Library/2020-12-08-22-43-35.bpo-42678.ba9ktU.rst new file mode 100644 index 00000000000000..7c94cdf40dd4cc --- /dev/null +++ b/Misc/NEWS.d/next/Library/2020-12-08-22-43-35.bpo-42678.ba9ktU.rst @@ -0,0 +1 @@ +`Enum`: call `__init_subclass__` after members have been added From 99d37a0ee82c16f30a874c9b583d59a3844dc9c9 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 15 Dec 2020 04:51:56 -0800 Subject: [PATCH 0802/1314] bpo-33610: Edit idlelib.codecontext (GH-23773) (GH-23775) Add sentence to module docstring and import tkinter items. (cherry picked from commit 6f79e60b66dacefca147bdaa80eb37f936a72991) Co-authored-by: Terry Jan Reedy --- Lib/idlelib/codecontext.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/Lib/idlelib/codecontext.py b/Lib/idlelib/codecontext.py index 989b30e5994650..eb19773f56e34b 100644 --- a/Lib/idlelib/codecontext.py +++ b/Lib/idlelib/codecontext.py @@ -7,11 +7,14 @@ enclosing block. The number of hint lines is determined by the maxlines variable in the codecontext section of config-extensions.def. Lines which do not open blocks are not shown in the context hints pane. + +For EditorWindows, <> is bound to CodeContext(self). +toggle_code_context_event. """ import re from sys import maxsize as INFINITY -import tkinter +from tkinter import Frame, Text, TclError from tkinter.constants import NSEW, SUNKEN from idlelib.config import idleConf @@ -83,7 +86,7 @@ def __del__(self): if self.t1 is not None: try: self.text.after_cancel(self.t1) - except tkinter.TclError: # pragma: no cover + except TclError: # pragma: no cover pass self.t1 = None @@ -111,7 +114,7 @@ def toggle_code_context_event(self, event=None): padx += widget.tk.getint(info['padx']) padx += widget.tk.getint(widget.cget('padx')) border += widget.tk.getint(widget.cget('border')) - context = self.context = tkinter.Text( + context = self.context = Text( self.editwin.text_frame, height=1, width=1, # Don't request more than we get. @@ -127,7 +130,7 @@ def toggle_code_context_event(self, event=None): line_number_colors = idleConf.GetHighlight(idleConf.CurrentTheme(), 'linenumber') - self.cell00 = tkinter.Frame(self.editwin.text_frame, + self.cell00 = Frame(self.editwin.text_frame, bg=line_number_colors['background']) self.cell00.grid(row=0, column=0, sticky=NSEW) menu_status = 'Hide' @@ -221,7 +224,7 @@ def jumptoline(self, event=None): """ try: self.context.index("sel.first") - except tkinter.TclError: + except TclError: lines = len(self.info) if lines == 1: # No context lines are showing. newtop = 1 From 28bf6ab61f77c69b732a211c398ac882bf3f65f4 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Tue, 15 Dec 2020 20:44:44 +0200 Subject: [PATCH 0803/1314] [3.9] bpo-42318: Fix support of non-BMP characters in Tkinter on macOS (GH-23281). (GH-23784) (cherry picked from commit a26215db11cfcf7b5f55cab9e91396761a0e0bcf) --- Lib/test/test_tcl.py | 46 +++++++++++++--- .../2020-11-14-13-46-27.bpo-42318.wYAcBD.rst | 1 + Modules/_tkinter.c | 54 ++++++++++++++++++- 3 files changed, 94 insertions(+), 7 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2020-11-14-13-46-27.bpo-42318.wYAcBD.rst diff --git a/Lib/test/test_tcl.py b/Lib/test/test_tcl.py index 1c5b9cf2bd2a83..bc8926a239921c 100644 --- a/Lib/test/test_tcl.py +++ b/Lib/test/test_tcl.py @@ -1,4 +1,5 @@ import unittest +import locale import re import subprocess import sys @@ -59,6 +60,10 @@ def test_eval_null_in_result(self): tcl = self.interp self.assertEqual(tcl.eval('set a "a\\0b"'), 'a\x00b') + def test_eval_surrogates_in_result(self): + tcl = self.interp + self.assertIn(tcl.eval(r'set a "<\ud83d\udcbb>"'), '<\U0001f4bb>') + def testEvalException(self): tcl = self.interp self.assertRaises(TclError,tcl.eval,'set a') @@ -191,29 +196,48 @@ def test_getboolean(self): def testEvalFile(self): tcl = self.interp - with open(support.TESTFN, 'w') as f: - self.addCleanup(support.unlink, support.TESTFN) + filename = support.TESTFN_ASCII + self.addCleanup(support.unlink, filename) + with open(filename, 'w') as f: f.write("""set a 1 set b 2 set c [ expr $a + $b ] """) - tcl.evalfile(support.TESTFN) + tcl.evalfile(filename) self.assertEqual(tcl.eval('set a'),'1') self.assertEqual(tcl.eval('set b'),'2') self.assertEqual(tcl.eval('set c'),'3') def test_evalfile_null_in_result(self): tcl = self.interp - with open(support.TESTFN, 'w') as f: - self.addCleanup(support.unlink, support.TESTFN) + filename = support.TESTFN_ASCII + self.addCleanup(support.unlink, filename) + with open(filename, 'w') as f: f.write(""" set a "a\0b" set b "a\\0b" """) - tcl.evalfile(support.TESTFN) + tcl.evalfile(filename) self.assertEqual(tcl.eval('set a'), 'a\x00b') self.assertEqual(tcl.eval('set b'), 'a\x00b') + def test_evalfile_surrogates_in_result(self): + tcl = self.interp + encoding = tcl.call('encoding', 'system') + self.addCleanup(tcl.call, 'encoding', 'system', encoding) + tcl.call('encoding', 'system', 'utf-8') + + filename = support.TESTFN_ASCII + self.addCleanup(support.unlink, filename) + with open(filename, 'wb') as f: + f.write(b""" + set a "<\xed\xa0\xbd\xed\xb2\xbb>" + set b "<\\ud83d\\udcbb>" + """) + tcl.evalfile(filename) + self.assertEqual(tcl.eval('set a'), '<\U0001f4bb>') + self.assertEqual(tcl.eval('set b'), '<\U0001f4bb>') + def testEvalFileException(self): tcl = self.interp filename = "doesnotexists" @@ -436,6 +460,11 @@ def passValue(value): self.assertEqual(passValue('str\x00ing\u20ac'), 'str\x00ing\u20ac') self.assertEqual(passValue('str\x00ing\U0001f4bb'), 'str\x00ing\U0001f4bb') + if sys.platform != 'win32': + self.assertEqual(passValue('<\udce2\udc82\udcac>'), + '<\u20ac>') + self.assertEqual(passValue('<\udced\udca0\udcbd\udced\udcb2\udcbb>'), + '<\U0001f4bb>') self.assertEqual(passValue(b'str\x00ing'), b'str\x00ing' if self.wantobjects else 'str\x00ing') self.assertEqual(passValue(b'str\xc0\x80ing'), @@ -495,6 +524,9 @@ def float_eq(actual, expected): check('string\xbd') check('string\u20ac') check('string\U0001f4bb') + if sys.platform != 'win32': + check('<\udce2\udc82\udcac>', '<\u20ac>') + check('<\udced\udca0\udcbd\udced\udcb2\udcbb>', '<\U0001f4bb>') check('') check(b'string', 'string') check(b'string\xe2\x82\xac', 'string\xe2\x82\xac') @@ -538,6 +570,8 @@ def test_splitlist(self): ('a \u20ac', ('a', '\u20ac')), ('a \U0001f4bb', ('a', '\U0001f4bb')), (b'a \xe2\x82\xac', ('a', '\u20ac')), + (b'a \xf0\x9f\x92\xbb', ('a', '\U0001f4bb')), + (b'a \xed\xa0\xbd\xed\xb2\xbb', ('a', '\U0001f4bb')), (b'a\xc0\x80b c\xc0\x80d', ('a\x00b', 'c\x00d')), ('a {b c}', ('a', 'b c')), (r'a b\ c', ('a', 'b c')), diff --git a/Misc/NEWS.d/next/Library/2020-11-14-13-46-27.bpo-42318.wYAcBD.rst b/Misc/NEWS.d/next/Library/2020-11-14-13-46-27.bpo-42318.wYAcBD.rst new file mode 100644 index 00000000000000..e72daebb2f152a --- /dev/null +++ b/Misc/NEWS.d/next/Library/2020-11-14-13-46-27.bpo-42318.wYAcBD.rst @@ -0,0 +1 @@ +Fixed support of non-BMP characters in :mod:`tkinter` on macOS. diff --git a/Modules/_tkinter.c b/Modules/_tkinter.c index 793c5e71548846..b30141d4497bda 100644 --- a/Modules/_tkinter.c +++ b/Modules/_tkinter.c @@ -395,7 +395,8 @@ unicodeFromTclStringAndSize(const char *s, Py_ssize_t size) char *buf = NULL; PyErr_Clear(); - /* Tcl encodes null character as \xc0\x80 */ + /* Tcl encodes null character as \xc0\x80. + https://en.wikipedia.org/wiki/UTF-8#Modified_UTF-8 */ if (memchr(s, '\xc0', size)) { char *q; const char *e = s + size; @@ -419,6 +420,57 @@ unicodeFromTclStringAndSize(const char *s, Py_ssize_t size) if (buf != NULL) { PyMem_Free(buf); } + if (r == NULL || PyUnicode_KIND(r) == PyUnicode_1BYTE_KIND) { + return r; + } + + /* In CESU-8 non-BMP characters are represented as a surrogate pair, + like in UTF-16, and then each surrogate code point is encoded in UTF-8. + https://en.wikipedia.org/wiki/CESU-8 */ + Py_ssize_t len = PyUnicode_GET_LENGTH(r); + Py_ssize_t i, j; + /* All encoded surrogate characters start with \xED. */ + i = PyUnicode_FindChar(r, 0xdcED, 0, len, 1); + if (i == -2) { + Py_DECREF(r); + return NULL; + } + if (i == -1) { + return r; + } + Py_UCS4 *u = PyUnicode_AsUCS4Copy(r); + Py_DECREF(r); + if (u == NULL) { + return NULL; + } + Py_UCS4 ch; + for (j = i; i < len; i++, u[j++] = ch) { + Py_UCS4 ch1, ch2, ch3, high, low; + /* Low surrogates U+D800 - U+DBFF are encoded as + \xED\xA0\x80 - \xED\xAF\xBF. */ + ch1 = ch = u[i]; + if (ch1 != 0xdcED) continue; + ch2 = u[i + 1]; + if (!(0xdcA0 <= ch2 && ch2 <= 0xdcAF)) continue; + ch3 = u[i + 2]; + if (!(0xdc80 <= ch3 && ch3 <= 0xdcBF)) continue; + high = 0xD000 | ((ch2 & 0x3F) << 6) | (ch3 & 0x3F); + assert(Py_UNICODE_IS_HIGH_SURROGATE(high)); + /* High surrogates U+DC00 - U+DFFF are encoded as + \xED\xB0\x80 - \xED\xBF\xBF. */ + ch1 = u[i + 3]; + if (ch1 != 0xdcED) continue; + ch2 = u[i + 4]; + if (!(0xdcB0 <= ch2 && ch2 <= 0xdcBF)) continue; + ch3 = u[i + 5]; + if (!(0xdc80 <= ch3 && ch3 <= 0xdcBF)) continue; + low = 0xD000 | ((ch2 & 0x3F) << 6) | (ch3 & 0x3F); + assert(Py_UNICODE_IS_HIGH_SURROGATE(high)); + ch = Py_UNICODE_JOIN_SURROGATES(high, low); + i += 5; + } + r = PyUnicode_FromKindAndData(PyUnicode_4BYTE_KIND, u, j); + PyMem_Free(u); return r; } From db63da7e5d4a98925a04f903a19bf3595b9c2c46 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 16 Dec 2020 02:12:08 -0800 Subject: [PATCH 0804/1314] bpo-42644: Validate values in logging.disable() (GH-23786) * bpo-42644: Validate values in logging.disable() Technically make the value of manager a property that checks and convert values assigned to it properly. This has the side effect of making `logging.disable` also accept strings representing the various level of warnings. We want to validate the type of the disable attribute at assignment time, as it is later compared to other levels when emitting warnings and would generate a `TypeError: '>=' not supported between ....` in a different part of the code base, which can make it difficult to track down. When assigned an incorrect value; it will raise a TypeError when the wrong type, or ValueError if an invalid str. Co-authored-by: Andrew Svetlov (cherry picked from commit b32d8b4f9bcd2e7d11240b6b9de0262cf8f5e09d) Co-authored-by: Matthias Bussonnier --- Lib/logging/__init__.py | 8 ++++++++ Lib/test/test_logging.py | 9 +++++++++ .../Library/2020-12-15-10-00-04.bpo-42644.XgLCNx.rst | 3 +++ 3 files changed, 20 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2020-12-15-10-00-04.bpo-42644.XgLCNx.rst diff --git a/Lib/logging/__init__.py b/Lib/logging/__init__.py index 7b169a16fbb70f..6920a7b654a598 100644 --- a/Lib/logging/__init__.py +++ b/Lib/logging/__init__.py @@ -1269,6 +1269,14 @@ def __init__(self, rootnode): self.loggerClass = None self.logRecordFactory = None + @property + def disable(self): + return self._disable + + @disable.setter + def disable(self, value): + self._disable = _checkLevel(value) + def getLogger(self, name): """ Get a logger with the specified name (channel name), creating it diff --git a/Lib/test/test_logging.py b/Lib/test/test_logging.py index 410eae22086884..a6cd291c9a5536 100644 --- a/Lib/test/test_logging.py +++ b/Lib/test/test_logging.py @@ -4191,6 +4191,15 @@ def test_disable(self): logging.disable(83) self.assertEqual(logging.root.manager.disable, 83) + self.assertRaises(ValueError, logging.disable, "doesnotexists") + + class _NotAnIntOrString: + pass + + self.assertRaises(TypeError, logging.disable, _NotAnIntOrString()) + + logging.disable("WARN") + # test the default value introduced in 3.7 # (Issue #28524) logging.disable() diff --git a/Misc/NEWS.d/next/Library/2020-12-15-10-00-04.bpo-42644.XgLCNx.rst b/Misc/NEWS.d/next/Library/2020-12-15-10-00-04.bpo-42644.XgLCNx.rst new file mode 100644 index 00000000000000..f58b58e4002ada --- /dev/null +++ b/Misc/NEWS.d/next/Library/2020-12-15-10-00-04.bpo-42644.XgLCNx.rst @@ -0,0 +1,3 @@ +`logging.disable` will now validate the types and value of its parameter. It +also now accepts strings representing the levels (as does `loging.setLevel`) +instead of only the numerical values. From cd7412e3c4a2805009d0baa948cd4026d6fa6f3d Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 16 Dec 2020 02:54:04 -0800 Subject: [PATCH 0805/1314] bpo-19733: Re-enable tests for -image option in Tkinter (GH-23785) (cherry picked from commit 5f0fe8ec70120f4586d08978b0911b436f82c421) Co-authored-by: Serhiy Storchaka --- Lib/tkinter/test/test_tkinter/test_widgets.py | 3 --- Lib/tkinter/test/widget_tests.py | 3 --- 2 files changed, 6 deletions(-) diff --git a/Lib/tkinter/test/test_tkinter/test_widgets.py b/Lib/tkinter/test/test_tkinter/test_widgets.py index b6f792d6c2cf85..4b9b6ebdda04ea 100644 --- a/Lib/tkinter/test/test_tkinter/test_widgets.py +++ b/Lib/tkinter/test/test_tkinter/test_widgets.py @@ -2,7 +2,6 @@ import tkinter from tkinter import TclError import os -import sys from test.support import requires from tkinter.test.support import (tcl_version, requires_tcl, @@ -265,8 +264,6 @@ def test_height(self): test_highlightthickness = StandardOptionsTests.test_highlightthickness - @unittest.skipIf(sys.platform == 'darwin', - 'crashes with Cocoa Tk (issue19733)') def test_image(self): widget = self.create() image = tkinter.PhotoImage(master=self.root, name='image1') diff --git a/Lib/tkinter/test/widget_tests.py b/Lib/tkinter/test/widget_tests.py index b42ff52178f29e..ad4a8bd2bf3252 100644 --- a/Lib/tkinter/test/widget_tests.py +++ b/Lib/tkinter/test/widget_tests.py @@ -1,7 +1,6 @@ # Common tests for test_tkinter/test_widgets.py and test_ttk/test_widgets.py import unittest -import sys import tkinter from tkinter.test.support import (AbstractTkTest, tcl_version, requires_tcl, get_tk_patchlevel, pixels_conv, tcl_obj_eq) @@ -332,8 +331,6 @@ def test_highlightthickness(self): self.checkParam(widget, 'highlightthickness', -2, expected=0, conv=self._conv_pixels) - @unittest.skipIf(sys.platform == 'darwin', - 'crashes with Cocoa Tk (issue19733)') def test_image(self): widget = self.create() self.checkImageParam(widget, 'image') From 7492b55ea0ca993c353b6373341b92e40faa9c4d Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 16 Dec 2020 08:33:05 -0800 Subject: [PATCH 0806/1314] bpo-40686: Fix compiler warnings on _zoneinfo.c (GH-23614) (GH-23804) "uint8_t day" is unsigned and so "day < 0" test is always true. Remove the test to fix the following warnings on Windows: modules\_zoneinfo.c(1224): warning C4068: unknown pragma modules\_zoneinfo.c(1225): warning C4068: unknown pragma modules\_zoneinfo.c(1227): warning C4068: unknown pragma (cherry picked from commit aefb69b23f056c61e82ad228d950f348de090c70) Co-authored-by: Victor Stinner Co-authored-by: Victor Stinner --- Modules/_zoneinfo.c | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/Modules/_zoneinfo.c b/Modules/_zoneinfo.c index 2cee65fac6dd04..fafb6b01df3712 100644 --- a/Modules/_zoneinfo.c +++ b/Modules/_zoneinfo.c @@ -171,7 +171,7 @@ static void update_strong_cache(const PyTypeObject *const type, PyObject *key, PyObject *zone); static PyObject * -zone_from_strong_cache(const PyTypeObject *const type, PyObject *key); +zone_from_strong_cache(const PyTypeObject *const type, PyObject *const key); static PyObject * zoneinfo_new_instance(PyTypeObject *type, PyObject *key) @@ -1219,15 +1219,9 @@ calendarrule_new(uint8_t month, uint8_t week, uint8_t day, int8_t hour, return -1; } - // day is an unsigned integer, so day < 0 should always return false, but - // if day's type changes to a signed integer *without* changing this value, - // it may create a bug. Considering that the compiler should be able to - // optimize out the first comparison if day is an unsigned integer anyway, - // we will leave this comparison in place and disable the compiler warning. -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wtype-limits" - if (day < 0 || day > 6) { -#pragma GCC diagnostic pop + // If the 'day' parameter type is changed to a signed type, + // "day < 0" check must be added. + if (/* day < 0 || */ day > 6) { PyErr_Format(PyExc_ValueError, "Day must be in [0, 6]"); return -1; } From 9d409d6b474c188feca6213b9601e06f97715b72 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 16 Dec 2020 09:56:10 -0800 Subject: [PATCH 0807/1314] bpo-39101: Fixes BaseException hang in IsolatedAsyncioTestCase. (GH-22654) (cherry picked from commit 8374d2ee1589791be8892b00f4bbf8121dde24bd) Co-authored-by: Lisa Roach --- Lib/unittest/async_case.py | 4 +-- Lib/unittest/test/test_async_case.py | 27 +++++++++++++++++++ .../2020-10-11-21-43-03.bpo-39101.-I49Pm.rst | 1 + 3 files changed, 30 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2020-10-11-21-43-03.bpo-39101.-I49Pm.rst diff --git a/Lib/unittest/async_case.py b/Lib/unittest/async_case.py index 1bc1312c8c2ee9..520213c3727555 100644 --- a/Lib/unittest/async_case.py +++ b/Lib/unittest/async_case.py @@ -102,9 +102,9 @@ async def _asyncioLoopRunner(self, fut): ret = await awaitable if not fut.cancelled(): fut.set_result(ret) - except asyncio.CancelledError: + except (SystemExit, KeyboardInterrupt): raise - except Exception as ex: + except (BaseException, asyncio.CancelledError) as ex: if not fut.cancelled(): fut.set_exception(ex) diff --git a/Lib/unittest/test/test_async_case.py b/Lib/unittest/test/test_async_case.py index 2db441da202a01..d01864b6936ca8 100644 --- a/Lib/unittest/test/test_async_case.py +++ b/Lib/unittest/test/test_async_case.py @@ -190,6 +190,33 @@ async def on_async_cleanup(self, val): 'async_cleanup 2', 'sync_cleanup 1']) + def test_base_exception_from_async_method(self): + events = [] + class Test(unittest.IsolatedAsyncioTestCase): + async def test_base(self): + events.append("test_base") + raise BaseException() + events.append("not it") + + async def test_no_err(self): + events.append("test_no_err") + + async def test_cancel(self): + raise asyncio.CancelledError() + + test = Test("test_base") + output = test.run() + self.assertFalse(output.wasSuccessful()) + + test = Test("test_no_err") + test.run() + self.assertEqual(events, ['test_base', 'test_no_err']) + + test = Test("test_cancel") + output = test.run() + self.assertFalse(output.wasSuccessful()) + + if __name__ == "__main__": unittest.main() diff --git a/Misc/NEWS.d/next/Library/2020-10-11-21-43-03.bpo-39101.-I49Pm.rst b/Misc/NEWS.d/next/Library/2020-10-11-21-43-03.bpo-39101.-I49Pm.rst new file mode 100644 index 00000000000000..a571e8343cde12 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2020-10-11-21-43-03.bpo-39101.-I49Pm.rst @@ -0,0 +1 @@ +Fixed tests using IsolatedAsyncioTestCase from hanging on BaseExceptions. \ No newline at end of file From bf0eed3e60acc7e4969a4fae940bc615fa924c30 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 16 Dec 2020 10:10:37 -0800 Subject: [PATCH 0808/1314] bpo-38323: Add guard clauses in MultiLoopChildWatcher. (GH-22756) This is a trivial refactor in preparation for a fix for bpo-38323. (cherry picked from commit 66d3b589c44fcbcf9afe1e442d9beac3bd8bcd34) Co-authored-by: Chris Jerdonek --- Lib/asyncio/unix_events.py | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/Lib/asyncio/unix_events.py b/Lib/asyncio/unix_events.py index f34a5b4b443736..3efa6698b89ced 100644 --- a/Lib/asyncio/unix_events.py +++ b/Lib/asyncio/unix_events.py @@ -1230,13 +1230,15 @@ def is_active(self): def close(self): self._callbacks.clear() - if self._saved_sighandler is not None: - handler = signal.getsignal(signal.SIGCHLD) - if handler != self._sig_chld: - logger.warning("SIGCHLD handler was changed by outside code") - else: - signal.signal(signal.SIGCHLD, self._saved_sighandler) - self._saved_sighandler = None + if self._saved_sighandler is None: + return + + handler = signal.getsignal(signal.SIGCHLD) + if handler != self._sig_chld: + logger.warning("SIGCHLD handler was changed by outside code") + else: + signal.signal(signal.SIGCHLD, self._saved_sighandler) + self._saved_sighandler = None def __enter__(self): return self @@ -1263,15 +1265,17 @@ def attach_loop(self, loop): # The reason to do it here is that attach_loop() is called from # unix policy only for the main thread. # Main thread is required for subscription on SIGCHLD signal + if self._saved_sighandler is not None: + return + + self._saved_sighandler = signal.signal(signal.SIGCHLD, self._sig_chld) if self._saved_sighandler is None: - self._saved_sighandler = signal.signal(signal.SIGCHLD, self._sig_chld) - if self._saved_sighandler is None: - logger.warning("Previous SIGCHLD handler was set by non-Python code, " - "restore to default handler on watcher close.") - self._saved_sighandler = signal.SIG_DFL + logger.warning("Previous SIGCHLD handler was set by non-Python code, " + "restore to default handler on watcher close.") + self._saved_sighandler = signal.SIG_DFL - # Set SA_RESTART to limit EINTR occurrences. - signal.siginterrupt(signal.SIGCHLD, False) + # Set SA_RESTART to limit EINTR occurrences. + signal.siginterrupt(signal.SIGCHLD, False) def _do_waitpid_all(self): for pid in list(self._callbacks): From 166286849048eccadecf02b242dbc4042b780944 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Wed, 16 Dec 2020 22:41:47 +0100 Subject: [PATCH 0809/1314] Add symbols of the stable ABI to python3dll.c (GH-23598) (GH-23801) Add the following symbols to python3dll.c: * PyFrame_GetCode (bpo-40421) * PyFrame_GetLineNumber (bpo-40421) * PyObject_CallNoArgs (bpo-37194) * PyThreadState_GetFrame (bpo-39947) * PyThreadState_GetID (bpo-39947) * PyThreadState_GetInterpreter (bpo-39947) (cherry picked from commit fcc6935384b933fbe1a1ef659ed455a3b74c849a) --- PC/python3.def | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/PC/python3.def b/PC/python3.def index 66d1595c943ed8..fce01249758e29 100644 --- a/PC/python3.def +++ b/PC/python3.def @@ -266,6 +266,8 @@ EXPORTS PyFloat_GetMax=python39.PyFloat_GetMax PyFloat_GetMin=python39.PyFloat_GetMin PyFloat_Type=python39.PyFloat_Type DATA + PyFrame_GetCode=python39.PyFrame_GetCode + PyFrame_GetLineNumber=python39.PyFrame_GetLineNumber PyFrozenSet_New=python39.PyFrozenSet_New PyFrozenSet_Type=python39.PyFrozenSet_Type DATA PyGC_Collect=python39.PyGC_Collect @@ -453,6 +455,7 @@ EXPORTS PyObject_CallFunctionObjArgs=python39.PyObject_CallFunctionObjArgs PyObject_CallMethod=python39.PyObject_CallMethod PyObject_CallMethodObjArgs=python39.PyObject_CallMethodObjArgs + PyObject_CallNoArgs=python39.PyObject_CallNoArgs PyObject_CallObject=python39.PyObject_CallObject PyObject_Calloc=python39.PyObject_Calloc PyObject_CheckReadBuffer=python39.PyObject_CheckReadBuffer @@ -569,6 +572,9 @@ EXPORTS PyThreadState_DeleteCurrent=python39.PyThreadState_DeleteCurrent PyThreadState_Get=python39.PyThreadState_Get PyThreadState_GetDict=python39.PyThreadState_GetDict + PyThreadState_GetFrame=python39.PyThreadState_GetFrame + PyThreadState_GetID=python39.PyThreadState_GetID + PyThreadState_GetInterpreter=python39.PyThreadState_GetInterpreter PyThreadState_New=python39.PyThreadState_New PyThreadState_SetAsyncExc=python39.PyThreadState_SetAsyncExc PyThreadState_Swap=python39.PyThreadState_Swap From 78062e07bc7c3b47ffdcdec786b259dda376370c Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 16 Dec 2020 14:01:14 -0800 Subject: [PATCH 0810/1314] bpo-37961: Fix regression in tracemalloc.Traceback.__repr__ (GH-23805) Regression in 8d59eb1b66c51b2b918da9881c57d07d08df43b7. (cherry picked from commit 051b9818671625d125dee8198e0d2af5ad4c85b8) Co-authored-by: Daniel Hahler --- Lib/test/test_tracemalloc.py | 20 +++++++++++++++++++ Lib/tracemalloc.py | 2 +- .../2020-12-16-16-16-33.bpo-37961.jrESEq.rst | 1 + 3 files changed, 22 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Library/2020-12-16-16-16-33.bpo-37961.jrESEq.rst diff --git a/Lib/test/test_tracemalloc.py b/Lib/test/test_tracemalloc.py index c5ae4e6d653bf7..b10d1798c29777 100644 --- a/Lib/test/test_tracemalloc.py +++ b/Lib/test/test_tracemalloc.py @@ -84,6 +84,25 @@ def traceback_filename(filename): return traceback_lineno(filename, 0) +class TestTraceback(unittest.TestCase): + def test_repr(self): + def get_repr(*args) -> str: + return repr(tracemalloc.Traceback(*args)) + + self.assertEqual(get_repr(()), "") + self.assertEqual(get_repr((), 0), "") + + frames = (("f1", 1), ("f2", 2)) + exp_repr_frames = ( + "(," + " )" + ) + self.assertEqual(get_repr(frames), + f"") + self.assertEqual(get_repr(frames, 2), + f"") + + class TestTracemallocEnabled(unittest.TestCase): def setUp(self): if tracemalloc.is_tracing(): @@ -1064,6 +1083,7 @@ def test_stop_untrack(self): def test_main(): support.run_unittest( + TestTraceback, TestTracemallocEnabled, TestSnapshot, TestFilters, diff --git a/Lib/tracemalloc.py b/Lib/tracemalloc.py index 69b4170ec82462..cec99c59700fe0 100644 --- a/Lib/tracemalloc.py +++ b/Lib/tracemalloc.py @@ -226,7 +226,7 @@ def __str__(self): return str(self[0]) def __repr__(self): - s = " Date: Wed, 16 Dec 2020 15:18:39 -0800 Subject: [PATCH 0811/1314] Fix indentation for get_stats_profile() docs (GH-23618) The existing method is indented one too many times which makes it look like a sub-method of print_callees(). (cherry picked from commit a6ba2b901543f3006ecdb2ad8b18cb00439ff9b2) Co-authored-by: Matthew Suozzo --- Doc/library/profile.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/profile.rst b/Doc/library/profile.rst index 34525a96f55c43..7edabfde0d7f18 100644 --- a/Doc/library/profile.rst +++ b/Doc/library/profile.rst @@ -525,7 +525,7 @@ Analysis of the profiler data is done using the :class:`~pstats.Stats` class. ordering are identical to the :meth:`~pstats.Stats.print_callers` method. - .. method:: get_stats_profile() + .. method:: get_stats_profile() This method returns an instance of StatsProfile, which contains a mapping of function names to instances of FunctionProfile. Each FunctionProfile From e962e3ad225a211b9f9689742db6e9771d07c505 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 17 Dec 2020 00:03:50 -0800 Subject: [PATCH 0812/1314] bpo-41804: Enhance test_epoll.test_control_and_wait() (GH-23795) Use shorter timeout and replace send() with sendall(). (cherry picked from commit 79782fe4f8cf73d7fdf8db02073bbadf7ff817b6) Co-authored-by: Victor Stinner --- Lib/test/test_epoll.py | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/Lib/test/test_epoll.py b/Lib/test/test_epoll.py index 10f148fe5cdb41..b623852f9eb4ee 100644 --- a/Lib/test/test_epoll.py +++ b/Lib/test/test_epoll.py @@ -160,44 +160,42 @@ def test_fromfd(self): self.fail("epoll on closed fd didn't raise EBADF") def test_control_and_wait(self): + # create the epoll object client, server = self._connected_pair() - ep = select.epoll(16) ep.register(server.fileno(), select.EPOLLIN | select.EPOLLOUT | select.EPOLLET) ep.register(client.fileno(), select.EPOLLIN | select.EPOLLOUT | select.EPOLLET) + # EPOLLOUT now = time.monotonic() events = ep.poll(1, 4) then = time.monotonic() self.assertFalse(then - now > 0.1, then - now) - events.sort() expected = [(client.fileno(), select.EPOLLOUT), (server.fileno(), select.EPOLLOUT)] - expected.sort() - - self.assertEqual(events, expected) + self.assertEqual(sorted(events), sorted(expected)) - events = ep.poll(timeout=2.1, maxevents=4) + # no event + events = ep.poll(timeout=0.1, maxevents=4) self.assertFalse(events) - client.send(b"Hello!") - server.send(b"world!!!") + # send: EPOLLIN and EPOLLOUT + client.sendall(b"Hello!") + server.sendall(b"world!!!") now = time.monotonic() - events = ep.poll(1, 4) + events = ep.poll(1.0, 4) then = time.monotonic() self.assertFalse(then - now > 0.01) - events.sort() expected = [(client.fileno(), select.EPOLLIN | select.EPOLLOUT), (server.fileno(), select.EPOLLIN | select.EPOLLOUT)] - expected.sort() - - self.assertEqual(events, expected) + self.assertEqual(sorted(events), sorted(expected)) + # unregister, modify ep.unregister(client.fileno()) ep.modify(server.fileno(), select.EPOLLOUT) now = time.monotonic() From 8d0a01c99b2a810bfe13d654b294c25a10151aa4 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 17 Dec 2020 03:15:20 -0800 Subject: [PATCH 0813/1314] bpo-42375: subprocess DragonFlyBSD build update. (GH-23320) (GH-23388) Same as FreeBSD, file descriptors in /dev/fd id from 0 to 63. (cherry picked from commit 13b865f0e17c88b081c23f7f05cf91166d220a50) Co-authored-by: David CARLIER Co-authored-by: David CARLIER --- .../next/Library/2020-11-19-04-13-53.bpo-42375.U8bp4s.rst | 1 + Modules/_posixsubprocess.c | 8 ++++---- 2 files changed, 5 insertions(+), 4 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2020-11-19-04-13-53.bpo-42375.U8bp4s.rst diff --git a/Misc/NEWS.d/next/Library/2020-11-19-04-13-53.bpo-42375.U8bp4s.rst b/Misc/NEWS.d/next/Library/2020-11-19-04-13-53.bpo-42375.U8bp4s.rst new file mode 100644 index 00000000000000..6d8c80c2f2c0ae --- /dev/null +++ b/Misc/NEWS.d/next/Library/2020-11-19-04-13-53.bpo-42375.U8bp4s.rst @@ -0,0 +1 @@ +subprocess module update for DragonFlyBSD support. \ No newline at end of file diff --git a/Modules/_posixsubprocess.c b/Modules/_posixsubprocess.c index 5356417dd7037f..c266fd1ec1756a 100644 --- a/Modules/_posixsubprocess.c +++ b/Modules/_posixsubprocess.c @@ -46,7 +46,7 @@ # endif #endif -#if defined(__FreeBSD__) || (defined(__APPLE__) && defined(__MACH__)) +#if defined(__FreeBSD__) || (defined(__APPLE__) && defined(__MACH__)) || defined(__DragonFly__) # define FD_DIR "/dev/fd" #else # define FD_DIR "/proc/self/fd" @@ -116,9 +116,9 @@ _pos_int_from_ascii(const char *name) } -#if defined(__FreeBSD__) +#if defined(__FreeBSD__) || defined(__DragonFly__) /* When /dev/fd isn't mounted it is often a static directory populated - * with 0 1 2 or entries for 0 .. 63 on FreeBSD, NetBSD and OpenBSD. + * with 0 1 2 or entries for 0 .. 63 on FreeBSD, NetBSD, OpenBSD and DragonFlyBSD. * NetBSD and OpenBSD have a /proc fs available (though not necessarily * mounted) and do not have fdescfs for /dev/fd. MacOS X has a devfs * that properly supports /dev/fd. @@ -377,7 +377,7 @@ _close_open_fds_maybe_unsafe(long start_fd, PyObject* py_fds_to_keep) ++start_fd; #endif -#if defined(__FreeBSD__) +#if defined(__FreeBSD__) || defined(__DragonFly__) if (!_is_fdescfs_mounted_on_dev_fd()) proc_fd_dir = NULL; else From 1c70d40e94741578ce28b8851fb65372ac2e7942 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 17 Dec 2020 05:19:58 -0800 Subject: [PATCH 0814/1314] bpo-26564: fix obsolete comment in traceback.c (GH-23819) (cherry picked from commit 40125ab3252453bf205ed906e46bf9741c27bf9d) Co-authored-by: Irit Katriel --- Python/traceback.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Python/traceback.c b/Python/traceback.c index 99b63af11f8bee..5d3a65cc160e04 100644 --- a/Python/traceback.c +++ b/Python/traceback.c @@ -622,7 +622,8 @@ PyTraceBack_Print(PyObject *v, PyObject *f) return err; } -/* Reverse a string. For example, "abcd" becomes "dcba". +/* Format an integer in range [0; 0xffffffff] to decimal and write it + into the file fd. This function is signal safe. */ From 79c535796da4a1377364910e309b97e53c3e51ef Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 17 Dec 2020 06:29:36 -0800 Subject: [PATCH 0815/1314] bpo-42613: Fix freeze.py config directory (GH-23792) (GH-23817) Fix freeze.py tool to use the prope config and library directories. (cherry picked from commit 1c653f17cb84d81df3a74ab0b42140d2bb68c5c4) Co-authored-by: Victor Stinner Co-authored-by: Victor Stinner --- .../2020-12-16-09-10-32.bpo-42613.J-jnm5.rst | 2 ++ Tools/freeze/freeze.py | 20 +++++++++---------- 2 files changed, 12 insertions(+), 10 deletions(-) create mode 100644 Misc/NEWS.d/next/Tools-Demos/2020-12-16-09-10-32.bpo-42613.J-jnm5.rst diff --git a/Misc/NEWS.d/next/Tools-Demos/2020-12-16-09-10-32.bpo-42613.J-jnm5.rst b/Misc/NEWS.d/next/Tools-Demos/2020-12-16-09-10-32.bpo-42613.J-jnm5.rst new file mode 100644 index 00000000000000..140ff8255b96b1 --- /dev/null +++ b/Misc/NEWS.d/next/Tools-Demos/2020-12-16-09-10-32.bpo-42613.J-jnm5.rst @@ -0,0 +1,2 @@ +Fix ``freeze.py`` tool to use the prope config and library directories. +Patch by Victor Stinner. diff --git a/Tools/freeze/freeze.py b/Tools/freeze/freeze.py index 83aa508a46a93e..d66e1e2708e758 100755 --- a/Tools/freeze/freeze.py +++ b/Tools/freeze/freeze.py @@ -93,6 +93,7 @@ import getopt import os import sys +import sysconfig # Import the freeze-private modules @@ -226,7 +227,7 @@ def main(): extensions_c = 'frozen_extensions.c' if ishome: print("(Using Python source directory)") - binlib = exec_prefix + configdir = exec_prefix incldir = os.path.join(prefix, 'Include') config_h_dir = exec_prefix config_c_in = os.path.join(prefix, 'Modules', 'config.c.in') @@ -235,22 +236,21 @@ def main(): if win: frozendllmain_c = os.path.join(exec_prefix, 'Pc\\frozen_dllmain.c') else: - binlib = os.path.join(exec_prefix, - 'lib', 'python%s' % version, - 'config-%s' % flagged_version) + configdir = sysconfig.get_config_var('LIBPL') incldir = os.path.join(prefix, 'include', 'python%s' % flagged_version) config_h_dir = os.path.join(exec_prefix, 'include', 'python%s' % flagged_version) - config_c_in = os.path.join(binlib, 'config.c.in') - frozenmain_c = os.path.join(binlib, 'frozenmain.c') - makefile_in = os.path.join(binlib, 'Makefile') - frozendllmain_c = os.path.join(binlib, 'frozen_dllmain.c') + config_c_in = os.path.join(configdir, 'config.c.in') + frozenmain_c = os.path.join(configdir, 'frozenmain.c') + makefile_in = os.path.join(configdir, 'Makefile') + frozendllmain_c = os.path.join(configdir, 'frozen_dllmain.c') + libdir = sysconfig.get_config_var('LIBDIR') supp_sources = [] defines = [] includes = ['-I' + incldir, '-I' + config_h_dir] # sanity check of directories and files - check_dirs = [prefix, exec_prefix, binlib, incldir] + check_dirs = [prefix, exec_prefix, configdir, incldir] if not win: # These are not directories on Windows. check_dirs = check_dirs + extensions @@ -457,7 +457,7 @@ def main(): cflags = ['$(OPT)'] cppflags = defines + includes - libs = [os.path.join(binlib, '$(LDLIBRARY)')] + libs = [os.path.join(libdir, '$(LDLIBRARY)')] somevars = {} if os.path.exists(makefile_in): From b812e236df506603e592086269e088b00d021460 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 18 Dec 2020 01:49:19 -0800 Subject: [PATCH 0816/1314] bpo-39096: Format specification documentation fixes for numeric types (GH-23575) (cherry picked from commit 886b2e5c7a2caf87070728dba8f18c3d65e51071) Co-authored-by: Mark Dickinson --- Doc/library/string.rst | 35 +++++++++++++++++++++++------------ 1 file changed, 23 insertions(+), 12 deletions(-) diff --git a/Doc/library/string.rst b/Doc/library/string.rst index 5542e9b727a6b8..54786d0c2ab0df 100644 --- a/Doc/library/string.rst +++ b/Doc/library/string.rst @@ -514,6 +514,8 @@ The available presentation types for :class:`float` and | | this rounds the number to ``p`` significant digits and | | | then formats the result in either fixed-point format | | | or in scientific notation, depending on its magnitude. | + | | A precision of ``0`` is treated as equivalent to a | + | | precision of ``1``. | | | | | | The precise rules are as follows: suppose that the | | | result formatted with presentation type ``'e'`` and | @@ -528,16 +530,19 @@ The available presentation types for :class:`float` and | | removed if there are no remaining digits following it, | | | unless the ``'#'`` option is used. | | | | + | | With no precision given, uses a precision of ``6`` | + | | significant digits for :class:`float`. For | + | | :class:`~decimal.Decimal`, the coefficient of the result | + | | is formed from the coefficient digits of the value; | + | | scientific notation is used for values smaller than | + | | ``1e-6`` in absolute value and values where the place | + | | value of the least significant digit is larger than 1, | + | | and fixed-point notation is used otherwise. | + | | | | | Positive and negative infinity, positive and negative | | | zero, and nans, are formatted as ``inf``, ``-inf``, | | | ``0``, ``-0`` and ``nan`` respectively, regardless of | | | the precision. | - | | | - | | A precision of ``0`` is treated as equivalent to a | - | | precision of ``1``. With no precision given, uses a | - | | precision of ``6`` significant digits for | - | | :class:`float`, and shows all coefficient digits | - | | for :class:`~decimal.Decimal`. | +---------+----------------------------------------------------------+ | ``'G'`` | General format. Same as ``'g'`` except switches to | | | ``'E'`` if the number gets too large. The | @@ -550,12 +555,18 @@ The available presentation types for :class:`float` and | ``'%'`` | Percentage. Multiplies the number by 100 and displays | | | in fixed (``'f'``) format, followed by a percent sign. | +---------+----------------------------------------------------------+ - | None | Similar to ``'g'``, except that fixed-point notation, | - | | when used, has at least one digit past the decimal point.| - | | The default precision is as high as needed to represent | - | | the particular value. The overall effect is to match the | - | | output of :func:`str` as altered by the other format | - | | modifiers. | + | None | For :class:`float` this is the same as ``'g'``, except | + | | that when fixed-point notation is used to format the | + | | result, it always includes at least one digit past the | + | | decimal point. The precision used is as large as needed | + | | to represent the given value faithfully. | + | | | + | | For :class:`~decimal.Decimal`, this is the same as | + | | either ``'g'`` or ``'G'`` depending on the value of | + | | ``context.capitals`` for the current decimal context. | + | | | + | | The overall effect is to match the output of :func:`str` | + | | as altered by the other format modifiers. | +---------+----------------------------------------------------------+ From 14619924c36435e356135988c244cbc28652c82b Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 18 Dec 2020 05:27:02 -0800 Subject: [PATCH 0817/1314] bpo-17140: Document multiprocessing's ThreadPool (GH-23812) Up until now, the `multiprocessing.pool.ThreadPool` class has gone undocumented, despite being a public class in multiprocessing that is included in `multiprocessing.pool.__all__`. (cherry picked from commit 84ebcf271a2cc8bfd1762acb279502b8b6ef236e) Co-authored-by: Matt Wozniski --- Doc/library/multiprocessing.rst | 40 +++++++++++++++++++ .../2020-12-16-21-06-16.bpo-17140.1leSEg.rst | 1 + 2 files changed, 41 insertions(+) create mode 100644 Misc/NEWS.d/next/Documentation/2020-12-16-21-06-16.bpo-17140.1leSEg.rst diff --git a/Doc/library/multiprocessing.rst b/Doc/library/multiprocessing.rst index ab84d39ed05163..352f48f513df99 100644 --- a/Doc/library/multiprocessing.rst +++ b/Doc/library/multiprocessing.rst @@ -2661,6 +2661,46 @@ The :mod:`multiprocessing.dummy` module :mod:`multiprocessing.dummy` replicates the API of :mod:`multiprocessing` but is no more than a wrapper around the :mod:`threading` module. +.. currentmodule:: multiprocessing.pool + +In particular, the ``Pool`` function provided by :mod:`multiprocessing.dummy` +returns an instance of :class:`ThreadPool`, which is a subclass of +:class:`Pool` that supports all the same method calls but uses a pool of +worker threads rather than worker processes. + + +.. class:: ThreadPool([processes[, initializer[, initargs]]]) + + A thread pool object which controls a pool of worker threads to which jobs + can be submitted. :class:`ThreadPool` instances are fully interface + compatible with :class:`Pool` instances, and their resources must also be + properly managed, either by using the pool as a context manager or by + calling :meth:`~multiprocessing.pool.Pool.close` and + :meth:`~multiprocessing.pool.Pool.terminate` manually. + + *processes* is the number of worker threads to use. If *processes* is + ``None`` then the number returned by :func:`os.cpu_count` is used. + + If *initializer* is not ``None`` then each worker process will call + ``initializer(*initargs)`` when it starts. + + Unlike :class:`Pool`, *maxtasksperchild* and *context* cannot be provided. + + .. note:: + + A :class:`ThreadPool` shares the same interface as :class:`Pool`, which + is designed around a pool of processes and predates the introduction of + the :class:`concurrent.futures` module. As such, it inherits some + operations that don't make sense for a pool backed by threads, and it + has its own type for representing the status of asynchronous jobs, + :class:`AsyncResult`, that is not understood by any other libraries. + + Users should generally prefer to use + :class:`concurrent.futures.ThreadPoolExecutor`, which has a simpler + interface that was designed around threads from the start, and which + returns :class:`concurrent.futures.Future` instances that are + compatible with many other libraries, including :mod:`asyncio`. + .. _multiprocessing-programming: diff --git a/Misc/NEWS.d/next/Documentation/2020-12-16-21-06-16.bpo-17140.1leSEg.rst b/Misc/NEWS.d/next/Documentation/2020-12-16-21-06-16.bpo-17140.1leSEg.rst new file mode 100644 index 00000000000000..cb1fd23a56e639 --- /dev/null +++ b/Misc/NEWS.d/next/Documentation/2020-12-16-21-06-16.bpo-17140.1leSEg.rst @@ -0,0 +1 @@ +Add documentation for the :class:`multiprocessing.pool.ThreadPool` class. From 82dbfd5a04863d8b6363527e6a34a90c9aa5691b Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 18 Dec 2020 11:19:10 -0800 Subject: [PATCH 0818/1314] bpo-41891: ensure asyncio.wait_for waits for task completion (GH-22461) (#23840) (cherry picked from commit 17ef4319a34f5a2f95e7823dfb5f5b8cff11882d) Co-authored-by: Richard Kojedzinszky Co-authored-by: Richard Kojedzinszky --- Lib/asyncio/tasks.py | 5 +- Lib/test/test_asyncio/test_asyncio_waitfor.py | 61 +++++++++++++++++++ .../2020-09-30-13-35-29.bpo-41891.pNAeYI.rst | 1 + 3 files changed, 66 insertions(+), 1 deletion(-) create mode 100644 Lib/test/test_asyncio/test_asyncio_waitfor.py create mode 100644 Misc/NEWS.d/next/Library/2020-09-30-13-35-29.bpo-41891.pNAeYI.rst diff --git a/Lib/asyncio/tasks.py b/Lib/asyncio/tasks.py index f486b672294111..d6262ae75e6569 100644 --- a/Lib/asyncio/tasks.py +++ b/Lib/asyncio/tasks.py @@ -471,7 +471,10 @@ async def wait_for(fut, timeout, *, loop=None): return fut.result() else: fut.remove_done_callback(cb) - fut.cancel() + # We must ensure that the task is not running + # after wait_for() returns. + # See https://bugs.python.org/issue32751 + await _cancel_and_wait(fut, loop=loop) raise if fut.done(): diff --git a/Lib/test/test_asyncio/test_asyncio_waitfor.py b/Lib/test/test_asyncio/test_asyncio_waitfor.py new file mode 100644 index 00000000000000..2ca64abbeb527c --- /dev/null +++ b/Lib/test/test_asyncio/test_asyncio_waitfor.py @@ -0,0 +1,61 @@ +import asyncio +import unittest +import time + +def tearDownModule(): + asyncio.set_event_loop_policy(None) + + +class SlowTask: + """ Task will run for this defined time, ignoring cancel requests """ + TASK_TIMEOUT = 0.2 + + def __init__(self): + self.exited = False + + async def run(self): + exitat = time.monotonic() + self.TASK_TIMEOUT + + while True: + tosleep = exitat - time.monotonic() + if tosleep <= 0: + break + + try: + await asyncio.sleep(tosleep) + except asyncio.CancelledError: + pass + + self.exited = True + +class AsyncioWaitForTest(unittest.TestCase): + + async def atest_asyncio_wait_for_cancelled(self): + t = SlowTask() + + waitfortask = asyncio.create_task(asyncio.wait_for(t.run(), t.TASK_TIMEOUT * 2)) + await asyncio.sleep(0) + waitfortask.cancel() + await asyncio.wait({waitfortask}) + + self.assertTrue(t.exited) + + def test_asyncio_wait_for_cancelled(self): + asyncio.run(self.atest_asyncio_wait_for_cancelled()) + + async def atest_asyncio_wait_for_timeout(self): + t = SlowTask() + + try: + await asyncio.wait_for(t.run(), t.TASK_TIMEOUT / 2) + except asyncio.TimeoutError: + pass + + self.assertTrue(t.exited) + + def test_asyncio_wait_for_timeout(self): + asyncio.run(self.atest_asyncio_wait_for_timeout()) + + +if __name__ == '__main__': + unittest.main() diff --git a/Misc/NEWS.d/next/Library/2020-09-30-13-35-29.bpo-41891.pNAeYI.rst b/Misc/NEWS.d/next/Library/2020-09-30-13-35-29.bpo-41891.pNAeYI.rst new file mode 100644 index 00000000000000..75c25127803153 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2020-09-30-13-35-29.bpo-41891.pNAeYI.rst @@ -0,0 +1 @@ +Ensure asyncio.wait_for waits for task completion From 4b412e830d0a7d3f30af60b9eb285558511d90af Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 18 Dec 2020 11:34:27 -0800 Subject: [PATCH 0819/1314] bpo-36769: Document that fnmatch.filter supports any kind of iterable (GH-13039) (cherry picked from commit e8d22642105d57007ab1242848a8cbadc7f179df) Co-authored-by: Andre Delfino --- Doc/library/fnmatch.rst | 2 +- Lib/fnmatch.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/library/fnmatch.rst b/Doc/library/fnmatch.rst index ce07d326b395d8..925f08e914685e 100644 --- a/Doc/library/fnmatch.rst +++ b/Doc/library/fnmatch.rst @@ -75,7 +75,7 @@ patterns. .. function:: filter(names, pattern) - Return the subset of the list of *names* that match *pattern*. It is the same as + Construct a list from those elements of the iterable *names* that match *pattern*. It is the same as ``[n for n in names if fnmatch(n, pattern)]``, but implemented more efficiently. diff --git a/Lib/fnmatch.py b/Lib/fnmatch.py index 0eb1802bdb53c5..7c52c23067d40f 100644 --- a/Lib/fnmatch.py +++ b/Lib/fnmatch.py @@ -52,7 +52,7 @@ def _compile_pattern(pat): return re.compile(res).match def filter(names, pat): - """Return the subset of the list NAMES that match PAT.""" + """Construct a list from those elements of the iterable NAMES that match PAT.""" result = [] pat = os.path.normcase(pat) match = _compile_pattern(pat) From eef33e6d49d05aad4111da4ad2d9cb34e7a5206c Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 18 Dec 2020 16:55:52 -0800 Subject: [PATCH 0820/1314] bpo-42670: Fix a missing word in the itertools.product() docs (GH-23823) (GH-23824) --- Doc/library/itertools.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/itertools.rst b/Doc/library/itertools.rst index 3de66c93492815..85f4928ce84fbe 100644 --- a/Doc/library/itertools.rst +++ b/Doc/library/itertools.rst @@ -565,7 +565,7 @@ loops that truncate the stream. Before :func:`product` runs, it completely consumes the input iterables, keeping pools of values in memory to generate the products. Accordingly, - it only useful with finite inputs. + it is only useful with finite inputs. .. function:: repeat(object[, times]) From 782665885c983e88aac12f7e082485cac2df8007 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 18 Dec 2020 17:17:32 -0800 Subject: [PATCH 0821/1314] bpo-34805: Guarantee that __subclasses__() is in definition order. (GH-23844) (GH-23850) --- Doc/library/stdtypes.rst | 4 ++-- Lib/test/test_descr.py | 10 ++++++++++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst index a48cfa13277910..59200730a48f5d 100644 --- a/Doc/library/stdtypes.rst +++ b/Doc/library/stdtypes.rst @@ -5196,8 +5196,8 @@ types, where they are relevant. Some of these are not reported by the .. method:: class.__subclasses__ Each class keeps a list of weak references to its immediate subclasses. This - method returns a list of all those references still alive. - Example:: + method returns a list of all those references still alive. The list is in + definition order. Example:: >>> int.__subclasses__() [] diff --git a/Lib/test/test_descr.py b/Lib/test/test_descr.py index 9e875da3750838..c7a191bccd69c4 100644 --- a/Lib/test/test_descr.py +++ b/Lib/test/test_descr.py @@ -4,6 +4,8 @@ import itertools import math import pickle +import random +import string import sys import types import unittest @@ -845,6 +847,14 @@ class Module(types.ModuleType, str): self.fail("inheriting from ModuleType and str at the same time " "should fail") + # Issue 34805: Verify that definition order is retained + def random_name(): + return ''.join(random.choices(string.ascii_letters, k=10)) + class A: + pass + subclasses = [type(random_name(), (A,), {}) for i in range(100)] + self.assertEqual(A.__subclasses__(), subclasses) + def test_multiple_inheritance(self): # Testing multiple inheritance... class C(object): From d458d8dab0abaf781c923f80f8eb832d0c683e88 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 18 Dec 2020 19:10:06 -0800 Subject: [PATCH 0822/1314] bpo-42559: Not that getrandbits() is non-negative. (GH-23843) (GH-23851) --- Doc/library/random.rst | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/Doc/library/random.rst b/Doc/library/random.rst index 8154dfc18ccc6d..0e703251259aa7 100644 --- a/Doc/library/random.rst +++ b/Doc/library/random.rst @@ -142,10 +142,11 @@ Functions for integers .. function:: getrandbits(k) - Returns a Python integer with *k* random bits. This method is supplied with - the MersenneTwister generator and some other generators may also provide it - as an optional part of the API. When available, :meth:`getrandbits` enables - :meth:`randrange` to handle arbitrarily large ranges. + Returns a non-negative Python integer with *k* random bits. This method + is supplied with the MersenneTwister generator and some other generators + may also provide it as an optional part of the API. When available, + :meth:`getrandbits` enables :meth:`randrange` to handle arbitrarily large + ranges. .. versionchanged:: 3.9 This method now accepts zero for *k*. From 87e7a14ee3bd7dc495e51166598453114342d0bf Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sat, 19 Dec 2020 13:08:07 +0200 Subject: [PATCH 0823/1314] [3.9] bpo-42630: Improve error reporting in Tkinter for absent default root (GH-23781) (GH-23853) * Tkinter functions and constructors which need a default root window raise now RuntimeError with descriptive message instead of obscure AttributeError or NameError if it is not created yet or cannot be created automatically. * Add tests for all functions which use default root window. * Fix import in the pynche script. (cherry picked from commit 3d569fd6dccf9f582bafaca04d3535094cae393e) --- Lib/idlelib/pyshell.py | 4 +- Lib/test/test_idle.py | 2 +- Lib/tkinter/__init__.py | 51 +++++++----- Lib/tkinter/commondialog.py | 4 +- Lib/tkinter/font.py | 6 +- Lib/tkinter/simpledialog.py | 19 ++--- Lib/tkinter/test/support.py | 27 ++++++ Lib/tkinter/test/test_tkinter/test_font.py | 35 +++++++- Lib/tkinter/test/test_tkinter/test_images.py | 45 +++++++++- Lib/tkinter/test/test_tkinter/test_misc.py | 82 ++++++++++++++++++- .../test/test_tkinter/test_simpledialog.py | 25 ++++++ .../test/test_tkinter/test_variables.py | 17 +++- Lib/tkinter/test/test_tkinter/test_widgets.py | 14 +++- Lib/tkinter/test/test_ttk/test_extensions.py | 26 ++---- Lib/tkinter/test/test_ttk/test_widgets.py | 14 +++- Lib/tkinter/tix.py | 9 +- Lib/tkinter/ttk.py | 7 +- .../2020-12-15-17-51-27.bpo-42630.jf4jBl.rst | 4 + Tools/pynche/PyncheWidget.py | 12 +-- 19 files changed, 316 insertions(+), 87 deletions(-) create mode 100644 Lib/tkinter/test/test_tkinter/test_simpledialog.py create mode 100644 Misc/NEWS.d/next/Library/2020-12-15-17-51-27.bpo-42630.jf4jBl.rst diff --git a/Lib/idlelib/pyshell.py b/Lib/idlelib/pyshell.py index adc302883ae669..6fa138219a24da 100755 --- a/Lib/idlelib/pyshell.py +++ b/Lib/idlelib/pyshell.py @@ -1061,8 +1061,10 @@ def begin(self): (sys.version, sys.platform, self.COPYRIGHT, nosub)) self.text.focus_force() self.showprompt() + # User code should use separate default Tk root window import tkinter - tkinter._default_root = None # 03Jan04 KBK What's this? + tkinter._support_default_root = True + tkinter._default_root = None return True def stop_readline(self): diff --git a/Lib/test/test_idle.py b/Lib/test/test_idle.py index 8bc01deaa33841..310b72c1d72e74 100644 --- a/Lib/test/test_idle.py +++ b/Lib/test/test_idle.py @@ -20,5 +20,5 @@ if __name__ == '__main__': tk.NoDefaultRoot() unittest.main(exit=False) - tk._support_default_root = 1 + tk._support_default_root = True tk._default_root = None diff --git a/Lib/tkinter/__init__.py b/Lib/tkinter/__init__.py index 2175afcffa435a..bf0342e27b21f3 100644 --- a/Lib/tkinter/__init__.py +++ b/Lib/tkinter/__init__.py @@ -270,7 +270,7 @@ def __repr__(self): ) -_support_default_root = 1 +_support_default_root = True _default_root = None @@ -280,13 +280,26 @@ def NoDefaultRoot(): Call this function to inhibit that the first instance of Tk is used for windows without an explicit parent window. """ - global _support_default_root - _support_default_root = 0 - global _default_root + global _support_default_root, _default_root + _support_default_root = False + # Delete, so any use of _default_root will immediately raise an exception. + # Rebind before deletion, so repeated calls will not fail. _default_root = None del _default_root +def _get_default_root(what=None): + if not _support_default_root: + raise RuntimeError("No master specified and tkinter is " + "configured to not support default root") + if not _default_root: + if what: + raise RuntimeError(f"Too early to {what}: no default root window") + root = Tk() + assert _default_root is root + return _default_root + + def _tkerror(err): """Internal function.""" pass @@ -330,7 +343,7 @@ def __init__(self, master=None, value=None, name=None): raise TypeError("name must be a string") global _varnum if not master: - master = _default_root + master = _get_default_root('create variable') self._root = master._root() self._tk = master.tk if name: @@ -591,7 +604,7 @@ def get(self): def mainloop(n=0): """Run the main loop of Tcl.""" - _default_root.tk.mainloop(n) + _get_default_root('run the main loop').tk.mainloop(n) getint = int @@ -600,9 +613,9 @@ def mainloop(n=0): def getboolean(s): - """Convert true and false to integer values 1 and 0.""" + """Convert Tcl object to True or False.""" try: - return _default_root.tk.getboolean(s) + return _get_default_root('use getboolean()').tk.getboolean(s) except TclError: raise ValueError("invalid literal for getboolean()") @@ -2248,7 +2261,7 @@ def __init__(self, screenName=None, baseName=None, className='Tk', is the name of the widget class.""" self.master = None self.children = {} - self._tkloaded = 0 + self._tkloaded = False # to avoid recursions in the getattr code in case of failure, we # ensure that self.tk is always _something_. self.tk = None @@ -2272,7 +2285,7 @@ def loadtk(self): self._loadtk() def _loadtk(self): - self._tkloaded = 1 + self._tkloaded = True global _default_root # Version sanity checks tk_version = self.tk.getvar('tk_version') @@ -2521,12 +2534,8 @@ class BaseWidget(Misc): def _setup(self, master, cnf): """Internal function. Sets up information about children.""" - if _support_default_root: - global _default_root - if not master: - if not _default_root: - _default_root = Tk() - master = _default_root + if not master: + master = _get_default_root() self.master = master self.tk = master.tk name = None @@ -3990,9 +3999,7 @@ class Image: def __init__(self, imgtype, name=None, cnf={}, master=None, **kw): self.name = None if not master: - master = _default_root - if not master: - raise RuntimeError('Too early to create image') + master = _get_default_root('create image') self.tk = getattr(master, 'tk', master) if not name: Image._last_id += 1 @@ -4146,11 +4153,13 @@ def __init__(self, name=None, cnf={}, master=None, **kw): def image_names(): - return _default_root.tk.splitlist(_default_root.tk.call('image', 'names')) + tk = _get_default_root('use image_names()').tk + return tk.splitlist(tk.call('image', 'names')) def image_types(): - return _default_root.tk.splitlist(_default_root.tk.call('image', 'types')) + tk = _get_default_root('use image_types()').tk + return tk.splitlist(tk.call('image', 'types')) class Spinbox(Widget, XView): diff --git a/Lib/tkinter/commondialog.py b/Lib/tkinter/commondialog.py index e56b5baf7d1e12..cc3069842c3e46 100644 --- a/Lib/tkinter/commondialog.py +++ b/Lib/tkinter/commondialog.py @@ -18,10 +18,10 @@ class Dialog: command = None def __init__(self, master=None, **options): + if not master: + master = options.get('parent') self.master = master self.options = options - if not master and options.get('parent'): - self.master = options['parent'] def _fixoptions(self): pass # hook diff --git a/Lib/tkinter/font.py b/Lib/tkinter/font.py index 15ad7ab4b63a81..2b58030c1fb5a9 100644 --- a/Lib/tkinter/font.py +++ b/Lib/tkinter/font.py @@ -69,7 +69,7 @@ def _mkdict(self, args): def __init__(self, root=None, font=None, name=None, exists=False, **options): if not root: - root = tkinter._default_root + root = tkinter._get_default_root('use font') tk = getattr(root, 'tk', root) if font: # get actual settings corresponding to the given font @@ -180,7 +180,7 @@ def metrics(self, *options, **kw): def families(root=None, displayof=None): "Get font families (as a tuple)" if not root: - root = tkinter._default_root + root = tkinter._get_default_root('use font.families()') args = () if displayof: args = ('-displayof', displayof) @@ -190,7 +190,7 @@ def families(root=None, displayof=None): def names(root=None): "Get names of defined fonts (as a tuple)" if not root: - root = tkinter._default_root + root = tkinter._get_default_root('use font.names()') return root.tk.splitlist(root.tk.call("font", "names")) diff --git a/Lib/tkinter/simpledialog.py b/Lib/tkinter/simpledialog.py index 85244171117b61..b882d47c961bdb 100644 --- a/Lib/tkinter/simpledialog.py +++ b/Lib/tkinter/simpledialog.py @@ -24,9 +24,7 @@ """ from tkinter import * -from tkinter import messagebox - -import tkinter # used at _QueryDialog for tkinter._default_root +from tkinter import messagebox, _get_default_root class SimpleDialog: @@ -128,13 +126,17 @@ def __init__(self, parent, title = None): title -- the dialog title ''' - Toplevel.__init__(self, parent) + master = parent + if not master: + master = _get_default_root('create dialog window') + + Toplevel.__init__(self, master) self.withdraw() # remain invisible for now - # If the master is not viewable, don't + # If the parent is not viewable, don't # make the child transient, or else it # would be opened withdrawn - if parent.winfo_viewable(): + if parent is not None and parent.winfo_viewable(): self.transient(parent) if title: @@ -155,7 +157,7 @@ def __init__(self, parent, title = None): self.protocol("WM_DELETE_WINDOW", self.cancel) - if self.parent is not None: + if parent is not None: self.geometry("+%d+%d" % (parent.winfo_rootx()+50, parent.winfo_rooty()+50)) @@ -259,9 +261,6 @@ def __init__(self, title, prompt, minvalue = None, maxvalue = None, parent = None): - if not parent: - parent = tkinter._default_root - self.prompt = prompt self.minvalue = minvalue self.maxvalue = maxvalue diff --git a/Lib/tkinter/test/support.py b/Lib/tkinter/test/support.py index 467a0b66c265c0..dbc47a81e65157 100644 --- a/Lib/tkinter/test/support.py +++ b/Lib/tkinter/test/support.py @@ -36,6 +36,33 @@ def tearDown(self): w.destroy() self.root.withdraw() + +class AbstractDefaultRootTest: + + def setUp(self): + self._old_support_default_root = tkinter._support_default_root + destroy_default_root() + tkinter._support_default_root = True + self.wantobjects = tkinter.wantobjects + + def tearDown(self): + destroy_default_root() + tkinter._default_root = None + tkinter._support_default_root = self._old_support_default_root + + def _test_widget(self, constructor): + # no master passing + x = constructor() + self.assertIsNotNone(tkinter._default_root) + self.assertIs(x.master, tkinter._default_root) + self.assertIs(x.tk, tkinter._default_root.tk) + x.destroy() + destroy_default_root() + tkinter.NoDefaultRoot() + self.assertRaises(RuntimeError, constructor) + self.assertFalse(hasattr(tkinter, '_default_root')) + + def destroy_default_root(): if getattr(tkinter, '_default_root', None): tkinter._default_root.update_idletasks() diff --git a/Lib/tkinter/test/test_tkinter/test_font.py b/Lib/tkinter/test/test_tkinter/test_font.py index a021ea336807bb..28d8c7b2f89636 100644 --- a/Lib/tkinter/test/test_tkinter/test_font.py +++ b/Lib/tkinter/test/test_tkinter/test_font.py @@ -2,7 +2,7 @@ import tkinter from tkinter import font from test.support import requires, run_unittest, gc_collect, ALWAYS_EQ -from tkinter.test.support import AbstractTkTest +from tkinter.test.support import AbstractTkTest, AbstractDefaultRootTest requires('gui') @@ -101,7 +101,38 @@ def test_names(self): self.assertTrue(name) self.assertIn(fontname, names) -tests_gui = (FontTest, ) + +class DefaultRootTest(AbstractDefaultRootTest, unittest.TestCase): + + def test_families(self): + self.assertRaises(RuntimeError, font.families) + root = tkinter.Tk() + families = font.families() + self.assertIsInstance(families, tuple) + self.assertTrue(families) + for family in families: + self.assertIsInstance(family, str) + self.assertTrue(family) + root.destroy() + tkinter.NoDefaultRoot() + self.assertRaises(RuntimeError, font.families) + + def test_names(self): + self.assertRaises(RuntimeError, font.names) + root = tkinter.Tk() + names = font.names() + self.assertIsInstance(names, tuple) + self.assertTrue(names) + for name in names: + self.assertIsInstance(name, str) + self.assertTrue(name) + self.assertIn(fontname, names) + root.destroy() + tkinter.NoDefaultRoot() + self.assertRaises(RuntimeError, font.names) + + +tests_gui = (FontTest, DefaultRootTest) if __name__ == "__main__": run_unittest(*tests_gui) diff --git a/Lib/tkinter/test/test_tkinter/test_images.py b/Lib/tkinter/test/test_tkinter/test_images.py index 2805d35a1f5b1b..94bba8518fdaa6 100644 --- a/Lib/tkinter/test/test_tkinter/test_images.py +++ b/Lib/tkinter/test/test_tkinter/test_images.py @@ -1,7 +1,7 @@ import unittest import tkinter from test import support -from tkinter.test.support import AbstractTkTest, requires_tcl +from tkinter.test.support import AbstractTkTest, AbstractDefaultRootTest, requires_tcl support.requires('gui') @@ -19,6 +19,47 @@ def test_image_names(self): self.assertIsInstance(image_names, tuple) +class DefaultRootTest(AbstractDefaultRootTest, unittest.TestCase): + + def test_image_types(self): + self.assertRaises(RuntimeError, tkinter.image_types) + root = tkinter.Tk() + image_types = tkinter.image_types() + self.assertIsInstance(image_types, tuple) + self.assertIn('photo', image_types) + self.assertIn('bitmap', image_types) + root.destroy() + tkinter.NoDefaultRoot() + self.assertRaises(RuntimeError, tkinter.image_types) + + def test_image_names(self): + self.assertRaises(RuntimeError, tkinter.image_names) + root = tkinter.Tk() + image_names = tkinter.image_names() + self.assertIsInstance(image_names, tuple) + root.destroy() + tkinter.NoDefaultRoot() + self.assertRaises(RuntimeError, tkinter.image_names) + + def test_image_create_bitmap(self): + self.assertRaises(RuntimeError, tkinter.BitmapImage) + root = tkinter.Tk() + image = tkinter.BitmapImage() + self.assertIn(image.name, tkinter.image_names()) + root.destroy() + tkinter.NoDefaultRoot() + self.assertRaises(RuntimeError, tkinter.BitmapImage) + + def test_image_create_photo(self): + self.assertRaises(RuntimeError, tkinter.PhotoImage) + root = tkinter.Tk() + image = tkinter.PhotoImage() + self.assertIn(image.name, tkinter.image_names()) + root.destroy() + tkinter.NoDefaultRoot() + self.assertRaises(RuntimeError, tkinter.PhotoImage) + + class BitmapImageTest(AbstractTkTest, unittest.TestCase): @classmethod @@ -330,7 +371,7 @@ def test_transparency(self): self.assertEqual(image.transparency_get(4, 6), False) -tests_gui = (MiscTest, BitmapImageTest, PhotoImageTest,) +tests_gui = (MiscTest, DefaultRootTest, BitmapImageTest, PhotoImageTest,) if __name__ == "__main__": support.run_unittest(*tests_gui) diff --git a/Lib/tkinter/test/test_tkinter/test_misc.py b/Lib/tkinter/test/test_tkinter/test_misc.py index b8eea2544f5228..585d81ddf9f2d6 100644 --- a/Lib/tkinter/test/test_tkinter/test_misc.py +++ b/Lib/tkinter/test/test_tkinter/test_misc.py @@ -1,7 +1,7 @@ import unittest import tkinter from test import support -from tkinter.test.support import AbstractTkTest +from tkinter.test.support import AbstractTkTest, AbstractDefaultRootTest support.requires('gui') @@ -241,7 +241,85 @@ def test_event_repr(self): " num=3 delta=-1 focus=True" " x=10 y=20 width=300 height=200>") -tests_gui = (MiscTest, ) + def test_getboolean(self): + for v in 'true', 'yes', 'on', '1', 't', 'y', 1, True: + self.assertIs(self.root.getboolean(v), True) + for v in 'false', 'no', 'off', '0', 'f', 'n', 0, False: + self.assertIs(self.root.getboolean(v), False) + self.assertRaises(ValueError, self.root.getboolean, 'yea') + self.assertRaises(ValueError, self.root.getboolean, '') + self.assertRaises(TypeError, self.root.getboolean, None) + self.assertRaises(TypeError, self.root.getboolean, ()) + + def test_mainloop(self): + log = [] + def callback(): + log.append(1) + self.root.after(100, self.root.quit) + self.root.after(100, callback) + self.root.mainloop(1) + self.assertEqual(log, []) + self.root.mainloop(0) + self.assertEqual(log, [1]) + self.assertTrue(self.root.winfo_exists()) + + +class DefaultRootTest(AbstractDefaultRootTest, unittest.TestCase): + + def test_default_root(self): + self.assertIs(tkinter._support_default_root, True) + self.assertIsNone(tkinter._default_root) + root = tkinter.Tk() + root2 = tkinter.Tk() + root3 = tkinter.Tk() + self.assertIs(tkinter._default_root, root) + root2.destroy() + self.assertIs(tkinter._default_root, root) + root.destroy() + self.assertIsNone(tkinter._default_root) + root3.destroy() + self.assertIsNone(tkinter._default_root) + + def test_no_default_root(self): + self.assertIs(tkinter._support_default_root, True) + self.assertIsNone(tkinter._default_root) + root = tkinter.Tk() + self.assertIs(tkinter._default_root, root) + tkinter.NoDefaultRoot() + self.assertIs(tkinter._support_default_root, False) + self.assertFalse(hasattr(tkinter, '_default_root')) + # repeated call is no-op + tkinter.NoDefaultRoot() + self.assertIs(tkinter._support_default_root, False) + self.assertFalse(hasattr(tkinter, '_default_root')) + root.destroy() + self.assertIs(tkinter._support_default_root, False) + self.assertFalse(hasattr(tkinter, '_default_root')) + root = tkinter.Tk() + self.assertIs(tkinter._support_default_root, False) + self.assertFalse(hasattr(tkinter, '_default_root')) + root.destroy() + + def test_getboolean(self): + self.assertRaises(RuntimeError, tkinter.getboolean, '1') + root = tkinter.Tk() + self.assertIs(tkinter.getboolean('1'), True) + self.assertRaises(ValueError, tkinter.getboolean, 'yea') + root.destroy() + tkinter.NoDefaultRoot() + self.assertRaises(RuntimeError, tkinter.getboolean, '1') + + def test_mainloop(self): + self.assertRaises(RuntimeError, tkinter.mainloop) + root = tkinter.Tk() + root.after_idle(root.quit) + tkinter.mainloop() + root.destroy() + tkinter.NoDefaultRoot() + self.assertRaises(RuntimeError, tkinter.mainloop) + + +tests_gui = (MiscTest, DefaultRootTest) if __name__ == "__main__": support.run_unittest(*tests_gui) diff --git a/Lib/tkinter/test/test_tkinter/test_simpledialog.py b/Lib/tkinter/test/test_tkinter/test_simpledialog.py new file mode 100644 index 00000000000000..911917258806d1 --- /dev/null +++ b/Lib/tkinter/test/test_tkinter/test_simpledialog.py @@ -0,0 +1,25 @@ +import unittest +import tkinter +from test.support import requires, run_unittest, swap_attr +from tkinter.test.support import AbstractDefaultRootTest +from tkinter.simpledialog import Dialog, askinteger + +requires('gui') + + +class DefaultRootTest(AbstractDefaultRootTest, unittest.TestCase): + + def test_askinteger(self): + self.assertRaises(RuntimeError, askinteger, "Go To Line", "Line number") + root = tkinter.Tk() + with swap_attr(Dialog, 'wait_window', lambda self, w: w.destroy()): + askinteger("Go To Line", "Line number") + root.destroy() + tkinter.NoDefaultRoot() + self.assertRaises(RuntimeError, askinteger, "Go To Line", "Line number") + + +tests_gui = (DefaultRootTest,) + +if __name__ == "__main__": + run_unittest(*tests_gui) diff --git a/Lib/tkinter/test/test_tkinter/test_variables.py b/Lib/tkinter/test/test_tkinter/test_variables.py index 08b7dedcaf933b..63d7c21059e38c 100644 --- a/Lib/tkinter/test/test_tkinter/test_variables.py +++ b/Lib/tkinter/test/test_tkinter/test_variables.py @@ -1,8 +1,10 @@ import unittest import gc +import tkinter from tkinter import (Variable, StringVar, IntVar, DoubleVar, BooleanVar, Tcl, TclError) from test.support import ALWAYS_EQ +from tkinter.test.support import AbstractDefaultRootTest class Var(Variable): @@ -308,8 +310,21 @@ def test_invalid_value_domain(self): v.get() +class DefaultRootTest(AbstractDefaultRootTest, unittest.TestCase): + + def test_variable(self): + self.assertRaises(RuntimeError, Variable) + root = tkinter.Tk() + v = Variable() + v.set("value") + self.assertEqual(v.get(), "value") + root.destroy() + tkinter.NoDefaultRoot() + self.assertRaises(RuntimeError, Variable) + + tests_gui = (TestVariable, TestStringVar, TestIntVar, - TestDoubleVar, TestBooleanVar) + TestDoubleVar, TestBooleanVar, DefaultRootTest) if __name__ == "__main__": diff --git a/Lib/tkinter/test/test_tkinter/test_widgets.py b/Lib/tkinter/test/test_tkinter/test_widgets.py index 4b9b6ebdda04ea..54eddbf8216110 100644 --- a/Lib/tkinter/test/test_tkinter/test_widgets.py +++ b/Lib/tkinter/test/test_tkinter/test_widgets.py @@ -5,7 +5,8 @@ from test.support import requires from tkinter.test.support import (tcl_version, requires_tcl, - get_tk_patchlevel, widget_eq) + get_tk_patchlevel, widget_eq, + AbstractDefaultRootTest) from tkinter.test.widget_tests import ( add_standard_options, noconv, pixels_round, AbstractWidgetTest, StandardOptionsTests, IntegerSizeTests, PixelSizeTests, @@ -1295,12 +1296,21 @@ def test_aspect(self): self.checkIntegerParam(widget, 'aspect', 250, 0, -300) +class DefaultRootTest(AbstractDefaultRootTest, unittest.TestCase): + + def test_frame(self): + self._test_widget(tkinter.Frame) + + def test_label(self): + self._test_widget(tkinter.Label) + + tests_gui = ( ButtonTest, CanvasTest, CheckbuttonTest, EntryTest, FrameTest, LabelFrameTest,LabelTest, ListboxTest, MenubuttonTest, MenuTest, MessageTest, OptionMenuTest, PanedWindowTest, RadiobuttonTest, ScaleTest, ScrollbarTest, - SpinboxTest, TextTest, ToplevelTest, + SpinboxTest, TextTest, ToplevelTest, DefaultRootTest, ) if __name__ == '__main__': diff --git a/Lib/tkinter/test/test_ttk/test_extensions.py b/Lib/tkinter/test/test_ttk/test_extensions.py index 6937ba1ca9be41..1a70e0befe6234 100644 --- a/Lib/tkinter/test/test_ttk/test_extensions.py +++ b/Lib/tkinter/test/test_ttk/test_extensions.py @@ -2,8 +2,8 @@ import unittest import tkinter from tkinter import ttk -from test.support import requires, run_unittest, swap_attr -from tkinter.test.support import AbstractTkTest, destroy_default_root +from test.support import requires, run_unittest +from tkinter.test.support import AbstractTkTest, AbstractDefaultRootTest requires('gui') @@ -46,20 +46,6 @@ def test_widget_destroy(self): if hasattr(sys, 'last_type'): self.assertNotEqual(sys.last_type, tkinter.TclError) - - def test_initialization_no_master(self): - # no master passing - with swap_attr(tkinter, '_default_root', None), \ - swap_attr(tkinter, '_support_default_root', True): - try: - x = ttk.LabeledScale() - self.assertIsNotNone(tkinter._default_root) - self.assertEqual(x.master, tkinter._default_root) - self.assertEqual(x.tk, tkinter._default_root.tk) - x.destroy() - finally: - destroy_default_root() - def test_initialization(self): # master passing master = tkinter.Frame(self.root) @@ -311,7 +297,13 @@ def test_unique_radiobuttons(self): optmenu2.destroy() -tests_gui = (LabeledScaleTest, OptionMenuTest) +class DefaultRootTest(AbstractDefaultRootTest, unittest.TestCase): + + def test_labeledscale(self): + self._test_widget(ttk.LabeledScale) + + +tests_gui = (LabeledScaleTest, OptionMenuTest, DefaultRootTest) if __name__ == "__main__": run_unittest(*tests_gui) diff --git a/Lib/tkinter/test/test_ttk/test_widgets.py b/Lib/tkinter/test/test_ttk/test_widgets.py index 157ef0e8f87bb5..de30e2476b4eb9 100644 --- a/Lib/tkinter/test/test_ttk/test_widgets.py +++ b/Lib/tkinter/test/test_ttk/test_widgets.py @@ -6,7 +6,7 @@ from tkinter.test.test_ttk.test_functions import MockTclObj from tkinter.test.support import (AbstractTkTest, tcl_version, get_tk_patchlevel, - simulate_mouse_click) + simulate_mouse_click, AbstractDefaultRootTest) from tkinter.test.widget_tests import (add_standard_options, noconv, AbstractWidgetTest, StandardOptionsTests, IntegerSizeTests, PixelSizeTests, setUpModule) @@ -1860,12 +1860,22 @@ class SizegripTest(AbstractWidgetTest, unittest.TestCase): def create(self, **kwargs): return ttk.Sizegrip(self.root, **kwargs) + +class DefaultRootTest(AbstractDefaultRootTest, unittest.TestCase): + + def test_frame(self): + self._test_widget(ttk.Frame) + + def test_label(self): + self._test_widget(ttk.Label) + + tests_gui = ( ButtonTest, CheckbuttonTest, ComboboxTest, EntryTest, FrameTest, LabelFrameTest, LabelTest, MenubuttonTest, NotebookTest, PanedWindowTest, ProgressbarTest, RadiobuttonTest, ScaleTest, ScrollbarTest, SeparatorTest, - SizegripTest, SpinboxTest, TreeviewTest, WidgetTest, + SizegripTest, SpinboxTest, TreeviewTest, WidgetTest, DefaultRootTest, ) if __name__ == "__main__": diff --git a/Lib/tkinter/tix.py b/Lib/tkinter/tix.py index ac545502e45c30..ef1e7406bc1ae0 100644 --- a/Lib/tkinter/tix.py +++ b/Lib/tkinter/tix.py @@ -387,9 +387,7 @@ def config_all(self, option, value): # These are missing from Tkinter def image_create(self, imgtype, cnf={}, master=None, **kw): if not master: - master = tkinter._default_root - if not master: - raise RuntimeError('Too early to create image') + master = self if kw and cnf: cnf = _cnfmerge((cnf, kw)) elif kw: cnf = kw options = () @@ -475,10 +473,7 @@ def __init__(self, itemtype, cnf={}, *, master=None, **kw): elif 'refwindow' in cnf: master = cnf['refwindow'] else: - master = tkinter._default_root - if not master: - raise RuntimeError("Too early to create display style: " - "no root window") + master = tkinter._get_default_root('create display style') self.tk = master.tk self.stylename = self.tk.call('tixDisplayStyle', itemtype, *self._options(cnf,kw) ) diff --git a/Lib/tkinter/ttk.py b/Lib/tkinter/ttk.py index 968fd54dce1ee0..523edb9715f08b 100644 --- a/Lib/tkinter/ttk.py +++ b/Lib/tkinter/ttk.py @@ -349,12 +349,7 @@ def setup_master(master=None): If it is not allowed to use the default root and master is None, RuntimeError is raised.""" if master is None: - if tkinter._support_default_root: - master = tkinter._default_root or tkinter.Tk() - else: - raise RuntimeError( - "No master specified and tkinter is " - "configured to not support default root") + master = tkinter._get_default_root() return master diff --git a/Misc/NEWS.d/next/Library/2020-12-15-17-51-27.bpo-42630.jf4jBl.rst b/Misc/NEWS.d/next/Library/2020-12-15-17-51-27.bpo-42630.jf4jBl.rst new file mode 100644 index 00000000000000..4b4a520931fda4 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2020-12-15-17-51-27.bpo-42630.jf4jBl.rst @@ -0,0 +1,4 @@ +:mod:`tkinter` functions and constructors which need a default root window +raise now :exc:`RuntimeError` with descriptive message instead of obscure +:exc:`AttributeError` or :exc:`NameError` if it is not created yet or cannot +be created automatically. diff --git a/Tools/pynche/PyncheWidget.py b/Tools/pynche/PyncheWidget.py index ef12198a218388..ea456e577e12a9 100644 --- a/Tools/pynche/PyncheWidget.py +++ b/Tools/pynche/PyncheWidget.py @@ -36,15 +36,11 @@ def __init__(self, version, switchboard, master=None, extrapath=[]): else: # Is there already a default root for Tk, say because we're # running under Guido's IDE? :-) Two conditions say no, either the - # import fails or _default_root is None. - tkroot = None - try: - from Tkinter import _default_root - tkroot = self.__tkroot = _default_root - except ImportError: - pass + # _default_root is None or it is unset. + tkroot = getattr(tkinter, '_default_root', None) if not tkroot: - tkroot = self.__tkroot = Tk(className='Pynche') + tkroot = Tk(className='Pynche') + self.__tkroot = tkroot # but this isn't our top level widget, so make it invisible tkroot.withdraw() # create the menubar From 6ad5fd14825fc6039a9684dfdc14f5d12b86e25f Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 19 Dec 2020 09:28:59 -0800 Subject: [PATCH 0824/1314] bpo-40219: Lowered ttk LabeledScale dummy (GH-21467) (GH-23788) (cherry picked from commit b9ced83cf427ec86802ba4c9a562c6d9cafc72f5) --- Lib/tkinter/ttk.py | 5 ++++- .../next/Library/2020-07-13-19-43-11.bpo-40219.MUoJEP.rst | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Library/2020-07-13-19-43-11.bpo-40219.MUoJEP.rst diff --git a/Lib/tkinter/ttk.py b/Lib/tkinter/ttk.py index 523edb9715f08b..ab7aeb15e8ff22 100644 --- a/Lib/tkinter/ttk.py +++ b/Lib/tkinter/ttk.py @@ -1533,7 +1533,10 @@ def __init__(self, master=None, variable=None, from_=0, to=10, **kw): scale_side = 'bottom' if self._label_top else 'top' label_side = 'top' if scale_side == 'bottom' else 'bottom' self.scale.pack(side=scale_side, fill='x') - tmp = Label(self).pack(side=label_side) # place holder + # Dummy required to make frame correct height + dummy = Label(self) + dummy.pack(side=label_side) + dummy.lower() self.label.place(anchor='n' if label_side == 'top' else 's') # update the label as scale or variable changes diff --git a/Misc/NEWS.d/next/Library/2020-07-13-19-43-11.bpo-40219.MUoJEP.rst b/Misc/NEWS.d/next/Library/2020-07-13-19-43-11.bpo-40219.MUoJEP.rst new file mode 100644 index 00000000000000..aedc5c49b4087a --- /dev/null +++ b/Misc/NEWS.d/next/Library/2020-07-13-19-43-11.bpo-40219.MUoJEP.rst @@ -0,0 +1 @@ +Lowered :class:`tkinter.ttk.LabeledScale` dummy widget to prevent hiding part of the content label. From 597ebc8cf604de49eabbc7b83be2debd005d7819 Mon Sep 17 00:00:00 2001 From: kj <28750310+Fidget-Spinner@users.noreply.github.com> Date: Sun, 20 Dec 2020 06:32:06 +0800 Subject: [PATCH 0825/1314] [3.9] bpo-42675: Document collections.abc.Callable changes (GH-23839) (#23852) --- Doc/library/types.rst | 3 +++ Doc/whatsnew/3.9.rst | 19 +++++++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/Doc/library/types.rst b/Doc/library/types.rst index 0fe3822fa542e3..d83d9667ba3a7c 100644 --- a/Doc/library/types.rst +++ b/Doc/library/types.rst @@ -260,6 +260,9 @@ Standard names are defined for the following types: .. versionadded:: 3.9 + .. versionchanged:: 3.9.2 + This type can now be subclassed. + .. class:: TracebackType(tb_next, tb_frame, tb_lasti, tb_lineno) diff --git a/Doc/whatsnew/3.9.rst b/Doc/whatsnew/3.9.rst index f8f421bdda1c7c..68b1e504da89ef 100644 --- a/Doc/whatsnew/3.9.rst +++ b/Doc/whatsnew/3.9.rst @@ -1497,3 +1497,22 @@ functions and options conditionally available based on the operating system version in use at runtime ("weaklinking"). (Contributed by Ronald Oussoren and Lawrence D'Anna in :issue:`41100`.) + +Notable changes in Python 3.9.2 +=============================== + +collections.abc +--------------- + +:class:`collections.abc.Callable` generic now flattens type parameters, similar +to what :data:`typing.Callable` currently does. This means that +``collections.abc.Callable[[int, str], str]`` will have ``__args__`` of +``(int, str, str)``; previously this was ``([int, str], str)``. To allow this +change, :class:`types.GenericAlias` can now be subclassed, and a subclass will +be returned when subscripting the :class:`collections.abc.Callable` type. +Code which accesses the arguments via :func:`typing.get_args` or ``__args__`` +need to account for this change. A :exc:`DeprecationWarning` may be emitted for +invalid forms of parameterizing :class:`collections.abc.Callable` which may have +passed silently in Python 3.9.1. This :exc:`DeprecationWarning` will +become a :exc:`TypeError` in Python 3.10. +(Contributed by Ken Jin in :issue:`42195`.) From a34ab8188e0352e4066da4f79ed3cc24d1b61a63 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 19 Dec 2020 16:02:25 -0800 Subject: [PATCH 0826/1314] bpo-41724: Explain when the conversion is not possible with detect_types enabled (GH-23855) (GH-23862) * Explain when the conversion is not possible with detect_types enabled (cherry picked from commit 09a36cdfb7c22f44df45b44e5561776206bcedfb) Co-authored-by: sblondon Co-authored-by: sblondon --- Doc/library/sqlite3.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Doc/library/sqlite3.rst b/Doc/library/sqlite3.rst index ccb82278bdaa13..b97414e6fcaa6e 100644 --- a/Doc/library/sqlite3.rst +++ b/Doc/library/sqlite3.rst @@ -197,7 +197,9 @@ Module functions and constants *detect_types* defaults to 0 (i. e. off, no type detection), you can set it to any combination of :const:`PARSE_DECLTYPES` and :const:`PARSE_COLNAMES` to turn - type detection on. + type detection on. Due to SQLite behaviour, types can't be detected for generated + fields (for example ``max(data)``), even when *detect_types* parameter is set. In + such case, the returned type is :class:`str`. By default, *check_same_thread* is :const:`True` and only the creating thread may use the connection. If set :const:`False`, the returned connection may be shared From 4b155967b3e743cbdc31600f13f1bfcf07f7b6ce Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 19 Dec 2020 20:54:18 -0800 Subject: [PATCH 0827/1314] bpo-42604: always set EXT_SUFFIX=${SOABI}${SHLIB_SUFFIX} when using configure (GH-23708) (GH-23866) Now all platforms use a value for the "EXT_SUFFIX" build variable derived from SOABI (for instance in FreeBSD, "EXT_SUFFIX" is now ".cpython-310d.so" instead of ".so"). Previously only Linux, Mac and VxWorks were using a value for "EXT_SUFFIX" that included "SOABI". Co-authored-by: Pablo Galindo (cherry picked from commit a44ce6c9f725d336aea51a946b42769f29fed613) Co-authored-by: Matti Picus Co-authored-by: Matti Picus --- .../next/Build/2020-12-20-02-35-28.bpo-42604.gRd89w.rst | 4 ++++ configure | 8 +------- configure.ac | 7 +------ 3 files changed, 6 insertions(+), 13 deletions(-) create mode 100644 Misc/NEWS.d/next/Build/2020-12-20-02-35-28.bpo-42604.gRd89w.rst diff --git a/Misc/NEWS.d/next/Build/2020-12-20-02-35-28.bpo-42604.gRd89w.rst b/Misc/NEWS.d/next/Build/2020-12-20-02-35-28.bpo-42604.gRd89w.rst new file mode 100644 index 00000000000000..caaada41cf9bad --- /dev/null +++ b/Misc/NEWS.d/next/Build/2020-12-20-02-35-28.bpo-42604.gRd89w.rst @@ -0,0 +1,4 @@ +Now all platforms use a value for the "EXT_SUFFIX" build variable derived +from SOABI (for instance in freeBSD, "EXT_SUFFIX" is now ".cpython-310d.so" +instead of ".so"). Previosuly only Linux, Mac and VxWorks were using a value +for "EXT_SUFFIX" that included "SOABI". diff --git a/configure b/configure index ed969c55b35ab6..1252335472f561 100755 --- a/configure +++ b/configure @@ -15382,13 +15382,7 @@ _ACEOF fi - -case $ac_sys_system in - Linux*|GNU*|Darwin|VxWorks) - EXT_SUFFIX=.${SOABI}${SHLIB_SUFFIX};; - *) - EXT_SUFFIX=${SHLIB_SUFFIX};; -esac +EXT_SUFFIX=.${SOABI}${SHLIB_SUFFIX} { $as_echo "$as_me:${as_lineno-$LINENO}: checking LDVERSION" >&5 $as_echo_n "checking LDVERSION... " >&6; } diff --git a/configure.ac b/configure.ac index c74e348e077fb7..972287a9c47661 100644 --- a/configure.ac +++ b/configure.ac @@ -4783,12 +4783,7 @@ if test "$Py_DEBUG" = 'true' -a "$with_trace_refs" != "yes"; then fi AC_SUBST(EXT_SUFFIX) -case $ac_sys_system in - Linux*|GNU*|Darwin|VxWorks) - EXT_SUFFIX=.${SOABI}${SHLIB_SUFFIX};; - *) - EXT_SUFFIX=${SHLIB_SUFFIX};; -esac +EXT_SUFFIX=.${SOABI}${SHLIB_SUFFIX} AC_MSG_CHECKING(LDVERSION) LDVERSION='$(VERSION)$(ABIFLAGS)' From 40b4c405f98f2d35835ef5d183f0327c0c55da6f Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 20 Dec 2020 10:51:20 -0800 Subject: [PATCH 0828/1314] bpo-42572: Improve argparse docs for the type parameter. (GH-23849) (GH-23869) --- Doc/library/argparse.rst | 107 +++++++++++++++++++++------------------ 1 file changed, 57 insertions(+), 50 deletions(-) diff --git a/Doc/library/argparse.rst b/Doc/library/argparse.rst index 02cd70f4f71cd6..1a298cdd2b5344 100644 --- a/Doc/library/argparse.rst +++ b/Doc/library/argparse.rst @@ -1050,63 +1050,70 @@ command-line argument was not present:: type ^^^^ -By default, :class:`ArgumentParser` objects read command-line arguments in as simple +By default, the parser reads command-line arguments in as simple strings. However, quite often the command-line string should instead be -interpreted as another type, like a :class:`float` or :class:`int`. The -``type`` keyword argument of :meth:`~ArgumentParser.add_argument` allows any -necessary type-checking and type conversions to be performed. Common built-in -types and functions can be used directly as the value of the ``type`` argument:: +interpreted as another type, such as a :class:`float` or :class:`int`. The +``type`` keyword for :meth:`~ArgumentParser.add_argument` allows any +necessary type-checking and type conversions to be performed. - >>> parser = argparse.ArgumentParser() - >>> parser.add_argument('foo', type=int) - >>> parser.add_argument('bar', type=open) - >>> parser.parse_args('2 temp.txt'.split()) - Namespace(bar=<_io.TextIOWrapper name='temp.txt' encoding='UTF-8'>, foo=2) +If the type_ keyword is used with the default_ keyword, the type converter +is only applied if the default is a string. -See the section on the default_ keyword argument for information on when the -``type`` argument is applied to default arguments. +The argument to ``type`` can be any callable that accepts a single string. +If the function raises :exc:`ArgumentTypeError`, :exc:`TypeError`, or +:exc:`ValueError`, the exception is caught and a nicely formatted error +message is displayed. No other exception types are handled. -To ease the use of various types of files, the argparse module provides the -factory FileType which takes the ``mode=``, ``bufsize=``, ``encoding=`` and -``errors=`` arguments of the :func:`open` function. For example, -``FileType('w')`` can be used to create a writable file:: +Common built-in types and functions can be used as type converters: - >>> parser = argparse.ArgumentParser() - >>> parser.add_argument('bar', type=argparse.FileType('w')) - >>> parser.parse_args(['out.txt']) - Namespace(bar=<_io.TextIOWrapper name='out.txt' encoding='UTF-8'>) - -``type=`` can take any callable that takes a single string argument and returns -the converted value:: - - >>> def perfect_square(string): - ... value = int(string) - ... sqrt = math.sqrt(value) - ... if sqrt != int(sqrt): - ... msg = "%r is not a perfect square" % string - ... raise argparse.ArgumentTypeError(msg) - ... return value - ... - >>> parser = argparse.ArgumentParser(prog='PROG') - >>> parser.add_argument('foo', type=perfect_square) - >>> parser.parse_args(['9']) - Namespace(foo=9) - >>> parser.parse_args(['7']) - usage: PROG [-h] foo - PROG: error: argument foo: '7' is not a perfect square +.. testcode:: -The choices_ keyword argument may be more convenient for type checkers that -simply check against a range of values:: + import argparse + import pathlib - >>> parser = argparse.ArgumentParser(prog='PROG') - >>> parser.add_argument('foo', type=int, choices=range(5, 10)) - >>> parser.parse_args(['7']) - Namespace(foo=7) - >>> parser.parse_args(['11']) - usage: PROG [-h] {5,6,7,8,9} - PROG: error: argument foo: invalid choice: 11 (choose from 5, 6, 7, 8, 9) - -See the choices_ section for more details. + parser = argparse.ArgumentParser() + parser.add_argument('count', type=int) + parser.add_argument('distance', type=float) + parser.add_argument('street', type=ascii) + parser.add_argument('code_point', type=ord) + parser.add_argument('source_file', type=open) + parser.add_argument('dest_file', type=argparse.FileType('w', encoding='latin-1')) + parser.add_argument('datapath', type=pathlib.Path) + +User defined functions can be used as well: + +.. doctest:: + + >>> def hyphenated(string): + ... return '-'.join([word[:4] for word in string.casefold().split()]) + ... + >>> parser = argparse.ArgumentParser() + >>> _ = parser.add_argument('short_title', type=hyphenated) + >>> parser.parse_args(['"The Tale of Two Cities"']) + Namespace(short_title='"the-tale-of-two-citi') + +The :func:`bool` function is not recommended as a type converter. All it does +is convert empty strings to ``False`` and non-empty strings to ``True``. +This is usually not what is desired. + +In general, the ``type`` keyword is a convenience that should only be used for +simple conversions that can only raise one of the three supported exceptions. +Anything with more interesting error-handling or resource management should be +done downstream after the arguments are parsed. + +For example, JSON or YAML conversions have complex error cases that require +better reporting than can be given by the ``type`` keyword. An +:exc:`~json.JSONDecodeError` would not be well formatted and a +:exc:`FileNotFound` exception would not be handled at all. + +Even :class:`~argparse.FileType` has its limitations for use with the ``type`` +keyword. If one argument uses *FileType* and then a subsequent argument fails, +an error is reported but the file is not automatically closed. In this case, it +would be better to wait until after the parser has run and then use the +:keyword:`with`-statement to manage the files. + +For type checkers that simply check against a fixed set of values, consider +using the choices_ keyword instead. choices From 409ce4a09e4f96ca9b251c19f5819205aae9ae34 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 20 Dec 2020 13:18:08 -0800 Subject: [PATCH 0829/1314] bpo-42669: Document that `except` rejects nested tuples (GH-23822) (GH-23870) In Python 2, it was possible to use `except` with a nested tuple, and occasionally natural. For example, `zope.formlib.interfaces.InputErrors` is a tuple of several exception classes, and one might reasonably think to do something like this: try: self.getInputValue() return True except (InputErrors, SomethingElse): return False As of Python 3.0, this raises `TypeError: catching classes that do not inherit from BaseException is not allowed` instead: one must instead either break it up into multiple `except` clauses or flatten the tuple. However, the reference documentation was never updated to match this new restriction. Make it clear that the definition is no longer recursive. Automerge-Triggered-By: GH:ericvsmith (cherry picked from commit c95f8bc2700b42f4568886505a819816c9b0ba28) Co-authored-by: Colin Watson Co-authored-by: Colin Watson --- Doc/reference/compound_stmts.rst | 3 ++- Misc/ACKS | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/Doc/reference/compound_stmts.rst b/Doc/reference/compound_stmts.rst index 2cae2f86d34f71..7e666351b1b31e 100644 --- a/Doc/reference/compound_stmts.rst +++ b/Doc/reference/compound_stmts.rst @@ -254,7 +254,8 @@ present, must be last; it matches any exception. For an except clause with an expression, that expression is evaluated, and the clause matches the exception if the resulting object is "compatible" with the exception. An object is compatible with an exception if it is the class or a base class of the exception -object or a tuple containing an item compatible with the exception. +object, or a tuple containing an item that is the class or a base class of +the exception object. If no except clause matches the exception, the search for an exception handler continues in the surrounding code and on the invocation stack. [#]_ diff --git a/Misc/ACKS b/Misc/ACKS index ebf12c9a9f1dcf..a20c41f1cb189e 100644 --- a/Misc/ACKS +++ b/Misc/ACKS @@ -1829,6 +1829,7 @@ Zachary Ware Barry Warsaw Steve Waterbury Bob Watson +Colin Watson David Watson Aaron Watters Henrik Weber From b4b323ce1afa13f3d60ddb63261743dd94986b81 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 21 Dec 2020 06:29:57 -0800 Subject: [PATCH 0830/1314] Fix typo in docstring (GH-23515) (cherry picked from commit 711381dfb09fbd434cc3b404656f7fd306161a64) Co-authored-by: Fernando Toledo <42938011+fernandohtr@users.noreply.github.com> --- Lib/http/client.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/http/client.py b/Lib/http/client.py index c2ad0471bfee50..16afc871ea6d7a 100644 --- a/Lib/http/client.py +++ b/Lib/http/client.py @@ -846,7 +846,7 @@ def set_tunnel(self, host, port=None, headers=None): the endpoint passed to `set_tunnel`. This done by sending an HTTP CONNECT request to the proxy server when the connection is established. - This method must be called before the HTML connection has been + This method must be called before the HTTP connection has been established. The headers argument should be a mapping of extra HTTP headers to send From e89993cff4e60fcf32643fc613d0544f3dbcd98a Mon Sep 17 00:00:00 2001 From: Andre Delfino Date: Mon, 21 Dec 2020 23:52:19 -0300 Subject: [PATCH 0831/1314] [3.9] [doc] Fix erroneous backslashes in signatures and names (GH-23658) (GH-23827) The issue being resolved is shown in the 3.10 docs (if you select docs for older versions you won't see a visual glitch). The newer sphinx version that produces the 3.10 docs doesn't treat the backslash to escape things in some situations it previously did.. (cherry picked from commit dcc997cd28ab33ebac44182ee55533c1b37689f7) Co-authored-by: Andre Delfino --- Doc/library/asyncio-eventloop.rst | 36 +++++++++++++++--------------- Doc/library/asyncio-future.rst | 6 ++--- Doc/library/asyncio-policy.rst | 2 +- Doc/library/asyncio-stream.rst | 10 ++++----- Doc/library/asyncio-subprocess.rst | 6 ++--- Doc/library/asyncio-task.rst | 24 ++++++++++---------- Doc/library/base64.rst | 2 +- Doc/library/compileall.rst | 4 ++-- Doc/library/concurrent.futures.rst | 2 +- Doc/library/contextvars.rst | 4 ++-- Doc/library/ctypes.rst | 2 +- Doc/library/difflib.rst | 6 ++--- Doc/library/email.header.rst | 2 +- Doc/library/email.policy.rst | 2 +- Doc/library/functions.rst | 2 +- Doc/library/http.cookies.rst | 2 +- Doc/library/importlib.rst | 4 ++-- Doc/library/inspect.rst | 8 +++---- Doc/library/io.rst | 2 +- Doc/library/lzma.rst | 4 ++-- Doc/library/os.rst | 10 ++++----- Doc/library/pickle.rst | 12 +++++----- Doc/library/plistlib.rst | 8 +++---- Doc/library/shutil.rst | 2 +- Doc/library/stdtypes.rst | 4 ++-- Doc/library/subprocess.rst | 2 +- Doc/library/sysconfig.rst | 2 +- Doc/library/tarfile.rst | 2 +- Doc/library/test.rst | 2 +- Doc/library/warnings.rst | 2 +- Doc/library/winreg.rst | 2 +- Doc/library/xml.dom.minidom.rst | 2 +- 32 files changed, 90 insertions(+), 90 deletions(-) diff --git a/Doc/library/asyncio-eventloop.rst b/Doc/library/asyncio-eventloop.rst index b1e73189a7a4cf..be43ca4aebe81a 100644 --- a/Doc/library/asyncio-eventloop.rst +++ b/Doc/library/asyncio-eventloop.rst @@ -321,7 +321,7 @@ Creating Futures and Tasks .. versionadded:: 3.5.2 -.. method:: loop.create_task(coro, \*, name=None) +.. method:: loop.create_task(coro, *, name=None) Schedule the execution of a :ref:`coroutine`. Return a :class:`Task` object. @@ -356,7 +356,7 @@ Opening network connections ^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. coroutinemethod:: loop.create_connection(protocol_factory, \ - host=None, port=None, \*, ssl=None, \ + host=None, port=None, *, ssl=None, \ family=0, proto=0, flags=0, sock=None, \ local_addr=None, server_hostname=None, \ ssl_handshake_timeout=None, \ @@ -482,7 +482,7 @@ Opening network connections that can be used directly in async/await code. .. coroutinemethod:: loop.create_datagram_endpoint(protocol_factory, \ - local_addr=None, remote_addr=None, \*, \ + local_addr=None, remote_addr=None, *, \ family=0, proto=0, flags=0, \ reuse_address=None, reuse_port=None, \ allow_broadcast=None, sock=None) @@ -559,7 +559,7 @@ Opening network connections Added support for Windows. .. coroutinemethod:: loop.create_unix_connection(protocol_factory, \ - path=None, \*, ssl=None, sock=None, \ + path=None, *, ssl=None, sock=None, \ server_hostname=None, ssl_handshake_timeout=None) Create a Unix connection. @@ -592,7 +592,7 @@ Creating network servers ^^^^^^^^^^^^^^^^^^^^^^^^ .. coroutinemethod:: loop.create_server(protocol_factory, \ - host=None, port=None, \*, \ + host=None, port=None, *, \ family=socket.AF_UNSPEC, \ flags=socket.AI_PASSIVE, \ sock=None, backlog=100, ssl=None, \ @@ -683,7 +683,7 @@ Creating network servers .. coroutinemethod:: loop.create_unix_server(protocol_factory, path=None, \ - \*, sock=None, backlog=100, ssl=None, \ + *, sock=None, backlog=100, ssl=None, \ ssl_handshake_timeout=None, start_serving=True) Similar to :meth:`loop.create_server` but works with the @@ -708,7 +708,7 @@ Creating network servers The *path* parameter can now be a :class:`~pathlib.Path` object. .. coroutinemethod:: loop.connect_accepted_socket(protocol_factory, \ - sock, \*, ssl=None, ssl_handshake_timeout=None) + sock, *, ssl=None, ssl_handshake_timeout=None) Wrap an already accepted connection into a transport/protocol pair. @@ -773,7 +773,7 @@ TLS Upgrade ^^^^^^^^^^^ .. coroutinemethod:: loop.start_tls(transport, protocol, \ - sslcontext, \*, server_side=False, \ + sslcontext, *, server_side=False, \ server_hostname=None, ssl_handshake_timeout=None) Upgrade an existing transport-based connection to TLS. @@ -806,7 +806,7 @@ TLS Upgrade Watching file descriptors ^^^^^^^^^^^^^^^^^^^^^^^^^ -.. method:: loop.add_reader(fd, callback, \*args) +.. method:: loop.add_reader(fd, callback, *args) Start monitoring the *fd* file descriptor for read availability and invoke *callback* with the specified arguments once *fd* is available for @@ -816,7 +816,7 @@ Watching file descriptors Stop monitoring the *fd* file descriptor for read availability. -.. method:: loop.add_writer(fd, callback, \*args) +.. method:: loop.add_writer(fd, callback, *args) Start monitoring the *fd* file descriptor for write availability and invoke *callback* with the specified arguments once *fd* is available for @@ -930,7 +930,7 @@ convenient. :meth:`loop.create_server` and :func:`start_server`. .. coroutinemethod:: loop.sock_sendfile(sock, file, offset=0, count=None, \ - \*, fallback=True) + *, fallback=True) Send a file using high-performance :mod:`os.sendfile` if possible. Return the total number of bytes sent. @@ -964,7 +964,7 @@ convenient. DNS ^^^ -.. coroutinemethod:: loop.getaddrinfo(host, port, \*, family=0, \ +.. coroutinemethod:: loop.getaddrinfo(host, port, *, family=0, \ type=0, proto=0, flags=0) Asynchronous version of :meth:`socket.getaddrinfo`. @@ -1029,7 +1029,7 @@ Working with pipes Unix signals ^^^^^^^^^^^^ -.. method:: loop.add_signal_handler(signum, callback, \*args) +.. method:: loop.add_signal_handler(signum, callback, *args) Set *callback* as the handler for the *signum* signal. @@ -1064,7 +1064,7 @@ Unix signals Executing code in thread or process pools ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -.. awaitablemethod:: loop.run_in_executor(executor, func, \*args) +.. awaitablemethod:: loop.run_in_executor(executor, func, *args) Arrange for *func* to be called in the specified executor. @@ -1234,9 +1234,9 @@ async/await code consider using the high-level subprocesses. See :ref:`Subprocess Support on Windows ` for details. -.. coroutinemethod:: loop.subprocess_exec(protocol_factory, \*args, \ +.. coroutinemethod:: loop.subprocess_exec(protocol_factory, *args, \ stdin=subprocess.PIPE, stdout=subprocess.PIPE, \ - stderr=subprocess.PIPE, \*\*kwargs) + stderr=subprocess.PIPE, **kwargs) Create a subprocess from one or more string arguments specified by *args*. @@ -1316,9 +1316,9 @@ async/await code consider using the high-level conforms to the :class:`asyncio.SubprocessTransport` base class and *protocol* is an object instantiated by the *protocol_factory*. -.. coroutinemethod:: loop.subprocess_shell(protocol_factory, cmd, \*, \ +.. coroutinemethod:: loop.subprocess_shell(protocol_factory, cmd, *, \ stdin=subprocess.PIPE, stdout=subprocess.PIPE, \ - stderr=subprocess.PIPE, \*\*kwargs) + stderr=subprocess.PIPE, **kwargs) Create a subprocess from *cmd*, which can be a :class:`str` or a :class:`bytes` string encoded to the diff --git a/Doc/library/asyncio-future.rst b/Doc/library/asyncio-future.rst index e1ac18eaf09882..939d4c1a84523a 100644 --- a/Doc/library/asyncio-future.rst +++ b/Doc/library/asyncio-future.rst @@ -31,7 +31,7 @@ Future Functions .. versionadded:: 3.5 -.. function:: ensure_future(obj, \*, loop=None) +.. function:: ensure_future(obj, *, loop=None) Return: @@ -58,7 +58,7 @@ Future Functions The function accepts any :term:`awaitable` object. -.. function:: wrap_future(future, \*, loop=None) +.. function:: wrap_future(future, *, loop=None) Wrap a :class:`concurrent.futures.Future` object in a :class:`asyncio.Future` object. @@ -67,7 +67,7 @@ Future Functions Future Object ============= -.. class:: Future(\*, loop=None) +.. class:: Future(*, loop=None) A Future represents an eventual result of an asynchronous operation. Not thread-safe. diff --git a/Doc/library/asyncio-policy.rst b/Doc/library/asyncio-policy.rst index 5e69525e90dd27..ef6a0588506b52 100644 --- a/Doc/library/asyncio-policy.rst +++ b/Doc/library/asyncio-policy.rst @@ -159,7 +159,7 @@ implementation used by the asyncio event loop: .. class:: AbstractChildWatcher - .. method:: add_child_handler(pid, callback, \*args) + .. method:: add_child_handler(pid, callback, *args) Register a new child handler. diff --git a/Doc/library/asyncio-stream.rst b/Doc/library/asyncio-stream.rst index b76ed379c7f4c8..584bf10fc042bc 100644 --- a/Doc/library/asyncio-stream.rst +++ b/Doc/library/asyncio-stream.rst @@ -48,7 +48,7 @@ The following top-level asyncio functions can be used to create and work with streams: -.. coroutinefunction:: open_connection(host=None, port=None, \*, \ +.. coroutinefunction:: open_connection(host=None, port=None, *, \ loop=None, limit=None, ssl=None, family=0, \ proto=0, flags=0, sock=None, local_addr=None, \ server_hostname=None, ssl_handshake_timeout=None) @@ -74,7 +74,7 @@ and work with streams: The *ssl_handshake_timeout* parameter. .. coroutinefunction:: start_server(client_connected_cb, host=None, \ - port=None, \*, loop=None, limit=None, \ + port=None, *, loop=None, limit=None, \ family=socket.AF_UNSPEC, \ flags=socket.AI_PASSIVE, sock=None, \ backlog=100, ssl=None, reuse_address=None, \ @@ -109,7 +109,7 @@ and work with streams: .. rubric:: Unix Sockets -.. coroutinefunction:: open_unix_connection(path=None, \*, loop=None, \ +.. coroutinefunction:: open_unix_connection(path=None, *, loop=None, \ limit=None, ssl=None, sock=None, \ server_hostname=None, ssl_handshake_timeout=None) @@ -132,7 +132,7 @@ and work with streams: .. coroutinefunction:: start_unix_server(client_connected_cb, path=None, \ - \*, loop=None, limit=None, sock=None, \ + *, loop=None, limit=None, sock=None, \ backlog=100, ssl=None, ssl_handshake_timeout=None, \ start_serving=True) @@ -192,7 +192,7 @@ StreamReader can be read. Use the :attr:`IncompleteReadError.partial` attribute to get the partially read data. - .. coroutinemethod:: readuntil(separator=b'\\n') + .. coroutinemethod:: readuntil(separator=b'\n') Read data from the stream until *separator* is found. diff --git a/Doc/library/asyncio-subprocess.rst b/Doc/library/asyncio-subprocess.rst index b0330349dfb651..fb98552c86d4c1 100644 --- a/Doc/library/asyncio-subprocess.rst +++ b/Doc/library/asyncio-subprocess.rst @@ -61,9 +61,9 @@ See also the `Examples`_ subsection. Creating Subprocesses ===================== -.. coroutinefunction:: create_subprocess_exec(program, \*args, stdin=None, \ +.. coroutinefunction:: create_subprocess_exec(program, *args, stdin=None, \ stdout=None, stderr=None, loop=None, \ - limit=None, \*\*kwds) + limit=None, **kwds) Create a subprocess. @@ -82,7 +82,7 @@ Creating Subprocesses .. coroutinefunction:: create_subprocess_shell(cmd, stdin=None, \ stdout=None, stderr=None, loop=None, \ - limit=None, \*\*kwds) + limit=None, **kwds) Run the *cmd* shell command. diff --git a/Doc/library/asyncio-task.rst b/Doc/library/asyncio-task.rst index c638f1263fdaa1..201678b0a3d57e 100644 --- a/Doc/library/asyncio-task.rst +++ b/Doc/library/asyncio-task.rst @@ -210,7 +210,7 @@ is :meth:`loop.run_in_executor`. Running an asyncio Program ========================== -.. function:: run(coro, \*, debug=False) +.. function:: run(coro, *, debug=False) Execute the :term:`coroutine` *coro* and return the result. @@ -247,7 +247,7 @@ Running an asyncio Program Creating Tasks ============== -.. function:: create_task(coro, \*, name=None) +.. function:: create_task(coro, *, name=None) Wrap the *coro* :ref:`coroutine ` into a :class:`Task` and schedule its execution. Return the Task object. @@ -283,7 +283,7 @@ Creating Tasks Sleeping ======== -.. coroutinefunction:: sleep(delay, result=None, \*, loop=None) +.. coroutinefunction:: sleep(delay, result=None, *, loop=None) Block for *delay* seconds. @@ -319,7 +319,7 @@ Sleeping Running Tasks Concurrently ========================== -.. awaitablefunction:: gather(\*aws, loop=None, return_exceptions=False) +.. awaitablefunction:: gather(*aws, loop=None, return_exceptions=False) Run :ref:`awaitable objects ` in the *aws* sequence *concurrently*. @@ -403,7 +403,7 @@ Running Tasks Concurrently Shielding From Cancellation =========================== -.. awaitablefunction:: shield(aw, \*, loop=None) +.. awaitablefunction:: shield(aw, *, loop=None) Protect an :ref:`awaitable object ` from being :meth:`cancelled `. @@ -443,7 +443,7 @@ Shielding From Cancellation Timeouts ======== -.. coroutinefunction:: wait_for(aw, timeout, \*, loop=None) +.. coroutinefunction:: wait_for(aw, timeout, *, loop=None) Wait for the *aw* :ref:`awaitable ` to complete with a timeout. @@ -500,7 +500,7 @@ Timeouts Waiting Primitives ================== -.. coroutinefunction:: wait(aws, \*, loop=None, timeout=None,\ +.. coroutinefunction:: wait(aws, *, loop=None, timeout=None,\ return_when=ALL_COMPLETED) Run :ref:`awaitable objects ` in the *aws* @@ -590,7 +590,7 @@ Waiting Primitives deprecated. -.. function:: as_completed(aws, \*, loop=None, timeout=None) +.. function:: as_completed(aws, *, loop=None, timeout=None) Run :ref:`awaitable objects ` in the *aws* iterable concurrently. Return an iterator of coroutines. @@ -613,7 +613,7 @@ Waiting Primitives Running in Threads ================== -.. coroutinefunction:: to_thread(func, /, \*args, \*\*kwargs) +.. coroutinefunction:: to_thread(func, /, *args, **kwargs) Asynchronously run function *func* in a separate thread. @@ -743,7 +743,7 @@ Introspection Task Object =========== -.. class:: Task(coro, \*, loop=None, name=None) +.. class:: Task(coro, *, loop=None, name=None) A :class:`Future-like ` object that runs a Python :ref:`coroutine `. Not thread-safe. @@ -909,7 +909,7 @@ Task Object See the documentation of :meth:`Future.remove_done_callback` for more details. - .. method:: get_stack(\*, limit=None) + .. method:: get_stack(*, limit=None) Return the list of stack frames for this Task. @@ -930,7 +930,7 @@ Task Object stack are returned, but the oldest frames of a traceback are returned. (This matches the behavior of the traceback module.) - .. method:: print_stack(\*, limit=None, file=None) + .. method:: print_stack(*, limit=None, file=None) Print the stack or traceback for this Task. diff --git a/Doc/library/base64.rst b/Doc/library/base64.rst index 1ff22a00d6199d..e6934431626a36 100644 --- a/Doc/library/base64.rst +++ b/Doc/library/base64.rst @@ -178,7 +178,7 @@ The modern interface provides: .. versionadded:: 3.4 -.. function:: a85decode(b, *, foldspaces=False, adobe=False, ignorechars=b' \\t\\n\\r\\v') +.. function:: a85decode(b, *, foldspaces=False, adobe=False, ignorechars=b' \t\n\r\v') Decode the Ascii85 encoded :term:`bytes-like object` or ASCII string *b* and return the decoded :class:`bytes`. diff --git a/Doc/library/compileall.rst b/Doc/library/compileall.rst index 9b914b1f0d9c6d..5c6e68f9304753 100644 --- a/Doc/library/compileall.rst +++ b/Doc/library/compileall.rst @@ -148,7 +148,7 @@ runtime. Public functions ---------------- -.. function:: compile_dir(dir, maxlevels=sys.getrecursionlimit(), ddir=None, force=False, rx=None, quiet=0, legacy=False, optimize=-1, workers=1, invalidation_mode=None, \*, stripdir=None, prependdir=None, limit_sl_dest=None, hardlink_dupes=False) +.. function:: compile_dir(dir, maxlevels=sys.getrecursionlimit(), ddir=None, force=False, rx=None, quiet=0, legacy=False, optimize=-1, workers=1, invalidation_mode=None, *, stripdir=None, prependdir=None, limit_sl_dest=None, hardlink_dupes=False) Recursively descend the directory tree named by *dir*, compiling all :file:`.py` files along the way. Return a true value if all the files compiled successfully, @@ -231,7 +231,7 @@ Public functions Added *stripdir*, *prependdir*, *limit_sl_dest* and *hardlink_dupes* arguments. Default value of *maxlevels* was changed from ``10`` to ``sys.getrecursionlimit()`` -.. function:: compile_file(fullname, ddir=None, force=False, rx=None, quiet=0, legacy=False, optimize=-1, invalidation_mode=None, \*, stripdir=None, prependdir=None, limit_sl_dest=None, hardlink_dupes=False) +.. function:: compile_file(fullname, ddir=None, force=False, rx=None, quiet=0, legacy=False, optimize=-1, invalidation_mode=None, *, stripdir=None, prependdir=None, limit_sl_dest=None, hardlink_dupes=False) Compile the file with path *fullname*. Return a true value if the file compiled successfully, and a false value otherwise. diff --git a/Doc/library/concurrent.futures.rst b/Doc/library/concurrent.futures.rst index 61d6c1143cfdd5..d57f8ce23d12c4 100644 --- a/Doc/library/concurrent.futures.rst +++ b/Doc/library/concurrent.futures.rst @@ -67,7 +67,7 @@ Executor Objects .. versionchanged:: 3.5 Added the *chunksize* argument. - .. method:: shutdown(wait=True, \*, cancel_futures=False) + .. method:: shutdown(wait=True, *, cancel_futures=False) Signal the executor that it should free any resources that it is using when the currently pending futures are done executing. Calls to diff --git a/Doc/library/contextvars.rst b/Doc/library/contextvars.rst index 8805661c456edb..14ac47f4c9eb16 100644 --- a/Doc/library/contextvars.rst +++ b/Doc/library/contextvars.rst @@ -26,7 +26,7 @@ See also :pep:`567` for additional details. Context Variables ----------------- -.. class:: ContextVar(name, [\*, default]) +.. class:: ContextVar(name, [*, default]) This class is used to declare a new Context Variable, e.g.:: @@ -146,7 +146,7 @@ Manual Context Management Context implements the :class:`collections.abc.Mapping` interface. - .. method:: run(callable, \*args, \*\*kwargs) + .. method:: run(callable, *args, **kwargs) Execute ``callable(*args, **kwargs)`` code in the context object the *run* method is called on. Return the result of the execution diff --git a/Doc/library/ctypes.rst b/Doc/library/ctypes.rst index bf32d3e549b480..7313148721dac6 100644 --- a/Doc/library/ctypes.rst +++ b/Doc/library/ctypes.rst @@ -2508,7 +2508,7 @@ other data types containing pointer type fields. Arrays and pointers ^^^^^^^^^^^^^^^^^^^ -.. class:: Array(\*args) +.. class:: Array(*args) Abstract base class for arrays. diff --git a/Doc/library/difflib.rst b/Doc/library/difflib.rst index aa08988c8b36f7..a5ee0fb5389793 100644 --- a/Doc/library/difflib.rst +++ b/Doc/library/difflib.rst @@ -149,7 +149,7 @@ diffs. For comparing directories and files, see also, the :mod:`filecmp` module. contains a good example of its use. -.. function:: context_diff(a, b, fromfile='', tofile='', fromfiledate='', tofiledate='', n=3, lineterm='\\n') +.. function:: context_diff(a, b, fromfile='', tofile='', fromfiledate='', tofiledate='', n=3, lineterm='\n') Compare *a* and *b* (lists of strings); return a delta (a :term:`generator` generating the delta lines) in context diff format. @@ -279,7 +279,7 @@ diffs. For comparing directories and files, see also, the :mod:`filecmp` module. emu -.. function:: unified_diff(a, b, fromfile='', tofile='', fromfiledate='', tofiledate='', n=3, lineterm='\\n') +.. function:: unified_diff(a, b, fromfile='', tofile='', fromfiledate='', tofiledate='', n=3, lineterm='\n') Compare *a* and *b* (lists of strings); return a delta (a :term:`generator` generating the delta lines) in unified diff format. @@ -321,7 +321,7 @@ diffs. For comparing directories and files, see also, the :mod:`filecmp` module. See :ref:`difflib-interface` for a more detailed example. -.. function:: diff_bytes(dfunc, a, b, fromfile=b'', tofile=b'', fromfiledate=b'', tofiledate=b'', n=3, lineterm=b'\\n') +.. function:: diff_bytes(dfunc, a, b, fromfile=b'', tofile=b'', fromfiledate=b'', tofiledate=b'', n=3, lineterm=b'\n') Compare *a* and *b* (lists of bytes objects) using *dfunc*; yield a sequence of delta lines (also bytes) in the format returned by *dfunc*. diff --git a/Doc/library/email.header.rst b/Doc/library/email.header.rst index 07152c224f2ff0..e093f138936b36 100644 --- a/Doc/library/email.header.rst +++ b/Doc/library/email.header.rst @@ -116,7 +116,7 @@ Here is the :class:`Header` class description: if *s* is a byte string. - .. method:: encode(splitchars=';, \\t', maxlinelen=None, linesep='\\n') + .. method:: encode(splitchars=';, \t', maxlinelen=None, linesep='\n') Encode a message header into an RFC-compliant format, possibly wrapping long lines and encapsulating non-ASCII parts in base64 or quoted-printable diff --git a/Doc/library/email.policy.rst b/Doc/library/email.policy.rst index 8e7076259810f5..bf53b9520fc723 100644 --- a/Doc/library/email.policy.rst +++ b/Doc/library/email.policy.rst @@ -210,7 +210,7 @@ added matters. To illustrate:: :meth:`register_defect` method. - .. attribute:: mangle_from\_ + .. attribute:: mangle_from_ If :const:`True`, lines starting with *"From "* in the body are escaped by putting a ``>`` in front of them. This parameter is used when diff --git a/Doc/library/functions.rst b/Doc/library/functions.rst index 9c12b6c48d8ff0..548ef59a47c6da 100644 --- a/Doc/library/functions.rst +++ b/Doc/library/functions.rst @@ -1316,7 +1316,7 @@ are always available. They are listed here in alphabetical order. supported. -.. function:: print(*objects, sep=' ', end='\\n', file=sys.stdout, flush=False) +.. function:: print(*objects, sep=' ', end='\n', file=sys.stdout, flush=False) Print *objects* to the text stream *file*, separated by *sep* and followed by *end*. *sep*, *end*, *file* and *flush*, if present, must be given as keyword diff --git a/Doc/library/http.cookies.rst b/Doc/library/http.cookies.rst index 17792b200599bd..a2c1eb00d8b33d 100644 --- a/Doc/library/http.cookies.rst +++ b/Doc/library/http.cookies.rst @@ -93,7 +93,7 @@ Cookie Objects :meth:`value_decode` are inverses on the range of *value_decode*. -.. method:: BaseCookie.output(attrs=None, header='Set-Cookie:', sep='\\r\\n') +.. method:: BaseCookie.output(attrs=None, header='Set-Cookie:', sep='\r\n') Return a string representation suitable to be sent as HTTP headers. *attrs* and *header* are sent to each :class:`Morsel`'s :meth:`output` method. *sep* is used diff --git a/Doc/library/importlib.rst b/Doc/library/importlib.rst index 9027ba58acb20a..305bb54d5271d5 100644 --- a/Doc/library/importlib.rst +++ b/Doc/library/importlib.rst @@ -1135,7 +1135,7 @@ find and load modules. directory for ``''`` (i.e. the empty string). -.. class:: FileFinder(path, \*loader_details) +.. class:: FileFinder(path, *loader_details) A concrete implementation of :class:`importlib.abc.PathEntryFinder` which caches results from the file system. @@ -1178,7 +1178,7 @@ find and load modules. Clear out the internal cache. - .. classmethod:: path_hook(\*loader_details) + .. classmethod:: path_hook(*loader_details) A class method which returns a closure for use on :attr:`sys.path_hooks`. An instance of :class:`FileFinder` is returned by the closure using the diff --git a/Doc/library/inspect.rst b/Doc/library/inspect.rst index d00a30ff004063..b53a9421fbca61 100644 --- a/Doc/library/inspect.rst +++ b/Doc/library/inspect.rst @@ -556,7 +556,7 @@ The Signature object represents the call signature of a callable object and its return annotation. To retrieve a Signature object, use the :func:`signature` function. -.. function:: signature(callable, \*, follow_wrapped=True) +.. function:: signature(callable, *, follow_wrapped=True) Return a :class:`Signature` object for the given ``callable``:: @@ -597,7 +597,7 @@ function. C provide no metadata about their arguments. -.. class:: Signature(parameters=None, \*, return_annotation=Signature.empty) +.. class:: Signature(parameters=None, *, return_annotation=Signature.empty) A Signature object represents the call signature of a function and its return annotation. For each parameter accepted by the function it stores a @@ -668,7 +668,7 @@ function. >>> str(new_sig) "(a, b) -> 'new return anno'" - .. classmethod:: Signature.from_callable(obj, \*, follow_wrapped=True) + .. classmethod:: Signature.from_callable(obj, *, follow_wrapped=True) Return a :class:`Signature` (or its subclass) object for a given callable ``obj``. Pass ``follow_wrapped=False`` to get a signature of ``obj`` @@ -684,7 +684,7 @@ function. .. versionadded:: 3.5 -.. class:: Parameter(name, kind, \*, default=Parameter.empty, annotation=Parameter.empty) +.. class:: Parameter(name, kind, *, default=Parameter.empty, annotation=Parameter.empty) Parameter objects are *immutable*. Instead of modifying a Parameter object, you can use :meth:`Parameter.replace` to create a modified copy. diff --git a/Doc/library/io.rst b/Doc/library/io.rst index aecbec56866d73..048cb2a7ff6924 100644 --- a/Doc/library/io.rst +++ b/Doc/library/io.rst @@ -964,7 +964,7 @@ Text I/O .. versionadded:: 3.7 -.. class:: StringIO(initial_value='', newline='\\n') +.. class:: StringIO(initial_value='', newline='\n') A text stream using an in-memory text buffer. It inherits :class:`TextIOBase`. diff --git a/Doc/library/lzma.rst b/Doc/library/lzma.rst index 4bfff9c6147ed4..633c87873cd8ce 100644 --- a/Doc/library/lzma.rst +++ b/Doc/library/lzma.rst @@ -33,7 +33,7 @@ from multiple threads, it is necessary to protect it with a lock. Reading and writing compressed files ------------------------------------ -.. function:: open(filename, mode="rb", \*, format=None, check=-1, preset=None, filters=None, encoding=None, errors=None, newline=None) +.. function:: open(filename, mode="rb", *, format=None, check=-1, preset=None, filters=None, encoding=None, errors=None, newline=None) Open an LZMA-compressed file in binary or text mode, returning a :term:`file object`. @@ -69,7 +69,7 @@ Reading and writing compressed files Accepts a :term:`path-like object`. -.. class:: LZMAFile(filename=None, mode="r", \*, format=None, check=-1, preset=None, filters=None) +.. class:: LZMAFile(filename=None, mode="r", *, format=None, check=-1, preset=None, filters=None) Open an LZMA-compressed file in binary mode. diff --git a/Doc/library/os.rst b/Doc/library/os.rst index 6e287abb6f78aa..9d206f46aebeb2 100644 --- a/Doc/library/os.rst +++ b/Doc/library/os.rst @@ -1869,7 +1869,7 @@ features: Accepts a :term:`path-like object`. -.. function:: lstat(path, \*, dir_fd=None) +.. function:: lstat(path, *, dir_fd=None) Perform the equivalent of an :c:func:`lstat` system call on the given path. Similar to :func:`~os.stat`, but does not follow symbolic links. Return a @@ -2376,7 +2376,7 @@ features: On the first, uncached call, a system call is required on Windows but not on Unix. - .. method:: is_dir(\*, follow_symlinks=True) + .. method:: is_dir(*, follow_symlinks=True) Return ``True`` if this entry is a directory or a symbolic link pointing to a directory; return ``False`` if the entry is or points to any other @@ -2400,7 +2400,7 @@ features: This method can raise :exc:`OSError`, such as :exc:`PermissionError`, but :exc:`FileNotFoundError` is caught and not raised. - .. method:: is_file(\*, follow_symlinks=True) + .. method:: is_file(*, follow_symlinks=True) Return ``True`` if this entry is a file or a symbolic link pointing to a file; return ``False`` if the entry is or points to a directory or other @@ -2430,7 +2430,7 @@ features: This method can raise :exc:`OSError`, such as :exc:`PermissionError`, but :exc:`FileNotFoundError` is caught and not raised. - .. method:: stat(\*, follow_symlinks=True) + .. method:: stat(*, follow_symlinks=True) Return a :class:`stat_result` object for this entry. This method follows symbolic links by default; to stat a symbolic link add the @@ -2462,7 +2462,7 @@ features: for :class:`bytes` paths on Windows. -.. function:: stat(path, \*, dir_fd=None, follow_symlinks=True) +.. function:: stat(path, *, dir_fd=None, follow_symlinks=True) Get the status of a file or a file descriptor. Perform the equivalent of a :c:func:`stat` system call on the given path. *path* may be specified as diff --git a/Doc/library/pickle.rst b/Doc/library/pickle.rst index b7c34527719486..be48561ed10ac8 100644 --- a/Doc/library/pickle.rst +++ b/Doc/library/pickle.rst @@ -213,7 +213,7 @@ The :mod:`pickle` module provides the following constants: The :mod:`pickle` module provides the following functions to make the pickling process more convenient: -.. function:: dump(obj, file, protocol=None, \*, fix_imports=True, buffer_callback=None) +.. function:: dump(obj, file, protocol=None, *, fix_imports=True, buffer_callback=None) Write the pickled representation of the object *obj* to the open :term:`file object` *file*. This is equivalent to @@ -225,7 +225,7 @@ process more convenient: .. versionchanged:: 3.8 The *buffer_callback* argument was added. -.. function:: dumps(obj, protocol=None, \*, fix_imports=True, buffer_callback=None) +.. function:: dumps(obj, protocol=None, *, fix_imports=True, buffer_callback=None) Return the pickled representation of the object *obj* as a :class:`bytes` object, instead of writing it to a file. @@ -236,7 +236,7 @@ process more convenient: .. versionchanged:: 3.8 The *buffer_callback* argument was added. -.. function:: load(file, \*, fix_imports=True, encoding="ASCII", errors="strict", buffers=None) +.. function:: load(file, *, fix_imports=True, encoding="ASCII", errors="strict", buffers=None) Read the pickled representation of an object from the open :term:`file object` *file* and return the reconstituted object hierarchy specified therein. @@ -252,7 +252,7 @@ process more convenient: .. versionchanged:: 3.8 The *buffers* argument was added. -.. function:: loads(data, /, \*, fix_imports=True, encoding="ASCII", errors="strict", buffers=None) +.. function:: loads(data, /, *, fix_imports=True, encoding="ASCII", errors="strict", buffers=None) Return the reconstituted object hierarchy of the pickled representation *data* of an object. *data* must be a :term:`bytes-like object`. @@ -296,7 +296,7 @@ The :mod:`pickle` module defines three exceptions: The :mod:`pickle` module exports three classes, :class:`Pickler`, :class:`Unpickler` and :class:`PickleBuffer`: -.. class:: Pickler(file, protocol=None, \*, fix_imports=True, buffer_callback=None) +.. class:: Pickler(file, protocol=None, *, fix_imports=True, buffer_callback=None) This takes a binary file for writing a pickle data stream. @@ -391,7 +391,7 @@ The :mod:`pickle` module exports three classes, :class:`Pickler`, Use :func:`pickletools.optimize` if you need more compact pickles. -.. class:: Unpickler(file, \*, fix_imports=True, encoding="ASCII", errors="strict", buffers=None) +.. class:: Unpickler(file, *, fix_imports=True, encoding="ASCII", errors="strict", buffers=None) This takes a binary file for reading a pickle data stream. diff --git a/Doc/library/plistlib.rst b/Doc/library/plistlib.rst index 6def72b3736b91..ce6d4a85bf5e9d 100644 --- a/Doc/library/plistlib.rst +++ b/Doc/library/plistlib.rst @@ -52,7 +52,7 @@ or :class:`datetime.datetime` objects. This module defines the following functions: -.. function:: load(fp, \*, fmt=None, dict_type=dict) +.. function:: load(fp, *, fmt=None, dict_type=dict) Read a plist file. *fp* should be a readable and binary file object. Return the unpacked root object (which usually is a @@ -80,7 +80,7 @@ This module defines the following functions: .. versionadded:: 3.4 -.. function:: loads(data, \*, fmt=None, dict_type=dict) +.. function:: loads(data, *, fmt=None, dict_type=dict) Load a plist from a bytes object. See :func:`load` for an explanation of the keyword arguments. @@ -88,7 +88,7 @@ This module defines the following functions: .. versionadded:: 3.4 -.. function:: dump(value, fp, \*, fmt=FMT_XML, sort_keys=True, skipkeys=False) +.. function:: dump(value, fp, *, fmt=FMT_XML, sort_keys=True, skipkeys=False) Write *value* to a plist file. *Fp* should be a writable, binary file object. @@ -116,7 +116,7 @@ This module defines the following functions: .. versionadded:: 3.4 -.. function:: dumps(value, \*, fmt=FMT_XML, sort_keys=True, skipkeys=False) +.. function:: dumps(value, *, fmt=FMT_XML, sort_keys=True, skipkeys=False) Return *value* as a plist-formatted bytes object. See the documentation for :func:`dump` for an explanation of the keyword diff --git a/Doc/library/shutil.rst b/Doc/library/shutil.rst index 3f5122760ee16f..435787c27661d5 100644 --- a/Doc/library/shutil.rst +++ b/Doc/library/shutil.rst @@ -218,7 +218,7 @@ Directory and files operations copy the file more efficiently. See :ref:`shutil-platform-dependent-efficient-copy-operations` section. -.. function:: ignore_patterns(\*patterns) +.. function:: ignore_patterns(*patterns) This factory function creates a function that can be used as a callable for :func:`copytree`\'s *ignore* argument, ignoring files and directories that diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst index 59200730a48f5d..0667a601576165 100644 --- a/Doc/library/stdtypes.rst +++ b/Doc/library/stdtypes.rst @@ -478,7 +478,7 @@ class`. In addition, it provides a few more methods: .. versionadded:: 3.1 -.. method:: int.to_bytes(length, byteorder, \*, signed=False) +.. method:: int.to_bytes(length, byteorder, *, signed=False) Return an array of bytes representing an integer. @@ -510,7 +510,7 @@ class`. In addition, it provides a few more methods: .. versionadded:: 3.2 -.. classmethod:: int.from_bytes(bytes, byteorder, \*, signed=False) +.. classmethod:: int.from_bytes(bytes, byteorder, *, signed=False) Return the integer represented by the given array of bytes. diff --git a/Doc/library/subprocess.rst b/Doc/library/subprocess.rst index e37cc980e97575..382ce85516dfbe 100644 --- a/Doc/library/subprocess.rst +++ b/Doc/library/subprocess.rst @@ -339,7 +339,7 @@ functions. stderr=None, preexec_fn=None, close_fds=True, shell=False, \ cwd=None, env=None, universal_newlines=None, \ startupinfo=None, creationflags=0, restore_signals=True, \ - start_new_session=False, pass_fds=(), \*, group=None, \ + start_new_session=False, pass_fds=(), *, group=None, \ extra_groups=None, user=None, umask=-1, \ encoding=None, errors=None, text=None) diff --git a/Doc/library/sysconfig.rst b/Doc/library/sysconfig.rst index 78a1dfce9ae05c..c9306e9bf9de16 100644 --- a/Doc/library/sysconfig.rst +++ b/Doc/library/sysconfig.rst @@ -32,7 +32,7 @@ can be accessed using :func:`get_config_vars` or :func:`get_config_var`. Notice that on Windows, it's a much smaller set. -.. function:: get_config_vars(\*args) +.. function:: get_config_vars(*args) With no arguments, return a dictionary of all configuration variables relevant for the current platform. diff --git a/Doc/library/tarfile.rst b/Doc/library/tarfile.rst index 7a114fdf5d54b1..13088a10d77c57 100644 --- a/Doc/library/tarfile.rst +++ b/Doc/library/tarfile.rst @@ -37,7 +37,7 @@ Some facts and figures: Added support for :mod:`lzma` compression. -.. function:: open(name=None, mode='r', fileobj=None, bufsize=10240, \*\*kwargs) +.. function:: open(name=None, mode='r', fileobj=None, bufsize=10240, **kwargs) Return a :class:`TarFile` object for the pathname *name*. For detailed information on :class:`TarFile` objects and the keyword arguments that are diff --git a/Doc/library/test.rst b/Doc/library/test.rst index e24f69cda8c868..bb1bd29bf698ed 100644 --- a/Doc/library/test.rst +++ b/Doc/library/test.rst @@ -546,7 +546,7 @@ The :mod:`test.support` module defines the following functions: Define match test with regular expression *patterns*. -.. function:: run_unittest(\*classes) +.. function:: run_unittest(*classes) Execute :class:`unittest.TestCase` subclasses passed to the function. The function scans the classes for methods starting with the prefix ``test_`` diff --git a/Doc/library/warnings.rst b/Doc/library/warnings.rst index a481a3509d4ec8..9c1743cad23cb7 100644 --- a/Doc/library/warnings.rst +++ b/Doc/library/warnings.rst @@ -491,7 +491,7 @@ Available Functions Available Context Managers -------------------------- -.. class:: catch_warnings(\*, record=False, module=None) +.. class:: catch_warnings(*, record=False, module=None) A context manager that copies and, upon exit, restores the warnings filter and the :func:`showwarning` function. diff --git a/Doc/library/winreg.rst b/Doc/library/winreg.rst index dccb7db27e90cc..487856a3ac6c60 100644 --- a/Doc/library/winreg.rst +++ b/Doc/library/winreg.rst @@ -791,7 +791,7 @@ integer handle, and also disconnect the Windows handle from the handle object. .. method:: PyHKEY.__enter__() - PyHKEY.__exit__(\*exc_info) + PyHKEY.__exit__(*exc_info) The HKEY object implements :meth:`~object.__enter__` and :meth:`~object.__exit__` and thus supports the context protocol for the diff --git a/Doc/library/xml.dom.minidom.rst b/Doc/library/xml.dom.minidom.rst index bf72c46561b7c7..e1cc96794221ad 100644 --- a/Doc/library/xml.dom.minidom.rst +++ b/Doc/library/xml.dom.minidom.rst @@ -174,7 +174,7 @@ module documentation. This section lists the differences between the API and The :meth:`toxml` method now preserves the attribute order specified by the user. -.. method:: Node.toprettyxml(indent="\\t", newl="\\n", encoding=None, \ +.. method:: Node.toprettyxml(indent="\t", newl="\n", encoding=None, \ standalone=None) Return a pretty-printed version of the document. *indent* specifies the From 7c48859eeb98f698b65bcc001afc64422387ec34 Mon Sep 17 00:00:00 2001 From: Andre Delfino Date: Mon, 21 Dec 2020 23:53:50 -0300 Subject: [PATCH 0832/1314] [3.9] [doc] Fix a few margins due to bad markup (GH-23619). (GH-23859) (cherry picked from commit 96a09df64483b70c4215c7025a19b9d2f1636c55) Co-authored-by: Andre Delfino --- Doc/library/dialog.rst | 2 +- Doc/library/enum.rst | 2 +- Doc/library/logging.config.rst | 78 +++++++++++++++++----------------- Doc/library/profile.rst | 6 +-- Doc/library/socket.rst | 10 ++--- Doc/library/trace.rst | 50 +++++++++++----------- Doc/library/turtle.rst | 12 +++--- Doc/reference/datamodel.rst | 1 - 8 files changed, 80 insertions(+), 81 deletions(-) diff --git a/Doc/library/dialog.rst b/Doc/library/dialog.rst index dc82a974ce095d..53f98c1018988f 100644 --- a/Doc/library/dialog.rst +++ b/Doc/library/dialog.rst @@ -198,7 +198,7 @@ These do not emulate the native look-and-feel of the platform. A subclass of FileDialog that creates a dialog window for selecting a destination file. - .. method:: ok_command() + .. method:: ok_command() Test whether or not the selection points to a valid file that is not a directory. Confirmation is required if an already existing file is diff --git a/Doc/library/enum.rst b/Doc/library/enum.rst index 4ecca209d87b3d..8836b24912e9e3 100644 --- a/Doc/library/enum.rst +++ b/Doc/library/enum.rst @@ -56,7 +56,7 @@ helper, :class:`auto`. the bitwise operations without losing their :class:`Flag` membership. .. function:: unique - :noindex: + :noindex: Enum class decorator that ensures only one name is bound to any one value. diff --git a/Doc/library/logging.config.rst b/Doc/library/logging.config.rst index 683d6ed5e8ba52..0b5e2fc2a658d5 100644 --- a/Doc/library/logging.config.rst +++ b/Doc/library/logging.config.rst @@ -35,45 +35,45 @@ in :mod:`logging` itself) and defining handlers which are declared either in .. function:: dictConfig(config) - Takes the logging configuration from a dictionary. The contents of - this dictionary are described in :ref:`logging-config-dictschema` - below. - - If an error is encountered during configuration, this function will - raise a :exc:`ValueError`, :exc:`TypeError`, :exc:`AttributeError` - or :exc:`ImportError` with a suitably descriptive message. The - following is a (possibly incomplete) list of conditions which will - raise an error: - - * A ``level`` which is not a string or which is a string not - corresponding to an actual logging level. - * A ``propagate`` value which is not a boolean. - * An id which does not have a corresponding destination. - * A non-existent handler id found during an incremental call. - * An invalid logger name. - * Inability to resolve to an internal or external object. - - Parsing is performed by the :class:`DictConfigurator` class, whose - constructor is passed the dictionary used for configuration, and - has a :meth:`configure` method. The :mod:`logging.config` module - has a callable attribute :attr:`dictConfigClass` - which is initially set to :class:`DictConfigurator`. - You can replace the value of :attr:`dictConfigClass` with a - suitable implementation of your own. - - :func:`dictConfig` calls :attr:`dictConfigClass` passing - the specified dictionary, and then calls the :meth:`configure` method on - the returned object to put the configuration into effect:: - - def dictConfig(config): - dictConfigClass(config).configure() - - For example, a subclass of :class:`DictConfigurator` could call - ``DictConfigurator.__init__()`` in its own :meth:`__init__()`, then - set up custom prefixes which would be usable in the subsequent - :meth:`configure` call. :attr:`dictConfigClass` would be bound to - this new subclass, and then :func:`dictConfig` could be called exactly as - in the default, uncustomized state. + Takes the logging configuration from a dictionary. The contents of + this dictionary are described in :ref:`logging-config-dictschema` + below. + + If an error is encountered during configuration, this function will + raise a :exc:`ValueError`, :exc:`TypeError`, :exc:`AttributeError` + or :exc:`ImportError` with a suitably descriptive message. The + following is a (possibly incomplete) list of conditions which will + raise an error: + + * A ``level`` which is not a string or which is a string not + corresponding to an actual logging level. + * A ``propagate`` value which is not a boolean. + * An id which does not have a corresponding destination. + * A non-existent handler id found during an incremental call. + * An invalid logger name. + * Inability to resolve to an internal or external object. + + Parsing is performed by the :class:`DictConfigurator` class, whose + constructor is passed the dictionary used for configuration, and + has a :meth:`configure` method. The :mod:`logging.config` module + has a callable attribute :attr:`dictConfigClass` + which is initially set to :class:`DictConfigurator`. + You can replace the value of :attr:`dictConfigClass` with a + suitable implementation of your own. + + :func:`dictConfig` calls :attr:`dictConfigClass` passing + the specified dictionary, and then calls the :meth:`configure` method on + the returned object to put the configuration into effect:: + + def dictConfig(config): + dictConfigClass(config).configure() + + For example, a subclass of :class:`DictConfigurator` could call + ``DictConfigurator.__init__()`` in its own :meth:`__init__()`, then + set up custom prefixes which would be usable in the subsequent + :meth:`configure` call. :attr:`dictConfigClass` would be bound to + this new subclass, and then :func:`dictConfig` could be called exactly as + in the default, uncustomized state. .. versionadded:: 3.2 diff --git a/Doc/library/profile.rst b/Doc/library/profile.rst index 7edabfde0d7f18..774d46d0e96247 100644 --- a/Doc/library/profile.rst +++ b/Doc/library/profile.rst @@ -532,9 +532,9 @@ Analysis of the profiler data is done using the :class:`~pstats.Stats` class. instance holds information related to the function's profile such as how long the function took to run, how many times it was called, etc... - .. versionadded:: 3.9 - Added the following dataclasses: StatsProfile, FunctionProfile. - Added the following function: get_stats_profile. + .. versionadded:: 3.9 + Added the following dataclasses: StatsProfile, FunctionProfile. + Added the following function: get_stats_profile. .. _deterministic-profiling: diff --git a/Doc/library/socket.rst b/Doc/library/socket.rst index faf8a76251420e..2fc170a0bc0bd3 100755 --- a/Doc/library/socket.rst +++ b/Doc/library/socket.rst @@ -56,12 +56,12 @@ created. Socket addresses are represented as follows: bytes-like object can be used for either type of address when passing it as an argument. - .. versionchanged:: 3.3 - Previously, :const:`AF_UNIX` socket paths were assumed to use UTF-8 - encoding. + .. versionchanged:: 3.3 + Previously, :const:`AF_UNIX` socket paths were assumed to use UTF-8 + encoding. - .. versionchanged:: 3.5 - Writable :term:`bytes-like object` is now accepted. + .. versionchanged:: 3.5 + Writable :term:`bytes-like object` is now accepted. .. _host_port: diff --git a/Doc/library/trace.rst b/Doc/library/trace.rst index c2732d900bc138..40cf198f1287d7 100644 --- a/Doc/library/trace.rst +++ b/Doc/library/trace.rst @@ -153,47 +153,47 @@ Programmatic Interface count information. *timing* enables a timestamp relative to when tracing was started to be displayed. - .. method:: run(cmd) + .. method:: run(cmd) - Execute the command and gather statistics from the execution with - the current tracing parameters. *cmd* must be a string or code object, - suitable for passing into :func:`exec`. + Execute the command and gather statistics from the execution with + the current tracing parameters. *cmd* must be a string or code object, + suitable for passing into :func:`exec`. - .. method:: runctx(cmd, globals=None, locals=None) + .. method:: runctx(cmd, globals=None, locals=None) - Execute the command and gather statistics from the execution with the - current tracing parameters, in the defined global and local - environments. If not defined, *globals* and *locals* default to empty - dictionaries. + Execute the command and gather statistics from the execution with the + current tracing parameters, in the defined global and local + environments. If not defined, *globals* and *locals* default to empty + dictionaries. - .. method:: runfunc(func, /, *args, **kwds) + .. method:: runfunc(func, /, *args, **kwds) - Call *func* with the given arguments under control of the :class:`Trace` - object with the current tracing parameters. + Call *func* with the given arguments under control of the :class:`Trace` + object with the current tracing parameters. - .. method:: results() + .. method:: results() - Return a :class:`CoverageResults` object that contains the cumulative - results of all previous calls to ``run``, ``runctx`` and ``runfunc`` - for the given :class:`Trace` instance. Does not reset the accumulated - trace results. + Return a :class:`CoverageResults` object that contains the cumulative + results of all previous calls to ``run``, ``runctx`` and ``runfunc`` + for the given :class:`Trace` instance. Does not reset the accumulated + trace results. .. class:: CoverageResults A container for coverage results, created by :meth:`Trace.results`. Should not be created directly by the user. - .. method:: update(other) + .. method:: update(other) - Merge in data from another :class:`CoverageResults` object. + Merge in data from another :class:`CoverageResults` object. - .. method:: write_results(show_missing=True, summary=False, coverdir=None) + .. method:: write_results(show_missing=True, summary=False, coverdir=None) - Write coverage results. Set *show_missing* to show lines that had no - hits. Set *summary* to include in the output the coverage summary per - module. *coverdir* specifies the directory into which the coverage - result files will be output. If ``None``, the results for each source - file are placed in its directory. + Write coverage results. Set *show_missing* to show lines that had no + hits. Set *summary* to include in the output the coverage summary per + module. *coverdir* specifies the directory into which the coverage + result files will be output. If ``None``, the results for each source + file are placed in its directory. A simple example demonstrating the use of the programmatic interface:: diff --git a/Doc/library/turtle.rst b/Doc/library/turtle.rst index d3487537df99a9..2084d75b3a57a0 100644 --- a/Doc/library/turtle.rst +++ b/Doc/library/turtle.rst @@ -913,8 +913,8 @@ Color control Set pencolor to the RGB color represented by *r*, *g*, and *b*. Each of *r*, *g*, and *b* must be in the range 0..colormode. - If turtleshape is a polygon, the outline of that polygon is drawn with the - newly set pencolor. + If turtleshape is a polygon, the outline of that polygon is drawn with the + newly set pencolor. .. doctest:: :skipif: _tkinter is None @@ -962,8 +962,8 @@ Color control Set fillcolor to the RGB color represented by *r*, *g*, and *b*. Each of *r*, *g*, and *b* must be in the range 0..colormode. - If turtleshape is a polygon, the interior of that polygon is drawn - with the newly set fillcolor. + If turtleshape is a polygon, the interior of that polygon is drawn + with the newly set fillcolor. .. doctest:: :skipif: _tkinter is None @@ -1001,8 +1001,8 @@ Color control Equivalent to ``pencolor(colorstring1)`` and ``fillcolor(colorstring2)`` and analogously if the other input format is used. - If turtleshape is a polygon, outline and interior of that polygon is drawn - with the newly set colors. + If turtleshape is a polygon, outline and interior of that polygon is drawn + with the newly set colors. .. doctest:: :skipif: _tkinter is None diff --git a/Doc/reference/datamodel.rst b/Doc/reference/datamodel.rst index 89063876ccc9ed..3b3bd5524ec5dc 100644 --- a/Doc/reference/datamodel.rst +++ b/Doc/reference/datamodel.rst @@ -217,7 +217,6 @@ Ellipsis There are two types of integers: Integers (:class:`int`) - These represent numbers in an unlimited range, subject to available (virtual) memory only. For the purpose of shift and mask operations, a binary representation is assumed, and negative numbers are represented in a variant of From 4ec2149708c7c06ebeccc27e28e2bbc51c4abeca Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 22 Dec 2020 10:19:24 -0800 Subject: [PATCH 0833/1314] bpo-29030: Document interaction between *choices* and *metavar*. (GH-23884) (GH-23894) --- Doc/library/argparse.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Doc/library/argparse.rst b/Doc/library/argparse.rst index 1a298cdd2b5344..4542961d7816ea 100644 --- a/Doc/library/argparse.rst +++ b/Doc/library/argparse.rst @@ -1152,6 +1152,11 @@ Any container can be passed as the *choices* value, so :class:`list` objects, Use of :class:`enum.Enum` is not recommended because it is difficult to control its appearance in usage, help, and error messages. +Formatted choices overrides the default *metavar* which is normally derived +from *dest*. This is usually what you want because the user never sees the +*dest* parameter. If this display isn't desirable (perhaps because there are +many choices), just specify an explicit metavar_. + required ^^^^^^^^ From 8e5c61a075f3a60272a7dcdc48db200090d76309 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 22 Dec 2020 14:12:30 -0800 Subject: [PATCH 0834/1314] bpo-34463: Make python tracebacks identical to C tracebacks for SyntaxErrors without a lineno (GH-23427) (cherry picked from commit 069560b1171eb6385121ff3b6331e8814a4e7454) Co-authored-by: Irit Katriel --- Lib/test/test_traceback.py | 25 +++++++++++++++++++ Lib/traceback.py | 14 +++++++---- .../2020-11-20-19-00-27.bpo-34463.aJcm56.rst | 1 + 3 files changed, 35 insertions(+), 5 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2020-11-20-19-00-27.bpo-34463.aJcm56.rst diff --git a/Lib/test/test_traceback.py b/Lib/test/test_traceback.py index 8549ba2b75ad08..5bb3a58b2a103b 100644 --- a/Lib/test/test_traceback.py +++ b/Lib/test/test_traceback.py @@ -667,6 +667,31 @@ def e(): msg = self.get_report(e).splitlines() self.assertEqual(msg[-2], ' ^') + def test_syntax_error_no_lineno(self): + # See #34463. + + # Without filename + e = SyntaxError('bad syntax') + msg = self.get_report(e).splitlines() + self.assertEqual(msg, + ['SyntaxError: bad syntax']) + e.lineno = 100 + msg = self.get_report(e).splitlines() + self.assertEqual(msg, + [' File "", line 100', 'SyntaxError: bad syntax']) + + # With filename + e = SyntaxError('bad syntax') + e.filename = 'myfile.py' + + msg = self.get_report(e).splitlines() + self.assertEqual(msg, + ['SyntaxError: bad syntax (myfile.py)']) + e.lineno = 100 + msg = self.get_report(e).splitlines() + self.assertEqual(msg, + [' File "myfile.py", line 100', 'SyntaxError: bad syntax']) + def test_message_none(self): # A message that looks like "None" should not be treated specially err = self.get_report(Exception(None)) diff --git a/Lib/traceback.py b/Lib/traceback.py index fb34de94893007..d7fbdae680be62 100644 --- a/Lib/traceback.py +++ b/Lib/traceback.py @@ -515,7 +515,8 @@ def __init__(self, exc_type, exc_value, exc_traceback, *, limit=None, if exc_type and issubclass(exc_type, SyntaxError): # Handle SyntaxError's specially self.filename = exc_value.filename - self.lineno = str(exc_value.lineno) + lno = exc_value.lineno + self.lineno = str(lno) if lno is not None else None self.text = exc_value.text self.offset = exc_value.offset self.msg = exc_value.msg @@ -574,9 +575,12 @@ def format_exception_only(self): def _format_syntax_error(self, stype): """Format SyntaxError exceptions (internal helper).""" # Show exactly where the problem was found. - filename = self.filename or "" - lineno = str(self.lineno) or '?' - yield ' File "{}", line {}\n'.format(filename, lineno) + filename_suffix = '' + if self.lineno is not None: + yield ' File "{}", line {}\n'.format( + self.filename or "", self.lineno) + elif self.filename is not None: + filename_suffix = ' ({})'.format(self.filename) text = self.text if text is not None: @@ -594,7 +598,7 @@ def _format_syntax_error(self, stype): caretspace = ((c if c.isspace() else ' ') for c in ltext[:caret]) yield ' {}^\n'.format(''.join(caretspace)) msg = self.msg or "" - yield "{}: {}\n".format(stype, msg) + yield "{}: {}{}\n".format(stype, msg, filename_suffix) def format(self, *, chain=True): """Format the exception. diff --git a/Misc/NEWS.d/next/Library/2020-11-20-19-00-27.bpo-34463.aJcm56.rst b/Misc/NEWS.d/next/Library/2020-11-20-19-00-27.bpo-34463.aJcm56.rst new file mode 100644 index 00000000000000..df183548236afb --- /dev/null +++ b/Misc/NEWS.d/next/Library/2020-11-20-19-00-27.bpo-34463.aJcm56.rst @@ -0,0 +1 @@ +Fixed discrepancy between :mod:`traceback` and the interpreter in formatting of SyntaxError with lineno not set (:mod:`traceback` was changed to match interpreter). From 7fe7d83c26b02c8a65c8a9633cc4251f5cd97ebf Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 22 Dec 2020 23:48:04 -0800 Subject: [PATCH 0835/1314] bpo-42620: Improve socket.getsockname doc string (GH-23742) Signed-off-by: Christian Heimes (cherry picked from commit cf3565ca9a7ed0f7decd000e41fa3de400986e4d) Co-authored-by: Christian Heimes --- Modules/socketmodule.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c index 76ef606e10b1fb..be75e681d45d99 100644 --- a/Modules/socketmodule.c +++ b/Modules/socketmodule.c @@ -3407,8 +3407,9 @@ sock_getsockname(PySocketSockObject *s, PyObject *Py_UNUSED(ignored)) PyDoc_STRVAR(getsockname_doc, "getsockname() -> address info\n\ \n\ -Return the address of the local endpoint. For IP sockets, the address\n\ -info is a pair (hostaddr, port)."); +Return the address of the local endpoint. The format depends on the\n\ +address family. For IPv4 sockets, the address info is a pair\n\ +(hostaddr, port)."); #ifdef HAVE_GETPEERNAME /* Cray APP doesn't have this :-( */ From 1e1bacf9e61143e7b0f78de9dcb578983bea8f81 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 23 Dec 2020 03:13:51 -0800 Subject: [PATCH 0836/1314] BPO-42703: Fix incorrect documentation links for asyncio.Event (GH-23881) (cherry picked from commit d90ff376813843310a6f9ccc96551fa1521e8fef) Co-authored-by: Matt Fowler --- Doc/library/asyncio-sync.rst | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Doc/library/asyncio-sync.rst b/Doc/library/asyncio-sync.rst index 84a52cb2d57571..f62ce670fccbf9 100644 --- a/Doc/library/asyncio-sync.rst +++ b/Doc/library/asyncio-sync.rst @@ -104,8 +104,8 @@ Event that some event has happened. An Event object manages an internal flag that can be set to *true* - with the :meth:`set` method and reset to *false* with the - :meth:`clear` method. The :meth:`wait` method blocks until the + with the :meth:`~Event.set` method and reset to *false* with the + :meth:`clear` method. The :meth:`~Event.wait` method blocks until the flag is set to *true*. The flag is set to *false* initially. @@ -142,7 +142,7 @@ Event Wait until the event is set. If the event is set, return ``True`` immediately. - Otherwise block until another task calls :meth:`set`. + Otherwise block until another task calls :meth:`~Event.set`. .. method:: set() @@ -155,8 +155,8 @@ Event Clear (unset) the event. - Tasks awaiting on :meth:`wait` will now block until the - :meth:`set` method is called again. + Tasks awaiting on :meth:`~Event.wait` will now block until the + :meth:`~Event.set` method is called again. .. method:: is_set() From a1251980d20ee8aab8d887fc0d30a726247327af Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 23 Dec 2020 19:07:51 -0800 Subject: [PATCH 0837/1314] bpo-42195: Override _CallableGenericAlias's __getitem__ (GH-23915) Added `__getitem__` for `_CallableGenericAlias` so that it returns a subclass (itself) of `types.GenericAlias` rather than the default behavior of returning a plain `types.GenericAlias`. This fixes `repr` issues occuring after `TypeVar` substitution arising from the previous behavior. (cherry picked from commit 6dd3da3cf4a0d6cb62d9c2a155434c127183454d) Co-authored-by: kj <28750310+Fidget-Spinner@users.noreply.github.com> --- Lib/_collections_abc.py | 12 +++++++++++- Lib/test/test_genericalias.py | 6 ++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/Lib/_collections_abc.py b/Lib/_collections_abc.py index cec19ec47349be..b6ecf8eac6368b 100644 --- a/Lib/_collections_abc.py +++ b/Lib/_collections_abc.py @@ -441,7 +441,7 @@ def __create_ga(cls, origin, args): raise TypeError( "Callable must be used as Callable[[arg, ...], result].") t_args, t_result = args - if isinstance(t_args, list): + if isinstance(t_args, (list, tuple)): ga_args = tuple(t_args) + (t_result,) # This relaxes what t_args can be on purpose to allow things like # PEP 612 ParamSpec. Responsibility for whether a user is using @@ -463,6 +463,16 @@ def __reduce__(self): args = list(args[:-1]), args[-1] return _CallableGenericAlias, (Callable, args) + def __getitem__(self, item): + # Called during TypeVar substitution, returns the custom subclass + # rather than the default types.GenericAlias object. + ga = super().__getitem__(item) + args = ga.__args__ + t_result = args[-1] + t_args = args[:-1] + args = (t_args, t_result) + return _CallableGenericAlias(Callable, args) + def _type_repr(obj): """Return the repr() of an object, special-casing types (internal helper). diff --git a/Lib/test/test_genericalias.py b/Lib/test/test_genericalias.py index 5de13fe6d2f68c..ccf40b13d3a94c 100644 --- a/Lib/test/test_genericalias.py +++ b/Lib/test/test_genericalias.py @@ -347,6 +347,12 @@ def test_abc_callable(self): self.assertEqual(C2[int, float, str], Callable[[int, float], str]) self.assertEqual(C3[int], Callable[..., int]) + # multi chaining + C4 = C2[int, V, str] + self.assertEqual(repr(C4).split(".")[-1], "Callable[[int, ~V], str]") + self.assertEqual(repr(C4[dict]).split(".")[-1], "Callable[[int, dict], str]") + self.assertEqual(C4[dict], Callable[[int, dict], str]) + with self.subTest("Testing type erasure"): class C1(Callable): def __call__(self): From 3bb85672bb894403a787a9c5afc0ca5987d28fe0 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 24 Dec 2020 09:37:07 -0800 Subject: [PATCH 0838/1314] closes bpo-42726: gdb libpython: InstanceProxy support for py3 (GH-23912) On Fedora 31 gdb is using python 3.7.9, calling `proxyval` on an instance with a dictionary fails because of the `dict.iteritems` usage. This PR changes the code to be compatible with py2 and py3. This changed seemed small enough to not need an issue and news blurb, if one is required please let me know. Automerge-Triggered-By: GH:benjaminp (cherry picked from commit b57ada98da0d5b0cf1ebc2c9c5502d04aa962042) Co-authored-by: Augusto Hack --- .../next/Tools-Demos/2020-12-23-19-42-11.bpo-42726.a5EkTv.rst | 2 ++ Tools/gdb/libpython.py | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Tools-Demos/2020-12-23-19-42-11.bpo-42726.a5EkTv.rst diff --git a/Misc/NEWS.d/next/Tools-Demos/2020-12-23-19-42-11.bpo-42726.a5EkTv.rst b/Misc/NEWS.d/next/Tools-Demos/2020-12-23-19-42-11.bpo-42726.a5EkTv.rst new file mode 100644 index 00000000000000..01a6e7fe55f5b3 --- /dev/null +++ b/Misc/NEWS.d/next/Tools-Demos/2020-12-23-19-42-11.bpo-42726.a5EkTv.rst @@ -0,0 +1,2 @@ +Fixed Python 3 compatibility issue with gdb/libpython.py handling of attribute +dictionaries. diff --git a/Tools/gdb/libpython.py b/Tools/gdb/libpython.py index 33bf5ac821fffc..aeaa63e540d8b5 100755 --- a/Tools/gdb/libpython.py +++ b/Tools/gdb/libpython.py @@ -468,7 +468,7 @@ def __init__(self, cl_name, attrdict, address): def __repr__(self): if isinstance(self.attrdict, dict): kwargs = ', '.join(["%s=%r" % (arg, val) - for arg, val in self.attrdict.iteritems()]) + for arg, val in self.attrdict.items()]) return '<%s(%s) at remote 0x%x>' % (self.cl_name, kwargs, self.address) else: From f7dca9b9c864c1b7807014ea21a30cac76727e8b Mon Sep 17 00:00:00 2001 From: Ethan Furman Date: Thu, 24 Dec 2020 12:02:38 -0800 Subject: [PATCH 0839/1314] [3.9] bpo-42727: [Enum] EnumMeta.__prepare__ now accepts **kwds (GH-23917). (GH-23926) * [3.9] [Enum] EnumMeta.__prepare__ now accepts **kwds (GH-23917). (cherry picked from commit 6ec0adefad60ec7cdec61c44baecf1dccc1461ab) --- Lib/enum.py | 2 +- Lib/test/test_enum.py | 12 +++++++++++- .../Library/2020-12-23-19-43-06.bpo-42727.WH3ODh.rst | 2 ++ 3 files changed, 14 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2020-12-23-19-43-06.bpo-42727.WH3ODh.rst diff --git a/Lib/enum.py b/Lib/enum.py index 88c951f4f12b46..aa9f4b00dd74d5 100644 --- a/Lib/enum.py +++ b/Lib/enum.py @@ -170,7 +170,7 @@ class EnumMeta(type): Metaclass for Enum """ @classmethod - def __prepare__(metacls, cls, bases): + def __prepare__(metacls, cls, bases, **kwds): # check that previous enum members do not exist metacls._check_for_existing_members(cls, bases) # create the namespace dict diff --git a/Lib/test/test_enum.py b/Lib/test/test_enum.py index 0868c30347216d..f6db73167dc959 100644 --- a/Lib/test/test_enum.py +++ b/Lib/test/test_enum.py @@ -2065,7 +2065,7 @@ class Private(Enum): except ValueError: pass - def test_init_subclass(self): + def test_init_subclass_calling(self): class MyEnum(Enum): def __init_subclass__(cls, **kwds): super(MyEnum, cls).__init_subclass__(**kwds) @@ -2101,6 +2101,16 @@ class NeverEnum(WhereEnum): self.assertFalse(NeverEnum.__dict__.get('_test1', False)) self.assertFalse(NeverEnum.__dict__.get('_test2', False)) + def test_init_subclass_parameter(self): + class multiEnum(Enum): + def __init_subclass__(cls, multi): + for member in cls: + member._as_parameter_ = multi * member.value + class E(multiEnum, multi=3): + A = 1 + B = 2 + self.assertEqual(E.A._as_parameter_, 3) + self.assertEqual(E.B._as_parameter_, 6) class TestOrder(unittest.TestCase): diff --git a/Misc/NEWS.d/next/Library/2020-12-23-19-43-06.bpo-42727.WH3ODh.rst b/Misc/NEWS.d/next/Library/2020-12-23-19-43-06.bpo-42727.WH3ODh.rst new file mode 100644 index 00000000000000..a986cb960a79e7 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2020-12-23-19-43-06.bpo-42727.WH3ODh.rst @@ -0,0 +1,2 @@ +`EnumMeta.__prepare__` now accepts `**kwds` to properly support +`__init_subclass__` From 5a6b5d8c392ca7028e7c034710a89492cd704778 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 24 Dec 2020 20:53:27 -0800 Subject: [PATCH 0840/1314] bpo-42727: Fix the NEWS entry .rst (GH-23932) It was causing CI failures. the offending file came from https://github.com/python/cpython/pull/23917 ``` python3 tools/rstlint.py ../Misc/NEWS.d/next/ [2] ../Misc/NEWS.d/next/Library/2020-12-23-19-43-06.bpo-42727.WH3ODh.rst:1: default role used [2] ../Misc/NEWS.d/next/Library/2020-12-23-19-43-06.bpo-42727.WH3ODh.rst:2: default role used 2 problems with severity 2 found. Makefile:204: recipe for target 'check' failed ``` (cherry picked from commit 8badadec53cbf9dc049c5b54198c5689481e3f3f) Co-authored-by: Gregory P. Smith --- .../next/Library/2020-12-23-19-43-06.bpo-42727.WH3ODh.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Misc/NEWS.d/next/Library/2020-12-23-19-43-06.bpo-42727.WH3ODh.rst b/Misc/NEWS.d/next/Library/2020-12-23-19-43-06.bpo-42727.WH3ODh.rst index a986cb960a79e7..c2ef8eecb85e15 100644 --- a/Misc/NEWS.d/next/Library/2020-12-23-19-43-06.bpo-42727.WH3ODh.rst +++ b/Misc/NEWS.d/next/Library/2020-12-23-19-43-06.bpo-42727.WH3ODh.rst @@ -1,2 +1,2 @@ -`EnumMeta.__prepare__` now accepts `**kwds` to properly support -`__init_subclass__` +``EnumMeta.__prepare__`` now accepts ``**kwds`` to properly support +``__init_subclass__`` From 7acfe4125725e86c982300cf10c0ab791a0783f4 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 24 Dec 2020 21:18:37 -0800 Subject: [PATCH 0841/1314] bpo-42388: Fix subprocess.check_output input=None when text=True (GH-23467) When the modern text= spelling of the universal_newlines= parameter was added for Python 3.7, check_output's special case around input=None was overlooked. So it behaved differently with universal_newlines=True vs text=True. This reconciles the behavior to be consistent and adds a test to guarantee it. Also clarifies the existing check_output documentation. Co-authored-by: Alexey Izbyshev (cherry picked from commit 64abf373444944a240274a9b6d66d1cb01ecfcdd) Co-authored-by: Gregory P. Smith --- Doc/library/subprocess.rst | 5 +++-- Lib/subprocess.py | 6 ++++- Lib/test/test_subprocess.py | 22 +++++++++++++++++++ .../2020-11-22-11-22-28.bpo-42388.LMgM6B.rst | 2 ++ 4 files changed, 32 insertions(+), 3 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2020-11-22-11-22-28.bpo-42388.LMgM6B.rst diff --git a/Doc/library/subprocess.rst b/Doc/library/subprocess.rst index 382ce85516dfbe..3150aa60700ee7 100644 --- a/Doc/library/subprocess.rst +++ b/Doc/library/subprocess.rst @@ -1163,8 +1163,9 @@ calls these functions. The arguments shown above are merely some common ones. The full function signature is largely the same as that of :func:`run` - most arguments are passed directly through to that interface. - However, explicitly passing ``input=None`` to inherit the parent's - standard input file handle is not supported. + One API deviation from :func:`run` behavior exists: passing ``input=None`` + will behave the same as ``input=b''`` (or ``input=''``, depending on other + arguments) rather than using the parent's standard input file handle. By default, this function will return the data as encoded bytes. The actual encoding of the output data may depend on the command being invoked, so the diff --git a/Lib/subprocess.py b/Lib/subprocess.py index f1d829a6f1724e..ddf1128fdd1c78 100644 --- a/Lib/subprocess.py +++ b/Lib/subprocess.py @@ -415,7 +415,11 @@ def check_output(*popenargs, timeout=None, **kwargs): if 'input' in kwargs and kwargs['input'] is None: # Explicitly passing input=None was previously equivalent to passing an # empty string. That is maintained here for backwards compatibility. - kwargs['input'] = '' if kwargs.get('universal_newlines', False) else b'' + if kwargs.get('universal_newlines') or kwargs.get('text'): + empty = '' + else: + empty = b'' + kwargs['input'] = empty return run(*popenargs, stdout=PIPE, timeout=timeout, check=True, **kwargs).stdout diff --git a/Lib/test/test_subprocess.py b/Lib/test/test_subprocess.py index 7373fe29c47d81..e8f9699ef76350 100644 --- a/Lib/test/test_subprocess.py +++ b/Lib/test/test_subprocess.py @@ -196,6 +196,28 @@ def test_check_output_input_arg(self): input=b'pear') self.assertIn(b'PEAR', output) + def test_check_output_input_none(self): + """input=None has a legacy meaning of input='' on check_output.""" + output = subprocess.check_output( + [sys.executable, "-c", + "import sys; print('XX' if sys.stdin.read() else '')"], + input=None) + self.assertNotIn(b'XX', output) + + def test_check_output_input_none_text(self): + output = subprocess.check_output( + [sys.executable, "-c", + "import sys; print('XX' if sys.stdin.read() else '')"], + input=None, text=True) + self.assertNotIn('XX', output) + + def test_check_output_input_none_universal_newlines(self): + output = subprocess.check_output( + [sys.executable, "-c", + "import sys; print('XX' if sys.stdin.read() else '')"], + input=None, universal_newlines=True) + self.assertNotIn('XX', output) + def test_check_output_stdout_arg(self): # check_output() refuses to accept 'stdout' argument with self.assertRaises(ValueError) as c: diff --git a/Misc/NEWS.d/next/Library/2020-11-22-11-22-28.bpo-42388.LMgM6B.rst b/Misc/NEWS.d/next/Library/2020-11-22-11-22-28.bpo-42388.LMgM6B.rst new file mode 100644 index 00000000000000..1b19247e841487 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2020-11-22-11-22-28.bpo-42388.LMgM6B.rst @@ -0,0 +1,2 @@ +Fix subprocess.check_output(..., input=None) behavior when text=True to be +consistent with that of the documentation and universal_newlines=True. From 51f502914656a1f8e8ffdf6e1b06f670d8fea8ed Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 25 Dec 2020 07:22:56 -0800 Subject: [PATCH 0842/1314] bpo-42734: Fix crasher bogus_code_obj.py (GH-23939) It did not work because the signature of code object constructor was changed. Also, it used old format of bytecode (pre-wordcode). (cherry picked from commit 954a7427ba9c2d02faed32c02090caeca873aeca) Co-authored-by: Serhiy Storchaka --- Lib/test/crashers/bogus_code_obj.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/crashers/bogus_code_obj.py b/Lib/test/crashers/bogus_code_obj.py index 198d229491b143..e71b3582cf2d76 100644 --- a/Lib/test/crashers/bogus_code_obj.py +++ b/Lib/test/crashers/bogus_code_obj.py @@ -14,6 +14,6 @@ import types -co = types.CodeType(0, 0, 0, 0, 0, b'\x04\x71\x00\x00', +co = types.CodeType(0, 0, 0, 0, 0, 0, b'\x04\x00\x71\x00', (), (), (), '', '', 1, b'') exec(co) From fbffda25b4b5f537e651eaab4ca1ec4cde800709 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 25 Dec 2020 08:07:30 -0800 Subject: [PATCH 0843/1314] bpo-42727: [Enum] use super() and include **kwds (GH-23927) for multiple inheritance support: use super().new pass **kwds to super().new (cherry picked from commit 786d97a66cac48e7a933010367b8993a5b3ab85b) Co-authored-by: Ethan Furman --- Lib/enum.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/enum.py b/Lib/enum.py index aa9f4b00dd74d5..1c22380f03b38c 100644 --- a/Lib/enum.py +++ b/Lib/enum.py @@ -227,10 +227,10 @@ def __new__(metacls, cls, bases, classdict, **kwds): # create our new Enum type if bases: bases = (_NoInitSubclass, ) + bases - enum_class = type.__new__(metacls, cls, bases, classdict) + enum_class = super().__new__(metacls, cls, bases, classdict, **kwds) enum_class.__bases__ = enum_class.__bases__[1:] #or (object, ) else: - enum_class = type.__new__(metacls, cls, bases, classdict) + enum_class = super().__new__(metacls, cls, bases, classdict, **kwds) old_init_subclass = getattr(enum_class, '__init_subclass__', None) # and restore the new one (if there was one) if new_init_subclass is not None: From 486e70c0a548bbdeea999ce8612711eead791c47 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 25 Dec 2020 14:30:40 -0800 Subject: [PATCH 0844/1314] Rename Tkinter tests for widget options (GH-23944) Every test for widget option starts now with "test_configure_" to distinguish it from tests for widget commands. (cherry picked from commit c1ae21c965cb4d0566df2095e4bcb274d0bd9353) Co-authored-by: Serhiy Storchaka --- Lib/tkinter/test/test_tkinter/test_widgets.py | 211 +++++++++--------- Lib/tkinter/test/test_ttk/test_widgets.py | 92 ++++---- Lib/tkinter/test/widget_tests.py | 119 +++++----- 3 files changed, 212 insertions(+), 210 deletions(-) diff --git a/Lib/tkinter/test/test_tkinter/test_widgets.py b/Lib/tkinter/test/test_tkinter/test_widgets.py index 54eddbf8216110..39334de8cf41c3 100644 --- a/Lib/tkinter/test/test_tkinter/test_widgets.py +++ b/Lib/tkinter/test/test_tkinter/test_widgets.py @@ -22,7 +22,7 @@ def float_round(x): class AbstractToplevelTest(AbstractWidgetTest, PixelSizeTests): _conv_pad_pixels = noconv - def test_class(self): + def test_configure_class(self): widget = self.create() self.assertEqual(widget['class'], widget.__class__.__name__.title()) @@ -31,7 +31,7 @@ def test_class(self): widget2 = self.create(class_='Foo') self.assertEqual(widget2['class'], 'Foo') - def test_colormap(self): + def test_configure_colormap(self): widget = self.create() self.assertEqual(widget['colormap'], '') self.checkInvalidParam(widget, 'colormap', 'new', @@ -39,7 +39,7 @@ def test_colormap(self): widget2 = self.create(colormap='new') self.assertEqual(widget2['colormap'], 'new') - def test_container(self): + def test_configure_container(self): widget = self.create() self.assertEqual(widget['container'], 0 if self.wantobjects else '0') self.checkInvalidParam(widget, 'container', 1, @@ -47,7 +47,7 @@ def test_container(self): widget2 = self.create(container=True) self.assertEqual(widget2['container'], 1 if self.wantobjects else '1') - def test_visual(self): + def test_configure_visual(self): widget = self.create() self.assertEqual(widget['visual'], '') self.checkInvalidParam(widget, 'visual', 'default', @@ -69,13 +69,13 @@ class ToplevelTest(AbstractToplevelTest, unittest.TestCase): def create(self, **kwargs): return tkinter.Toplevel(self.root, **kwargs) - def test_menu(self): + def test_configure_menu(self): widget = self.create() menu = tkinter.Menu(self.root) self.checkParam(widget, 'menu', menu, eq=widget_eq) self.checkParam(widget, 'menu', '') - def test_screen(self): + def test_configure_screen(self): widget = self.create() self.assertEqual(widget['screen'], '') try: @@ -87,7 +87,7 @@ def test_screen(self): widget2 = self.create(screen=display) self.assertEqual(widget2['screen'], display) - def test_use(self): + def test_configure_use(self): widget = self.create() self.assertEqual(widget['use'], '') parent = self.create(container=True) @@ -124,14 +124,14 @@ class LabelFrameTest(AbstractToplevelTest, unittest.TestCase): def create(self, **kwargs): return tkinter.LabelFrame(self.root, **kwargs) - def test_labelanchor(self): + def test_configure_labelanchor(self): widget = self.create() self.checkEnumParam(widget, 'labelanchor', 'e', 'en', 'es', 'n', 'ne', 'nw', 's', 'se', 'sw', 'w', 'wn', 'ws') self.checkInvalidParam(widget, 'labelanchor', 'center') - def test_labelwidget(self): + def test_configure_labelwidget(self): widget = self.create() label = tkinter.Label(self.root, text='Mupp', name='foo') self.checkParam(widget, 'labelwidget', label, expected='.foo') @@ -141,7 +141,7 @@ def test_labelwidget(self): class AbstractLabelTest(AbstractWidgetTest, IntegerSizeTests): _conv_pixels = noconv - def test_highlightthickness(self): + def test_configure_highlightthickness(self): widget = self.create() self.checkPixelsParam(widget, 'highlightthickness', 0, 1.3, 2.6, 6, -2, '10p') @@ -179,7 +179,7 @@ class ButtonTest(AbstractLabelTest, unittest.TestCase): def create(self, **kwargs): return tkinter.Button(self.root, **kwargs) - def test_default(self): + def test_configure_default(self): widget = self.create() self.checkEnumParam(widget, 'default', 'active', 'disabled', 'normal') @@ -204,11 +204,11 @@ def create(self, **kwargs): return tkinter.Checkbutton(self.root, **kwargs) - def test_offvalue(self): + def test_configure_offvalue(self): widget = self.create() self.checkParams(widget, 'offvalue', 1, 2.3, '', 'any string') - def test_onvalue(self): + def test_configure_onvalue(self): widget = self.create() self.checkParams(widget, 'onvalue', 1, 2.3, '', 'any string') @@ -231,7 +231,7 @@ class RadiobuttonTest(AbstractLabelTest, unittest.TestCase): def create(self, **kwargs): return tkinter.Radiobutton(self.root, **kwargs) - def test_value(self): + def test_configure_value(self): widget = self.create() self.checkParams(widget, 'value', 1, 2.3, '', 'any string') @@ -254,18 +254,19 @@ class MenubuttonTest(AbstractLabelTest, unittest.TestCase): def create(self, **kwargs): return tkinter.Menubutton(self.root, **kwargs) - def test_direction(self): + def test_configure_direction(self): widget = self.create() self.checkEnumParam(widget, 'direction', 'above', 'below', 'flush', 'left', 'right') - def test_height(self): + def test_configure_height(self): widget = self.create() self.checkIntegerParam(widget, 'height', 100, -100, 0, conv=str) - test_highlightthickness = StandardOptionsTests.test_highlightthickness + test_configure_highlightthickness = \ + StandardOptionsTests.test_configure_highlightthickness - def test_image(self): + def test_configure_image(self): widget = self.create() image = tkinter.PhotoImage(master=self.root, name='image1') self.checkParam(widget, 'image', image, conv=str) @@ -279,23 +280,23 @@ def test_image(self): if errmsg is not None: self.assertEqual(str(cm.exception), errmsg) - def test_menu(self): + def test_configure_menu(self): widget = self.create() menu = tkinter.Menu(widget, name='menu') self.checkParam(widget, 'menu', menu, eq=widget_eq) menu.destroy() - def test_padx(self): + def test_configure_padx(self): widget = self.create() self.checkPixelsParam(widget, 'padx', 3, 4.4, 5.6, '12m') self.checkParam(widget, 'padx', -2, expected=0) - def test_pady(self): + def test_configure_pady(self): widget = self.create() self.checkPixelsParam(widget, 'pady', 3, 4.4, 5.6, '12m') self.checkParam(widget, 'pady', -2, expected=0) - def test_width(self): + def test_configure_width(self): widget = self.create() self.checkIntegerParam(widget, 'width', 402, -402, 0, conv=str) @@ -328,18 +329,18 @@ class EntryTest(AbstractWidgetTest, unittest.TestCase): def create(self, **kwargs): return tkinter.Entry(self.root, **kwargs) - def test_disabledbackground(self): + def test_configure_disabledbackground(self): widget = self.create() self.checkColorParam(widget, 'disabledbackground') - def test_insertborderwidth(self): + def test_configure_insertborderwidth(self): widget = self.create(insertwidth=100) self.checkPixelsParam(widget, 'insertborderwidth', 0, 1.3, 2.6, 6, -2, '10p') # insertborderwidth is bounded above by a half of insertwidth. self.checkParam(widget, 'insertborderwidth', 60, expected=100//2) - def test_insertwidth(self): + def test_configure_insertwidth(self): widget = self.create() self.checkPixelsParam(widget, 'insertwidth', 1.3, 3.6, '10p') self.checkParam(widget, 'insertwidth', 0.1, expected=2) @@ -349,32 +350,32 @@ def test_insertwidth(self): else: self.checkParam(widget, 'insertwidth', 0.9, expected=1) - def test_invalidcommand(self): + def test_configure_invalidcommand(self): widget = self.create() self.checkCommandParam(widget, 'invalidcommand') self.checkCommandParam(widget, 'invcmd') - def test_readonlybackground(self): + def test_configure_readonlybackground(self): widget = self.create() self.checkColorParam(widget, 'readonlybackground') - def test_show(self): + def test_configure_show(self): widget = self.create() self.checkParam(widget, 'show', '*') self.checkParam(widget, 'show', '') self.checkParam(widget, 'show', ' ') - def test_state(self): + def test_configure_state(self): widget = self.create() self.checkEnumParam(widget, 'state', 'disabled', 'normal', 'readonly') - def test_validate(self): + def test_configure_validate(self): widget = self.create() self.checkEnumParam(widget, 'validate', 'all', 'key', 'focus', 'focusin', 'focusout', 'none') - def test_validatecommand(self): + def test_configure_validatecommand(self): widget = self.create() self.checkCommandParam(widget, 'validatecommand') self.checkCommandParam(widget, 'vcmd') @@ -427,25 +428,25 @@ class SpinboxTest(EntryTest, unittest.TestCase): def create(self, **kwargs): return tkinter.Spinbox(self.root, **kwargs) - test_show = None + test_configure_show = None - def test_buttonbackground(self): + def test_configure_buttonbackground(self): widget = self.create() self.checkColorParam(widget, 'buttonbackground') - def test_buttoncursor(self): + def test_configure_buttoncursor(self): widget = self.create() self.checkCursorParam(widget, 'buttoncursor') - def test_buttondownrelief(self): + def test_configure_buttondownrelief(self): widget = self.create() self.checkReliefParam(widget, 'buttondownrelief') - def test_buttonuprelief(self): + def test_configure_buttonuprelief(self): widget = self.create() self.checkReliefParam(widget, 'buttonuprelief') - def test_format(self): + def test_configure_format(self): widget = self.create() self.checkParam(widget, 'format', '%2f') self.checkParam(widget, 'format', '%2.2f') @@ -460,25 +461,25 @@ def test_format(self): self.checkParam(widget, 'format', '%09.200f') self.checkInvalidParam(widget, 'format', '%d') - def test_from(self): + def test_configure_from(self): widget = self.create() self.checkParam(widget, 'to', 100.0) self.checkFloatParam(widget, 'from', -10, 10.2, 11.7) self.checkInvalidParam(widget, 'from', 200, errmsg='-to value must be greater than -from value') - def test_increment(self): + def test_configure_increment(self): widget = self.create() self.checkFloatParam(widget, 'increment', -1, 1, 10.2, 12.8, 0) - def test_to(self): + def test_configure_to(self): widget = self.create() self.checkParam(widget, 'from', -100.0) self.checkFloatParam(widget, 'to', -10, 10.2, 11.7) self.checkInvalidParam(widget, 'to', -200, errmsg='-to value must be greater than -from value') - def test_values(self): + def test_configure_values(self): # XXX widget = self.create() self.assertEqual(widget['values'], '') @@ -489,7 +490,7 @@ def test_values(self): expected='42 3.14 {} {any string}') self.checkParam(widget, 'values', '') - def test_wrap(self): + def test_configure_wrap(self): widget = self.create() self.checkBooleanParam(widget, 'wrap') @@ -555,17 +556,17 @@ class TextTest(AbstractWidgetTest, unittest.TestCase): def create(self, **kwargs): return tkinter.Text(self.root, **kwargs) - def test_autoseparators(self): + def test_configure_autoseparators(self): widget = self.create() self.checkBooleanParam(widget, 'autoseparators') @requires_tcl(8, 5) - def test_blockcursor(self): + def test_configure_blockcursor(self): widget = self.create() self.checkBooleanParam(widget, 'blockcursor') @requires_tcl(8, 5) - def test_endline(self): + def test_configure_endline(self): widget = self.create() text = '\n'.join('Line %d' for i in range(100)) widget.insert('end', text) @@ -578,50 +579,50 @@ def test_endline(self): self.checkInvalidParam(widget, 'endline', 10, errmsg='-startline must be less than or equal to -endline') - def test_height(self): + def test_configure_height(self): widget = self.create() self.checkPixelsParam(widget, 'height', 100, 101.2, 102.6, '3c') self.checkParam(widget, 'height', -100, expected=1) self.checkParam(widget, 'height', 0, expected=1) - def test_maxundo(self): + def test_configure_maxundo(self): widget = self.create() self.checkIntegerParam(widget, 'maxundo', 0, 5, -1) @requires_tcl(8, 5) - def test_inactiveselectbackground(self): + def test_configure_inactiveselectbackground(self): widget = self.create() self.checkColorParam(widget, 'inactiveselectbackground') @requires_tcl(8, 6) - def test_insertunfocussed(self): + def test_configure_insertunfocussed(self): widget = self.create() self.checkEnumParam(widget, 'insertunfocussed', 'hollow', 'none', 'solid') - def test_selectborderwidth(self): + def test_configure_selectborderwidth(self): widget = self.create() self.checkPixelsParam(widget, 'selectborderwidth', 1.3, 2.6, -2, '10p', conv=noconv, keep_orig=tcl_version >= (8, 5)) - def test_spacing1(self): + def test_configure_spacing1(self): widget = self.create() self.checkPixelsParam(widget, 'spacing1', 20, 21.4, 22.6, '0.5c') self.checkParam(widget, 'spacing1', -5, expected=0) - def test_spacing2(self): + def test_configure_spacing2(self): widget = self.create() self.checkPixelsParam(widget, 'spacing2', 5, 6.4, 7.6, '0.1c') self.checkParam(widget, 'spacing2', -1, expected=0) - def test_spacing3(self): + def test_configure_spacing3(self): widget = self.create() self.checkPixelsParam(widget, 'spacing3', 20, 21.4, 22.6, '0.5c') self.checkParam(widget, 'spacing3', -10, expected=0) @requires_tcl(8, 5) - def test_startline(self): + def test_configure_startline(self): widget = self.create() text = '\n'.join('Line %d' for i in range(100)) widget.insert('end', text) @@ -634,14 +635,14 @@ def test_startline(self): self.checkInvalidParam(widget, 'startline', 70, errmsg='-startline must be less than or equal to -endline') - def test_state(self): + def test_configure_state(self): widget = self.create() if tcl_version < (8, 5): self.checkParams(widget, 'state', 'disabled', 'normal') else: self.checkEnumParam(widget, 'state', 'disabled', 'normal') - def test_tabs(self): + def test_configure_tabs(self): widget = self.create() if get_tk_patchlevel() < (8, 5, 11): self.checkParam(widget, 'tabs', (10.2, 20.7, '1i', '2i'), @@ -657,21 +658,21 @@ def test_tabs(self): keep_orig=tcl_version >= (8, 5)) @requires_tcl(8, 5) - def test_tabstyle(self): + def test_configure_tabstyle(self): widget = self.create() self.checkEnumParam(widget, 'tabstyle', 'tabular', 'wordprocessor') - def test_undo(self): + def test_configure_undo(self): widget = self.create() self.checkBooleanParam(widget, 'undo') - def test_width(self): + def test_configure_width(self): widget = self.create() self.checkIntegerParam(widget, 'width', 402) self.checkParam(widget, 'width', -402, expected=1) self.checkParam(widget, 'width', 0, expected=1) - def test_wrap(self): + def test_configure_wrap(self): widget = self.create() if tcl_version < (8, 5): self.checkParams(widget, 'wrap', 'char', 'none', 'word') @@ -709,16 +710,16 @@ class CanvasTest(AbstractWidgetTest, unittest.TestCase): def create(self, **kwargs): return tkinter.Canvas(self.root, **kwargs) - def test_closeenough(self): + def test_configure_closeenough(self): widget = self.create() self.checkFloatParam(widget, 'closeenough', 24, 2.4, 3.6, -3, conv=float) - def test_confine(self): + def test_configure_confine(self): widget = self.create() self.checkBooleanParam(widget, 'confine') - def test_offset(self): + def test_configure_offset(self): widget = self.create() self.assertEqual(widget['offset'], '0,0') self.checkParams(widget, 'offset', @@ -727,7 +728,7 @@ def test_offset(self): self.checkParam(widget, 'offset', '#5,6') self.checkInvalidParam(widget, 'offset', 'spam') - def test_scrollregion(self): + def test_configure_scrollregion(self): widget = self.create() self.checkParam(widget, 'scrollregion', '0 0 200 150') self.checkParam(widget, 'scrollregion', (0, 0, 200, 150), @@ -739,17 +740,17 @@ def test_scrollregion(self): self.checkInvalidParam(widget, 'scrollregion', (0, 0, 200)) self.checkInvalidParam(widget, 'scrollregion', (0, 0, 200, 150, 0)) - def test_state(self): + def test_configure_state(self): widget = self.create() self.checkEnumParam(widget, 'state', 'disabled', 'normal', errmsg='bad state value "{}": must be normal or disabled') - def test_xscrollincrement(self): + def test_configure_xscrollincrement(self): widget = self.create() self.checkPixelsParam(widget, 'xscrollincrement', 40, 0, 41.2, 43.6, -40, '0.5i') - def test_yscrollincrement(self): + def test_configure_yscrollincrement(self): widget = self.create() self.checkPixelsParam(widget, 'yscrollincrement', 10, 0, 11.2, 13.6, -10, '0.1i') @@ -794,26 +795,26 @@ class ListboxTest(AbstractWidgetTest, unittest.TestCase): def create(self, **kwargs): return tkinter.Listbox(self.root, **kwargs) - def test_activestyle(self): + def test_configure_activestyle(self): widget = self.create() self.checkEnumParam(widget, 'activestyle', 'dotbox', 'none', 'underline') - test_justify = requires_tcl(8, 6, 5)(StandardOptionsTests.test_justify) + test_justify = requires_tcl(8, 6, 5)(StandardOptionsTests.test_configure_justify) - def test_listvariable(self): + def test_configure_listvariable(self): widget = self.create() var = tkinter.DoubleVar(self.root) self.checkVariableParam(widget, 'listvariable', var) - def test_selectmode(self): + def test_configure_selectmode(self): widget = self.create() self.checkParam(widget, 'selectmode', 'single') self.checkParam(widget, 'selectmode', 'browse') self.checkParam(widget, 'selectmode', 'multiple') self.checkParam(widget, 'selectmode', 'extended') - def test_state(self): + def test_configure_state(self): widget = self.create() self.checkEnumParam(widget, 'state', 'disabled', 'normal') @@ -928,53 +929,53 @@ class ScaleTest(AbstractWidgetTest, unittest.TestCase): def create(self, **kwargs): return tkinter.Scale(self.root, **kwargs) - def test_bigincrement(self): + def test_configure_bigincrement(self): widget = self.create() self.checkFloatParam(widget, 'bigincrement', 12.4, 23.6, -5) - def test_digits(self): + def test_configure_digits(self): widget = self.create() self.checkIntegerParam(widget, 'digits', 5, 0) - def test_from(self): + def test_configure_from(self): widget = self.create() conv = False if get_tk_patchlevel() >= (8, 6, 10) else float_round self.checkFloatParam(widget, 'from', 100, 14.9, 15.1, conv=conv) - def test_label(self): + def test_configure_label(self): widget = self.create() self.checkParam(widget, 'label', 'any string') self.checkParam(widget, 'label', '') - def test_length(self): + def test_configure_length(self): widget = self.create() self.checkPixelsParam(widget, 'length', 130, 131.2, 135.6, '5i') - def test_resolution(self): + def test_configure_resolution(self): widget = self.create() self.checkFloatParam(widget, 'resolution', 4.2, 0, 6.7, -2) - def test_showvalue(self): + def test_configure_showvalue(self): widget = self.create() self.checkBooleanParam(widget, 'showvalue') - def test_sliderlength(self): + def test_configure_sliderlength(self): widget = self.create() self.checkPixelsParam(widget, 'sliderlength', 10, 11.2, 15.6, -3, '3m') - def test_sliderrelief(self): + def test_configure_sliderrelief(self): widget = self.create() self.checkReliefParam(widget, 'sliderrelief') - def test_tickinterval(self): + def test_configure_tickinterval(self): widget = self.create() self.checkFloatParam(widget, 'tickinterval', 1, 4.3, 7.6, 0, conv=float_round) self.checkParam(widget, 'tickinterval', -2, expected=2, conv=float_round) - def test_to(self): + def test_configure_to(self): widget = self.create() self.checkFloatParam(widget, 'to', 300, 14.9, 15.1, -10, conv=float_round) @@ -998,15 +999,15 @@ class ScrollbarTest(AbstractWidgetTest, unittest.TestCase): def create(self, **kwargs): return tkinter.Scrollbar(self.root, **kwargs) - def test_activerelief(self): + def test_configure_activerelief(self): widget = self.create() self.checkReliefParam(widget, 'activerelief') - def test_elementborderwidth(self): + def test_configure_elementborderwidth(self): widget = self.create() self.checkPixelsParam(widget, 'elementborderwidth', 4.3, 5.6, -2, '1m') - def test_orient(self): + def test_configure_orient(self): widget = self.create() self.checkEnumParam(widget, 'orient', 'vertical', 'horizontal', errmsg='bad orientation "{}": must be vertical or horizontal') @@ -1047,63 +1048,63 @@ class PanedWindowTest(AbstractWidgetTest, unittest.TestCase): def create(self, **kwargs): return tkinter.PanedWindow(self.root, **kwargs) - def test_handlepad(self): + def test_configure_handlepad(self): widget = self.create() self.checkPixelsParam(widget, 'handlepad', 5, 6.4, 7.6, -3, '1m') - def test_handlesize(self): + def test_configure_handlesize(self): widget = self.create() self.checkPixelsParam(widget, 'handlesize', 8, 9.4, 10.6, -3, '2m', conv=noconv) - def test_height(self): + def test_configure_height(self): widget = self.create() self.checkPixelsParam(widget, 'height', 100, 101.2, 102.6, -100, 0, '1i', conv=noconv) - def test_opaqueresize(self): + def test_configure_opaqueresize(self): widget = self.create() self.checkBooleanParam(widget, 'opaqueresize') @requires_tcl(8, 6, 5) - def test_proxybackground(self): + def test_configure_proxybackground(self): widget = self.create() self.checkColorParam(widget, 'proxybackground') @requires_tcl(8, 6, 5) - def test_proxyborderwidth(self): + def test_configure_proxyborderwidth(self): widget = self.create() self.checkPixelsParam(widget, 'proxyborderwidth', 0, 1.3, 2.9, 6, -2, '10p', conv=noconv) @requires_tcl(8, 6, 5) - def test_proxyrelief(self): + def test_configure_proxyrelief(self): widget = self.create() self.checkReliefParam(widget, 'proxyrelief') - def test_sashcursor(self): + def test_configure_sashcursor(self): widget = self.create() self.checkCursorParam(widget, 'sashcursor') - def test_sashpad(self): + def test_configure_sashpad(self): widget = self.create() self.checkPixelsParam(widget, 'sashpad', 8, 1.3, 2.6, -2, '2m') - def test_sashrelief(self): + def test_configure_sashrelief(self): widget = self.create() self.checkReliefParam(widget, 'sashrelief') - def test_sashwidth(self): + def test_configure_sashwidth(self): widget = self.create() self.checkPixelsParam(widget, 'sashwidth', 10, 11.1, 15.6, -3, '1m', conv=noconv) - def test_showhandle(self): + def test_configure_showhandle(self): widget = self.create() self.checkBooleanParam(widget, 'showhandle') - def test_width(self): + def test_configure_width(self): widget = self.create() self.checkPixelsParam(widget, 'width', 402, 403.4, 404.6, -402, 0, '5i', conv=noconv) @@ -1222,23 +1223,23 @@ class MenuTest(AbstractWidgetTest, unittest.TestCase): def create(self, **kwargs): return tkinter.Menu(self.root, **kwargs) - def test_postcommand(self): + def test_configure_postcommand(self): widget = self.create() self.checkCommandParam(widget, 'postcommand') - def test_tearoff(self): + def test_configure_tearoff(self): widget = self.create() self.checkBooleanParam(widget, 'tearoff') - def test_tearoffcommand(self): + def test_configure_tearoffcommand(self): widget = self.create() self.checkCommandParam(widget, 'tearoffcommand') - def test_title(self): + def test_configure_title(self): widget = self.create() self.checkParam(widget, 'title', 'any string') - def test_type(self): + def test_configure_type(self): widget = self.create() self.checkEnumParam(widget, 'type', 'normal', 'tearoff', 'menubar') @@ -1291,7 +1292,7 @@ class MessageTest(AbstractWidgetTest, unittest.TestCase): def create(self, **kwargs): return tkinter.Message(self.root, **kwargs) - def test_aspect(self): + def test_configure_aspect(self): widget = self.create() self.checkIntegerParam(widget, 'aspect', 250, 0, -300) diff --git a/Lib/tkinter/test/test_ttk/test_widgets.py b/Lib/tkinter/test/test_ttk/test_widgets.py index de30e2476b4eb9..1fac83a004a6d0 100644 --- a/Lib/tkinter/test/test_ttk/test_widgets.py +++ b/Lib/tkinter/test/test_ttk/test_widgets.py @@ -16,7 +16,7 @@ class StandardTtkOptionsTests(StandardOptionsTests): - def test_class(self): + def test_configure_class(self): widget = self.create() self.assertEqual(widget['class'], '') errmsg='attempt to change read-only option' @@ -26,7 +26,7 @@ def test_class(self): widget2 = self.create(class_='Foo') self.assertEqual(widget2['class'], 'Foo') - def test_padding(self): + def test_configure_padding(self): widget = self.create() self.checkParam(widget, 'padding', 0, expected=('0',)) self.checkParam(widget, 'padding', 5, expected=('5',)) @@ -38,7 +38,7 @@ def test_padding(self): self.checkParam(widget, 'padding', ('5p', '6p', '7p', '8p')) self.checkParam(widget, 'padding', (), expected='') - def test_style(self): + def test_configure_style(self): widget = self.create() self.assertEqual(widget['style'], '') errmsg = 'Layout Foo not found' @@ -139,14 +139,14 @@ class LabelFrameTest(AbstractToplevelTest, unittest.TestCase): def create(self, **kwargs): return ttk.LabelFrame(self.root, **kwargs) - def test_labelanchor(self): + def test_configure_labelanchor(self): widget = self.create() self.checkEnumParam(widget, 'labelanchor', 'e', 'en', 'es', 'n', 'ne', 'nw', 's', 'se', 'sw', 'w', 'wn', 'ws', errmsg='Bad label anchor specification {}') self.checkInvalidParam(widget, 'labelanchor', 'center') - def test_labelwidget(self): + def test_configure_labelwidget(self): widget = self.create() label = ttk.Label(self.root, text='Mupp', name='foo') self.checkParam(widget, 'labelwidget', label, expected='.foo') @@ -168,17 +168,17 @@ def checkImageParam(self, widget, name): self.checkInvalidParam(widget, name, 'spam', errmsg='image "spam" doesn\'t exist') - def test_compound(self): + def test_configure_compound(self): widget = self.create() self.checkEnumParam(widget, 'compound', 'none', 'text', 'image', 'center', 'top', 'bottom', 'left', 'right') - def test_state(self): + def test_configure_state(self): widget = self.create() self.checkParams(widget, 'state', 'active', 'disabled', 'normal') - def test_width(self): + def test_configure_width(self): widget = self.create() self.checkParams(widget, 'width', 402, -402, 0) @@ -197,7 +197,7 @@ class LabelTest(AbstractLabelTest, unittest.TestCase): def create(self, **kwargs): return ttk.Label(self.root, **kwargs) - def test_font(self): + def test_configure_font(self): widget = self.create() self.checkParam(widget, 'font', '-Adobe-Helvetica-Medium-R-Normal--*-120-*-*-*-*-*-*') @@ -215,7 +215,7 @@ class ButtonTest(AbstractLabelTest, unittest.TestCase): def create(self, **kwargs): return ttk.Button(self.root, **kwargs) - def test_default(self): + def test_configure_default(self): widget = self.create() self.checkEnumParam(widget, 'default', 'normal', 'active', 'disabled') @@ -240,11 +240,11 @@ class CheckbuttonTest(AbstractLabelTest, unittest.TestCase): def create(self, **kwargs): return ttk.Checkbutton(self.root, **kwargs) - def test_offvalue(self): + def test_configure_offvalue(self): widget = self.create() self.checkParams(widget, 'offvalue', 1, 2.3, '', 'any string') - def test_onvalue(self): + def test_configure_onvalue(self): widget = self.create() self.checkParams(widget, 'onvalue', 1, 2.3, '', 'any string') @@ -292,27 +292,27 @@ def setUp(self): def create(self, **kwargs): return ttk.Entry(self.root, **kwargs) - def test_invalidcommand(self): + def test_configure_invalidcommand(self): widget = self.create() self.checkCommandParam(widget, 'invalidcommand') - def test_show(self): + def test_configure_show(self): widget = self.create() self.checkParam(widget, 'show', '*') self.checkParam(widget, 'show', '') self.checkParam(widget, 'show', ' ') - def test_state(self): + def test_configure_state(self): widget = self.create() self.checkParams(widget, 'state', 'disabled', 'normal', 'readonly') - def test_validate(self): + def test_configure_validate(self): widget = self.create() self.checkEnumParam(widget, 'validate', 'all', 'key', 'focus', 'focusin', 'focusout', 'none') - def test_validatecommand(self): + def test_configure_validatecommand(self): widget = self.create() self.checkCommandParam(widget, 'validatecommand') @@ -429,7 +429,7 @@ def setUp(self): def create(self, **kwargs): return ttk.Combobox(self.root, **kwargs) - def test_height(self): + def test_configure_height(self): widget = self.create() self.checkParams(widget, 'height', 100, 101.2, 102.6, -100, 0, '1i') @@ -459,7 +459,7 @@ def test_virtual_event(self): self.assertTrue(success) - def test_postcommand(self): + def test_configure_postcommand(self): success = [] self.combo['postcommand'] = lambda: success.append(True) @@ -475,7 +475,7 @@ def test_postcommand(self): self.assertEqual(len(success), 1) - def test_values(self): + def test_configure_values(self): def check_get_current(getval, currval): self.assertEqual(self.combo.get(), getval) self.assertEqual(self.combo.current(), currval) @@ -551,7 +551,7 @@ def setUp(self): def create(self, **kwargs): return ttk.PanedWindow(self.root, **kwargs) - def test_orient(self): + def test_configure_orient(self): widget = self.create() self.assertEqual(str(widget['orient']), 'vertical') errmsg='attempt to change read-only option' @@ -684,11 +684,11 @@ class RadiobuttonTest(AbstractLabelTest, unittest.TestCase): def create(self, **kwargs): return ttk.Radiobutton(self.root, **kwargs) - def test_value(self): + def test_configure_value(self): widget = self.create() self.checkParams(widget, 'value', 1, 2.3, '', 'any string') - def test_invoke(self): + def test_configure_invoke(self): success = [] def cb_test(): success.append(1) @@ -739,7 +739,7 @@ def test_direction(self): self.checkEnumParam(widget, 'direction', 'above', 'below', 'left', 'right', 'flush') - def test_menu(self): + def test_configure_menu(self): widget = self.create() menu = tkinter.Menu(widget, name='menu') self.checkParam(widget, 'menu', menu, conv=str) @@ -764,19 +764,19 @@ def setUp(self): def create(self, **kwargs): return ttk.Scale(self.root, **kwargs) - def test_from(self): + def test_configure_from(self): widget = self.create() self.checkFloatParam(widget, 'from', 100, 14.9, 15.1, conv=False) - def test_length(self): + def test_configure_length(self): widget = self.create() self.checkPixelsParam(widget, 'length', 130, 131.2, 135.6, '5i') - def test_to(self): + def test_configure_to(self): widget = self.create() self.checkFloatParam(widget, 'to', 300, 14.9, 15.1, -10, conv=False) - def test_value(self): + def test_configure_value(self): widget = self.create() self.checkFloatParam(widget, 'value', 300, 14.9, 15.1, -10, conv=False) @@ -866,23 +866,23 @@ class ProgressbarTest(AbstractWidgetTest, unittest.TestCase): def create(self, **kwargs): return ttk.Progressbar(self.root, **kwargs) - def test_length(self): + def test_configure_length(self): widget = self.create() self.checkPixelsParam(widget, 'length', 100.1, 56.7, '2i') - def test_maximum(self): + def test_configure_maximum(self): widget = self.create() self.checkFloatParam(widget, 'maximum', 150.2, 77.7, 0, -10, conv=False) - def test_mode(self): + def test_configure_mode(self): widget = self.create() self.checkEnumParam(widget, 'mode', 'determinate', 'indeterminate') - def test_phase(self): + def test_configure_phase(self): # XXX pass - def test_value(self): + def test_configure_value(self): widget = self.create() self.checkFloatParam(widget, 'value', 150.2, 77.7, 0, -10, conv=False) @@ -1071,7 +1071,7 @@ def test_tab(self): self.assertEqual(self.nb.tab(self.child1, 'text'), 'abc') - def test_tabs(self): + def test_configure_tabs(self): self.assertEqual(len(self.nb.tabs()), 2) self.nb.forget(self.child1) @@ -1147,7 +1147,7 @@ def _click_decrement_arrow(self): self.spin.event_generate('', x=x, y=y) self.spin.update_idletasks() - def test_command(self): + def test_configure_command(self): success = [] self.spin['command'] = lambda: success.append(True) @@ -1167,7 +1167,7 @@ def test_command(self): self.spin.update() self.assertEqual(len(success), 2) - def test_to(self): + def test_configure_to(self): self.spin['from'] = 0 self.spin['to'] = 5 self.spin.set(4) @@ -1179,7 +1179,7 @@ def test_to(self): self._click_increment_arrow() # 5 self.assertEqual(self.spin.get(), '5') - def test_from(self): + def test_configure_from(self): self.spin['from'] = 1 self.spin['to'] = 10 self.spin.set(2) @@ -1189,7 +1189,7 @@ def test_from(self): self._click_decrement_arrow() # 1 self.assertEqual(self.spin.get(), '1') - def test_increment(self): + def test_configure_increment(self): self.spin['from'] = 0 self.spin['to'] = 10 self.spin['increment'] = 4 @@ -1203,7 +1203,7 @@ def test_increment(self): self._click_decrement_arrow() # 3 self.assertEqual(self.spin.get(), '3') - def test_format(self): + def test_configure_format(self): self.spin.set(1) self.spin['format'] = '%10.3f' self.spin.update() @@ -1220,7 +1220,7 @@ def test_format(self): self.assertTrue('.' not in value) self.assertEqual(len(value), 1) - def test_wrap(self): + def test_configure_wrap(self): self.spin['to'] = 10 self.spin['from'] = 1 self.spin.set(1) @@ -1239,7 +1239,7 @@ def test_wrap(self): self._click_decrement_arrow() self.assertEqual(self.spin.get(), '1') - def test_values(self): + def test_configure_values(self): self.assertEqual(self.spin['values'], () if tcl_version < (8, 5) else '') self.checkParam(self.spin, 'values', 'mon tue wed thur', @@ -1299,14 +1299,14 @@ def setUp(self): def create(self, **kwargs): return ttk.Treeview(self.root, **kwargs) - def test_columns(self): + def test_configure_columns(self): widget = self.create() self.checkParam(widget, 'columns', 'a b c', expected=('a', 'b', 'c')) self.checkParam(widget, 'columns', ('a', 'b', 'c')) self.checkParam(widget, 'columns', '') - def test_displaycolumns(self): + def test_configure_displaycolumns(self): widget = self.create() widget['columns'] = ('a', 'b', 'c') self.checkParam(widget, 'displaycolumns', 'b a c', @@ -1322,17 +1322,17 @@ def test_displaycolumns(self): self.checkInvalidParam(widget, 'displaycolumns', (1, -2), errmsg='Column index -2 out of bounds') - def test_height(self): + def test_configure_height(self): widget = self.create() self.checkPixelsParam(widget, 'height', 100, -100, 0, '3c', conv=False) self.checkPixelsParam(widget, 'height', 101.2, 102.6, conv=noconv) - def test_selectmode(self): + def test_configure_selectmode(self): widget = self.create() self.checkEnumParam(widget, 'selectmode', 'none', 'browse', 'extended') - def test_show(self): + def test_configure_show(self): widget = self.create() self.checkParam(widget, 'show', 'tree headings', expected=('tree', 'headings')) diff --git a/Lib/tkinter/test/widget_tests.py b/Lib/tkinter/test/widget_tests.py index ad4a8bd2bf3252..9702ff453002e9 100644 --- a/Lib/tkinter/test/widget_tests.py +++ b/Lib/tkinter/test/widget_tests.py @@ -242,31 +242,31 @@ class StandardOptionsTests: 'underline', 'wraplength', 'xscrollcommand', 'yscrollcommand', ) - def test_activebackground(self): + def test_configure_activebackground(self): widget = self.create() self.checkColorParam(widget, 'activebackground') - def test_activeborderwidth(self): + def test_configure_activeborderwidth(self): widget = self.create() self.checkPixelsParam(widget, 'activeborderwidth', 0, 1.3, 2.9, 6, -2, '10p') - def test_activeforeground(self): + def test_configure_activeforeground(self): widget = self.create() self.checkColorParam(widget, 'activeforeground') - def test_anchor(self): + def test_configure_anchor(self): widget = self.create() self.checkEnumParam(widget, 'anchor', 'n', 'ne', 'e', 'se', 's', 'sw', 'w', 'nw', 'center') - def test_background(self): + def test_configure_background(self): widget = self.create() self.checkColorParam(widget, 'background') if 'bg' in self.OPTIONS: self.checkColorParam(widget, 'bg') - def test_bitmap(self): + def test_configure_bitmap(self): widget = self.create() self.checkParam(widget, 'bitmap', 'questhead') self.checkParam(widget, 'bitmap', 'gray50') @@ -279,88 +279,88 @@ def test_bitmap(self): self.checkInvalidParam(widget, 'bitmap', 'spam', errmsg='bitmap "spam" not defined') - def test_borderwidth(self): + def test_configure_borderwidth(self): widget = self.create() self.checkPixelsParam(widget, 'borderwidth', 0, 1.3, 2.6, 6, -2, '10p') if 'bd' in self.OPTIONS: self.checkPixelsParam(widget, 'bd', 0, 1.3, 2.6, 6, -2, '10p') - def test_compound(self): + def test_configure_compound(self): widget = self.create() self.checkEnumParam(widget, 'compound', 'bottom', 'center', 'left', 'none', 'right', 'top') - def test_cursor(self): + def test_configure_cursor(self): widget = self.create() self.checkCursorParam(widget, 'cursor') - def test_disabledforeground(self): + def test_configure_disabledforeground(self): widget = self.create() self.checkColorParam(widget, 'disabledforeground') - def test_exportselection(self): + def test_configure_exportselection(self): widget = self.create() self.checkBooleanParam(widget, 'exportselection') - def test_font(self): + def test_configure_font(self): widget = self.create() self.checkParam(widget, 'font', '-Adobe-Helvetica-Medium-R-Normal--*-120-*-*-*-*-*-*') self.checkInvalidParam(widget, 'font', '', errmsg='font "" doesn\'t exist') - def test_foreground(self): + def test_configure_foreground(self): widget = self.create() self.checkColorParam(widget, 'foreground') if 'fg' in self.OPTIONS: self.checkColorParam(widget, 'fg') - def test_highlightbackground(self): + def test_configure_highlightbackground(self): widget = self.create() self.checkColorParam(widget, 'highlightbackground') - def test_highlightcolor(self): + def test_configure_highlightcolor(self): widget = self.create() self.checkColorParam(widget, 'highlightcolor') - def test_highlightthickness(self): + def test_configure_highlightthickness(self): widget = self.create() self.checkPixelsParam(widget, 'highlightthickness', 0, 1.3, 2.6, 6, '10p') self.checkParam(widget, 'highlightthickness', -2, expected=0, conv=self._conv_pixels) - def test_image(self): + def test_configure_image(self): widget = self.create() self.checkImageParam(widget, 'image') - def test_insertbackground(self): + def test_configure_insertbackground(self): widget = self.create() self.checkColorParam(widget, 'insertbackground') - def test_insertborderwidth(self): + def test_configure_insertborderwidth(self): widget = self.create() self.checkPixelsParam(widget, 'insertborderwidth', 0, 1.3, 2.6, 6, -2, '10p') - def test_insertofftime(self): + def test_configure_insertofftime(self): widget = self.create() self.checkIntegerParam(widget, 'insertofftime', 100) - def test_insertontime(self): + def test_configure_insertontime(self): widget = self.create() self.checkIntegerParam(widget, 'insertontime', 100) - def test_insertwidth(self): + def test_configure_insertwidth(self): widget = self.create() self.checkPixelsParam(widget, 'insertwidth', 1.3, 2.6, -2, '10p') - def test_jump(self): + def test_configure_jump(self): widget = self.create() self.checkBooleanParam(widget, 'jump') - def test_justify(self): + def test_configure_justify(self): widget = self.create() self.checkEnumParam(widget, 'justify', 'left', 'right', 'center', errmsg='bad justification "{}": must be ' @@ -369,154 +369,155 @@ def test_justify(self): errmsg='ambiguous justification "": must be ' 'left, right, or center') - def test_orient(self): + def test_configure_orient(self): widget = self.create() self.assertEqual(str(widget['orient']), self.default_orient) self.checkEnumParam(widget, 'orient', 'horizontal', 'vertical') - def test_padx(self): + def test_configure_padx(self): widget = self.create() self.checkPixelsParam(widget, 'padx', 3, 4.4, 5.6, -2, '12m', conv=self._conv_pad_pixels) - def test_pady(self): + def test_configure_pady(self): widget = self.create() self.checkPixelsParam(widget, 'pady', 3, 4.4, 5.6, -2, '12m', conv=self._conv_pad_pixels) - def test_relief(self): + def test_configure_relief(self): widget = self.create() self.checkReliefParam(widget, 'relief') - def test_repeatdelay(self): + def test_configure_repeatdelay(self): widget = self.create() self.checkIntegerParam(widget, 'repeatdelay', -500, 500) - def test_repeatinterval(self): + def test_configure_repeatinterval(self): widget = self.create() self.checkIntegerParam(widget, 'repeatinterval', -500, 500) - def test_selectbackground(self): + def test_configure_selectbackground(self): widget = self.create() self.checkColorParam(widget, 'selectbackground') - def test_selectborderwidth(self): + def test_configure_selectborderwidth(self): widget = self.create() self.checkPixelsParam(widget, 'selectborderwidth', 1.3, 2.6, -2, '10p') - def test_selectforeground(self): + def test_configure_selectforeground(self): widget = self.create() self.checkColorParam(widget, 'selectforeground') - def test_setgrid(self): + def test_configure_setgrid(self): widget = self.create() self.checkBooleanParam(widget, 'setgrid') - def test_state(self): + def test_configure_state(self): widget = self.create() self.checkEnumParam(widget, 'state', 'active', 'disabled', 'normal') - def test_takefocus(self): + def test_configure_takefocus(self): widget = self.create() self.checkParams(widget, 'takefocus', '0', '1', '') - def test_text(self): + def test_configure_text(self): widget = self.create() self.checkParams(widget, 'text', '', 'any string') - def test_textvariable(self): + def test_configure_textvariable(self): widget = self.create() var = tkinter.StringVar(self.root) self.checkVariableParam(widget, 'textvariable', var) - def test_troughcolor(self): + def test_configure_troughcolor(self): widget = self.create() self.checkColorParam(widget, 'troughcolor') - def test_underline(self): + def test_configure_underline(self): widget = self.create() self.checkIntegerParam(widget, 'underline', 0, 1, 10) - def test_wraplength(self): + def test_configure_wraplength(self): widget = self.create() self.checkPixelsParam(widget, 'wraplength', 100) - def test_xscrollcommand(self): + def test_configure_xscrollcommand(self): widget = self.create() self.checkCommandParam(widget, 'xscrollcommand') - def test_yscrollcommand(self): + def test_configure_yscrollcommand(self): widget = self.create() self.checkCommandParam(widget, 'yscrollcommand') # non-standard but common options - def test_command(self): + def test_configure_command(self): widget = self.create() self.checkCommandParam(widget, 'command') - def test_indicatoron(self): + def test_configure_indicatoron(self): widget = self.create() self.checkBooleanParam(widget, 'indicatoron') - def test_offrelief(self): + def test_configure_offrelief(self): widget = self.create() self.checkReliefParam(widget, 'offrelief') - def test_overrelief(self): + def test_configure_overrelief(self): widget = self.create() self.checkReliefParam(widget, 'overrelief') - def test_selectcolor(self): + def test_configure_selectcolor(self): widget = self.create() self.checkColorParam(widget, 'selectcolor') - def test_selectimage(self): + def test_configure_selectimage(self): widget = self.create() self.checkImageParam(widget, 'selectimage') @requires_tcl(8, 5) - def test_tristateimage(self): + def test_configure_tristateimage(self): widget = self.create() self.checkImageParam(widget, 'tristateimage') @requires_tcl(8, 5) - def test_tristatevalue(self): + def test_configure_tristatevalue(self): widget = self.create() self.checkParam(widget, 'tristatevalue', 'unknowable') - def test_variable(self): + def test_configure_variable(self): widget = self.create() var = tkinter.DoubleVar(self.root) self.checkVariableParam(widget, 'variable', var) class IntegerSizeTests: - def test_height(self): + def test_configure_height(self): widget = self.create() self.checkIntegerParam(widget, 'height', 100, -100, 0) - def test_width(self): + def test_configure_width(self): widget = self.create() self.checkIntegerParam(widget, 'width', 402, -402, 0) class PixelSizeTests: - def test_height(self): + def test_configure_height(self): widget = self.create() self.checkPixelsParam(widget, 'height', 100, 101.2, 102.6, -100, 0, '3c') - def test_width(self): + def test_configure_width(self): widget = self.create() self.checkPixelsParam(widget, 'width', 402, 403.4, 404.6, -402, 0, '5i') def add_standard_options(*source_classes): - # This decorator adds test_xxx methods from source classes for every xxx - # option in the OPTIONS class attribute if they are not defined explicitly. + # This decorator adds test_configure_xxx methods from source classes for + # every xxx option in the OPTIONS class attribute if they are not defined + # explicitly. def decorator(cls): for option in cls.OPTIONS: - methodname = 'test_' + option + methodname = 'test_configure_' + option if not hasattr(cls, methodname): for source_class in source_classes: if hasattr(source_class, methodname): From ed48e9e2862971c2e9dcbd9a253477ec3def5e2e Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 25 Dec 2020 20:23:35 -0800 Subject: [PATCH 0845/1314] Add convolve() to the itertools recipes (GH-23928) (GH-23949) --- Doc/library/itertools.rst | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/Doc/library/itertools.rst b/Doc/library/itertools.rst index 85f4928ce84fbe..ff5b60d70ff4ed 100644 --- a/Doc/library/itertools.rst +++ b/Doc/library/itertools.rst @@ -769,6 +769,18 @@ which incur interpreter overhead. def dotproduct(vec1, vec2): return sum(map(operator.mul, vec1, vec2)) + def convolve(signal, kernel): + # See: https://betterexplained.com/articles/intuitive-convolution/ + # convolve(data, [0.25, 0.25, 0.25, 0.25]) --> Moving average (blur) + # convolve(data, [1, -1]) --> 1st finite difference (1st derivative) + # convolve(data, [1, -2, 1]) --> 2nd finite difference (2nd derivative) + kernel = list(reversed(kernel)) + n = len(kernel) + window = collections.deque([0] * n, maxlen=n) + for x in chain(signal, repeat(0, n-1)): + window.append(x) + yield sum(map(operator.mul, kernel, window)) + def flatten(list_of_lists): "Flatten one level of nesting" return chain.from_iterable(list_of_lists) From dda12ad63e927e93d71462ad77cc84da55bada9b Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 27 Dec 2020 00:32:27 -0800 Subject: [PATCH 0846/1314] bpo-42749: Fix testing bignum if Tkinter is compiled with Tk 8.4 and dynamic linked with Tk >= 8.5 (GH-23955) (cherry picked from commit b02ad2458bc127a7afdeef414fa68c9a7f1f32af) Co-authored-by: Serhiy Storchaka --- Lib/test/test_tcl.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/Lib/test/test_tcl.py b/Lib/test/test_tcl.py index bc8926a239921c..a126b68a108faf 100644 --- a/Lib/test/test_tcl.py +++ b/Lib/test/test_tcl.py @@ -136,10 +136,14 @@ def testUnsetVarException(self): def get_integers(self): integers = (0, 1, -1, 2**31-1, -2**31, 2**31, -2**31-1, 2**63-1, -2**63) - # bignum was added in Tcl 8.5, but its support is able only since 8.5.8 - if (get_tk_patchlevel() >= (8, 6, 0, 'final') or - (8, 5, 8) <= get_tk_patchlevel() < (8, 6)): - integers += (2**63, -2**63-1, 2**1000, -2**1000) + # bignum was added in Tcl 8.5, but its support is able only since 8.5.8. + # Actually it is determined at compile time, so using get_tk_patchlevel() + # is not reliable. + # TODO: expose full static version. + if tcl_version >= (8, 5): + v = get_tk_patchlevel() + if v >= (8, 6, 0, 'final') or (8, 5, 8) <= v < (8, 6): + integers += (2**63, -2**63-1, 2**1000, -2**1000) return integers def test_getint(self): From 9f6a37cc072dab9f9a13d491d3592d23d9809d2b Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 27 Dec 2020 14:56:41 -0800 Subject: [PATCH 0847/1314] bpo-42755: Fix sqlite3.Connection.backup docs (GH-23965) The `pages` argument default value now reflects the implementation. (cherry picked from commit abba83b4b91f78dc556dc0b7700ecb46cba22c01) Co-authored-by: Erlend Egeberg Aasland --- Doc/library/sqlite3.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/sqlite3.rst b/Doc/library/sqlite3.rst index b97414e6fcaa6e..fc9ad2e113e112 100644 --- a/Doc/library/sqlite3.rst +++ b/Doc/library/sqlite3.rst @@ -545,7 +545,7 @@ Connection Objects con.close() - .. method:: backup(target, *, pages=0, progress=None, name="main", sleep=0.250) + .. method:: backup(target, *, pages=-1, progress=None, name="main", sleep=0.250) This method makes a backup of a SQLite database even while it's being accessed by other clients, or concurrently by the same connection. The copy will be From 03e571f1d5f3e7a11f33bb9f47dd4acedf17b166 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 28 Dec 2020 12:26:39 -0800 Subject: [PATCH 0848/1314] bpo-42740: Fix get_args for PEP 585 collections.abc.Callable (GH-23963) PR 1/2. Needs backport to 3.9. (cherry picked from commit 4140f10a16f06c32fd49f9e21fb2a53abe7357f0) Co-authored-by: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> --- Lib/test/test_typing.py | 5 +++++ Lib/typing.py | 4 +--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index 3b3aa29de7221d..4bdb2a0fad6c76 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -3071,6 +3071,11 @@ class C(Generic[T]): pass self.assertEqual(get_args(Callable), ()) self.assertEqual(get_args(list[int]), (int,)) self.assertEqual(get_args(list), ()) + self.assertEqual(get_args(collections.abc.Callable[[int], str]), ([int], str)) + self.assertEqual(get_args(collections.abc.Callable[..., str]), (..., str)) + self.assertEqual(get_args(collections.abc.Callable[[], str]), ([], str)) + self.assertEqual(get_args(collections.abc.Callable[[int], str]), + get_args(Callable[[int], str])) class CollectionsAbcTests(BaseTestCase): diff --git a/Lib/typing.py b/Lib/typing.py index 81e4a2fa403b9a..3556b8adb81905 100644 --- a/Lib/typing.py +++ b/Lib/typing.py @@ -1507,13 +1507,11 @@ def get_args(tp): """ if isinstance(tp, _AnnotatedAlias): return (tp.__origin__,) + tp.__metadata__ - if isinstance(tp, _GenericAlias): + if isinstance(tp, (_GenericAlias, GenericAlias)): res = tp.__args__ if tp.__origin__ is collections.abc.Callable and res[0] is not Ellipsis: res = (list(res[:-1]), res[-1]) return res - if isinstance(tp, GenericAlias): - return tp.__args__ return () From 0b43778b3cd222761beb850178492b6bd0ea2370 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 28 Dec 2020 20:37:20 -0800 Subject: [PATCH 0849/1314] bpo-42770: Fix a typo in the email.headerregistry docs (GH-23982) Automerge-Triggered-By: GH:zware (cherry picked from commit c56988b88fecf6dc70f039704fda6051a0754db1) Co-authored-by: Zackery Spytz --- Doc/library/email.headerregistry.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/email.headerregistry.rst b/Doc/library/email.headerregistry.rst index 9376da2b8d39ce..3e1d97a03264b2 100644 --- a/Doc/library/email.headerregistry.rst +++ b/Doc/library/email.headerregistry.rst @@ -289,7 +289,7 @@ variant, :attr:`~.BaseHeader.max_count` is set to 1. A :class:`ParameterizedMIMEHeader` class that handles the :mailheader:`Content-Disposition` header. - .. attribute:: content-disposition + .. attribute:: content_disposition ``inline`` and ``attachment`` are the only valid values in common use. From 7bdb3e08251894b49e7893db1dc4868e2656b342 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 29 Dec 2020 03:17:43 -0800 Subject: [PATCH 0850/1314] bpo-42749: Use dynamic version to test for unsupported bignum in Tk (GH-23966) Tk can internally support bignum even if Tkinter is built without support of bignum. (cherry picked from commit 156b7f7052102ee1633a18e9a136ad8c38f66db0) Co-authored-by: Serhiy Storchaka --- Lib/test/test_tcl.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/test_tcl.py b/Lib/test/test_tcl.py index a126b68a108faf..0bbb39b147ea1e 100644 --- a/Lib/test/test_tcl.py +++ b/Lib/test/test_tcl.py @@ -447,7 +447,7 @@ def test_expr_bignum(self): else: self.assertEqual(result, str(i)) self.assertIsInstance(result, str) - if tcl_version < (8, 5): # bignum was added in Tcl 8.5 + if get_tk_patchlevel() < (8, 5): # bignum was added in Tcl 8.5 self.assertRaises(TclError, tcl.call, 'expr', str(2**1000)) def test_passing_values(self): From 578caafabe1de652a8f31dbeb8cc660e1ed725eb Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 29 Dec 2020 03:18:26 -0800 Subject: [PATCH 0851/1314] bpo-42759: Fix equality comparison of Variable and Font in Tkinter (GH-23968) Objects which belong to different Tcl interpreters are now always different, even if they have the same name. (cherry picked from commit 1df56bc0597a051c13d53514e120e9b6764185f8) Co-authored-by: Serhiy Storchaka --- Lib/tkinter/__init__.py | 10 +++------- Lib/tkinter/font.py | 2 +- Lib/tkinter/test/test_tkinter/test_font.py | 9 ++++++++- Lib/tkinter/test/test_tkinter/test_variables.py | 14 ++++++++++++-- .../2020-12-27-22-19-26.bpo-42759.lGi_03.rst | 3 +++ 5 files changed, 27 insertions(+), 11 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2020-12-27-22-19-26.bpo-42759.lGi_03.rst diff --git a/Lib/tkinter/__init__.py b/Lib/tkinter/__init__.py index bf0342e27b21f3..98e95ad44866fe 100644 --- a/Lib/tkinter/__init__.py +++ b/Lib/tkinter/__init__.py @@ -491,15 +491,11 @@ def trace_vinfo(self): self._tk.call("trace", "vinfo", self._name))] def __eq__(self, other): - """Comparison for equality (==). - - Note: if the Variable's master matters to behavior - also compare self._master == other._master - """ if not isinstance(other, Variable): return NotImplemented - return self.__class__.__name__ == other.__class__.__name__ \ - and self._name == other._name + return (self._name == other._name + and self.__class__.__name__ == other.__class__.__name__ + and self._tk == other._tk) class StringVar(Variable): diff --git a/Lib/tkinter/font.py b/Lib/tkinter/font.py index 2b58030c1fb5a9..78b660c54be314 100644 --- a/Lib/tkinter/font.py +++ b/Lib/tkinter/font.py @@ -103,7 +103,7 @@ def __str__(self): def __eq__(self, other): if not isinstance(other, Font): return NotImplemented - return self.name == other.name + return self.name == other.name and self._tk == other._tk def __getitem__(self, key): return self.cget(key) diff --git a/Lib/tkinter/test/test_tkinter/test_font.py b/Lib/tkinter/test/test_tkinter/test_font.py index 28d8c7b2f89636..0ea7924f5d5c9e 100644 --- a/Lib/tkinter/test/test_tkinter/test_font.py +++ b/Lib/tkinter/test/test_tkinter/test_font.py @@ -63,15 +63,22 @@ def test_name(self): self.assertEqual(self.font.name, fontname) self.assertEqual(str(self.font), fontname) - def test_eq(self): + def test_equality(self): font1 = font.Font(root=self.root, name=fontname, exists=True) font2 = font.Font(root=self.root, name=fontname, exists=True) self.assertIsNot(font1, font2) self.assertEqual(font1, font2) self.assertNotEqual(font1, font1.copy()) + self.assertNotEqual(font1, 0) self.assertEqual(font1, ALWAYS_EQ) + root2 = tkinter.Tk() + self.addCleanup(root2.destroy) + font3 = font.Font(root=root2, name=fontname, exists=True) + self.assertEqual(str(font1), str(font3)) + self.assertNotEqual(font1, font3) + def test_measure(self): self.assertIsInstance(self.font.measure('abc'), int) diff --git a/Lib/tkinter/test/test_tkinter/test_variables.py b/Lib/tkinter/test/test_tkinter/test_variables.py index 63d7c21059e38c..6aebe8d16d556b 100644 --- a/Lib/tkinter/test/test_tkinter/test_variables.py +++ b/Lib/tkinter/test/test_tkinter/test_variables.py @@ -58,22 +58,32 @@ def test_dont_unset_not_existing(self): del v2 self.assertFalse(self.info_exists("name")) - def test___eq__(self): + def test_equality(self): # values doesn't matter, only class and name are checked v1 = Variable(self.root, name="abc") v2 = Variable(self.root, name="abc") self.assertIsNot(v1, v2) self.assertEqual(v1, v2) - v3 = StringVar(self.root, name="abc") + v3 = Variable(self.root, name="cba") self.assertNotEqual(v1, v3) + v4 = StringVar(self.root, name="abc") + self.assertEqual(str(v1), str(v4)) + self.assertNotEqual(v1, v4) + V = type('Variable', (), {}) self.assertNotEqual(v1, V()) self.assertNotEqual(v1, object()) self.assertEqual(v1, ALWAYS_EQ) + root2 = tkinter.Tk() + self.addCleanup(root2.destroy) + v5 = Variable(root2, name="abc") + self.assertEqual(str(v1), str(v5)) + self.assertNotEqual(v1, v5) + def test_invalid_name(self): with self.assertRaises(TypeError): Variable(self.root, name=123) diff --git a/Misc/NEWS.d/next/Library/2020-12-27-22-19-26.bpo-42759.lGi_03.rst b/Misc/NEWS.d/next/Library/2020-12-27-22-19-26.bpo-42759.lGi_03.rst new file mode 100644 index 00000000000000..a5ec7d5820336d --- /dev/null +++ b/Misc/NEWS.d/next/Library/2020-12-27-22-19-26.bpo-42759.lGi_03.rst @@ -0,0 +1,3 @@ +Fixed equality comparison of :class:`tkinter.Variable` and +:class:`tkinter.font.Font`. Objects which belong to different Tcl +interpreters are now always different, even if they have the same name. From 71d73900ebd4a93a64dae9d2fbef4337fa975e66 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 29 Dec 2020 03:52:12 -0800 Subject: [PATCH 0852/1314] bpo-16396: fix BPO number in changelog (GH-23951) (GH-23956) Automerge-Triggered-By: GH:jaraco (cherry picked from commit 7865f516f313bd31ca48ee1fdae2a80add2293b6) Co-authored-by: Shantanu <12621235+hauntsaninja@users.noreply.github.com> --- Misc/NEWS.d/3.9.1rc1.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Misc/NEWS.d/3.9.1rc1.rst b/Misc/NEWS.d/3.9.1rc1.rst index ac4bf36f5c2173..51edf2fed7e83b 100644 --- a/Misc/NEWS.d/3.9.1rc1.rst +++ b/Misc/NEWS.d/3.9.1rc1.rst @@ -475,7 +475,7 @@ compression header. .. -.. bpo: 16936 +.. bpo: 16396 .. date: 2020-07-08-09-45-00 .. nonce: z8o8Pn .. section: Library From 1ceb097cecc0bbec1cd872c11c5ed2735b840539 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 29 Dec 2020 04:28:58 -0800 Subject: [PATCH 0853/1314] [doc] Fix missing commas in signatures (GH-23693) * Fix star in signatures * Fix comma in signatures (cherry picked from commit 60eccd095624f39195cc5ae0b49a59022bbbb028) Co-authored-by: Andre Delfino --- Doc/library/datetime.rst | 4 ++-- Doc/library/email.contentmanager.rst | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Doc/library/datetime.rst b/Doc/library/datetime.rst index 508bc88e7f4b8a..dae0dd7aa55898 100644 --- a/Doc/library/datetime.rst +++ b/Doc/library/datetime.rst @@ -1219,7 +1219,7 @@ Instance methods: .. method:: datetime.replace(year=self.year, month=self.month, day=self.day, \ hour=self.hour, minute=self.minute, second=self.second, microsecond=self.microsecond, \ - tzinfo=self.tzinfo, * fold=0) + tzinfo=self.tzinfo, *, fold=0) Return a datetime with the same attributes, except for those attributes given new values by whichever keyword arguments are specified. Note that @@ -1783,7 +1783,7 @@ Other constructor: Instance methods: .. method:: time.replace(hour=self.hour, minute=self.minute, second=self.second, \ - microsecond=self.microsecond, tzinfo=self.tzinfo, * fold=0) + microsecond=self.microsecond, tzinfo=self.tzinfo, *, fold=0) Return a :class:`.time` with the same value, except for those attributes given new values by whichever keyword arguments are specified. Note that diff --git a/Doc/library/email.contentmanager.rst b/Doc/library/email.contentmanager.rst index e09c7c0e402bbc..918fc55677e723 100644 --- a/Doc/library/email.contentmanager.rst +++ b/Doc/library/email.contentmanager.rst @@ -116,7 +116,7 @@ Currently the email package provides only one concrete content manager, decoding the payload to unicode. The default error handler is ``replace``. - .. method:: set_content(msg, <'str'>, subtype="plain", charset='utf-8' \ + .. method:: set_content(msg, <'str'>, subtype="plain", charset='utf-8', \ cte=None, \ disposition=None, filename=None, cid=None, \ params=None, headers=None) From df794406a8803e3d6062af8404d7564833f9af28 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 29 Dec 2020 04:46:05 -0800 Subject: [PATCH 0854/1314] Allow / character in username,password fields in _PROXY envvars. (GH-23973) (cherry picked from commit 030a713183084594659aefd77b76fe30178e23c8) Co-authored-by: Senthil Kumaran --- Lib/test/test_urllib2.py | 10 +++++++++- Lib/urllib/request.py | 6 +++++- .../Library/2020-12-27-18-47-01.bpo-23328._xqepZ.rst | 1 + 3 files changed, 15 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2020-12-27-18-47-01.bpo-23328._xqepZ.rst diff --git a/Lib/test/test_urllib2.py b/Lib/test/test_urllib2.py index b71be549d28b5a..12c3f4dbd5bf08 100644 --- a/Lib/test/test_urllib2.py +++ b/Lib/test/test_urllib2.py @@ -1849,9 +1849,17 @@ def test_parse_proxy(self): ('ftp', 'joe', 'password', 'proxy.example.com')), # Test for no trailing '/' case ('http://joe:password@proxy.example.com', - ('http', 'joe', 'password', 'proxy.example.com')) + ('http', 'joe', 'password', 'proxy.example.com')), + # Testcases with '/' character in username, password + ('http://user/name:password@localhost:22', + ('http', 'user/name', 'password', 'localhost:22')), + ('http://username:pass/word@localhost:22', + ('http', 'username', 'pass/word', 'localhost:22')), + ('http://user/name:pass/word@localhost:22', + ('http', 'user/name', 'pass/word', 'localhost:22')), ] + for tc, expected in parse_proxy_test_cases: self.assertEqual(_parse_proxy(tc), expected) diff --git a/Lib/urllib/request.py b/Lib/urllib/request.py index a8c870b9778eba..57d991465a5b0c 100644 --- a/Lib/urllib/request.py +++ b/Lib/urllib/request.py @@ -771,7 +771,11 @@ def _parse_proxy(proxy): raise ValueError("proxy URL with no authority: %r" % proxy) # We have an authority, so for RFC 3986-compliant URLs (by ss 3. # and 3.3.), path is empty or starts with '/' - end = r_scheme.find("/", 2) + if '@' in r_scheme: + host_separator = r_scheme.find('@') + end = r_scheme.find("/", host_separator) + else: + end = r_scheme.find("/", 2) if end == -1: end = None authority = r_scheme[2:end] diff --git a/Misc/NEWS.d/next/Library/2020-12-27-18-47-01.bpo-23328._xqepZ.rst b/Misc/NEWS.d/next/Library/2020-12-27-18-47-01.bpo-23328._xqepZ.rst new file mode 100644 index 00000000000000..07b15d34e8d56b --- /dev/null +++ b/Misc/NEWS.d/next/Library/2020-12-27-18-47-01.bpo-23328._xqepZ.rst @@ -0,0 +1 @@ +Allow / character in username, password fields on _PROXY envars. From cc7f745e80bc177dfc746b057e1c7656b78382e5 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 29 Dec 2020 04:55:33 -0800 Subject: [PATCH 0855/1314] bpo-42700: Swap descriptions in pyexpat.errors (GH-23876) The descriptions of the `codes` and `messages` dictionaries in `xml.parsers.expat.errors` were swapped, and this commit swaps them back. For example, `codes` maps string descriptions of errors to numeric error codes, not the other way around. (cherry picked from commit 84402eb11086f97d31164aaa23e7238da3464f41) Co-authored-by: Michael Wayne Goodman --- Doc/library/pyexpat.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/library/pyexpat.rst b/Doc/library/pyexpat.rst index e43b9aecd86835..034e579315de00 100644 --- a/Doc/library/pyexpat.rst +++ b/Doc/library/pyexpat.rst @@ -665,14 +665,14 @@ The ``errors`` module has the following attributes: .. data:: codes - A dictionary mapping numeric error codes to their string descriptions. + A dictionary mapping string descriptions to their error codes. .. versionadded:: 3.2 .. data:: messages - A dictionary mapping string descriptions to their error codes. + A dictionary mapping numeric error codes to their string descriptions. .. versionadded:: 3.2 From 3966e2ea412a5f190dc8655d9aa7a15c08c4e280 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 29 Dec 2020 05:22:13 -0800 Subject: [PATCH 0856/1314] bpo-42655: Fix subprocess extra_groups gid conversion (GH-23762) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit (cherry picked from commit 0159e5efeebd12b3cf365c8569ca000eac7cb03e) Co-authored-by: Jakub Kulík --- .../next/Library/2020-12-25-12-32-47.bpo-42655.W5ytpV.rst | 2 ++ Modules/_posixsubprocess.c | 6 +----- Modules/posixmodule.c | 8 ++++---- Modules/posixmodule.h | 4 ++-- 4 files changed, 9 insertions(+), 11 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2020-12-25-12-32-47.bpo-42655.W5ytpV.rst diff --git a/Misc/NEWS.d/next/Library/2020-12-25-12-32-47.bpo-42655.W5ytpV.rst b/Misc/NEWS.d/next/Library/2020-12-25-12-32-47.bpo-42655.W5ytpV.rst new file mode 100644 index 00000000000000..57c9a666e395aa --- /dev/null +++ b/Misc/NEWS.d/next/Library/2020-12-25-12-32-47.bpo-42655.W5ytpV.rst @@ -0,0 +1,2 @@ +:mod:`subprocess` *extra_groups* is now correctly passed into setgroups() +system call. diff --git a/Modules/_posixsubprocess.c b/Modules/_posixsubprocess.c index c266fd1ec1756a..d64e0a1cfa06d6 100644 --- a/Modules/_posixsubprocess.c +++ b/Modules/_posixsubprocess.c @@ -753,7 +753,7 @@ subprocess_fork_exec(PyObject* self, PyObject *args) if (groups_list != Py_None) { #ifdef HAVE_SETGROUPS Py_ssize_t i; - unsigned long gid; + gid_t gid; if (!PyList_Check(groups_list)) { PyErr_SetString(PyExc_TypeError, @@ -787,10 +787,6 @@ subprocess_fork_exec(PyObject* self, PyObject *args) Py_DECREF(elem); goto cleanup; } else { - /* In posixmodule.c UnsignedLong is used as a fallback value - * if the value provided does not fit in a Long. Since we are - * already doing the bounds checking on the Python side, we - * can go directly to an UnsignedLong here. */ if (!_Py_Gid_Converter(elem, &gid)) { Py_DECREF(elem); PyErr_SetString(PyExc_ValueError, "invalid group id"); diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index 12f72f525f7ae4..d2ce8339e61f06 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -632,7 +632,7 @@ _PyLong_FromGid(gid_t gid) } int -_Py_Uid_Converter(PyObject *obj, void *p) +_Py_Uid_Converter(PyObject *obj, uid_t *p) { uid_t uid; PyObject *index; @@ -719,7 +719,7 @@ _Py_Uid_Converter(PyObject *obj, void *p) success: Py_DECREF(index); - *(uid_t *)p = uid; + *p = uid; return 1; underflow: @@ -738,7 +738,7 @@ _Py_Uid_Converter(PyObject *obj, void *p) } int -_Py_Gid_Converter(PyObject *obj, void *p) +_Py_Gid_Converter(PyObject *obj, gid_t *p) { gid_t gid; PyObject *index; @@ -826,7 +826,7 @@ _Py_Gid_Converter(PyObject *obj, void *p) success: Py_DECREF(index); - *(gid_t *)p = gid; + *p = gid; return 1; underflow: diff --git a/Modules/posixmodule.h b/Modules/posixmodule.h index 1e00562abc3370..711ac686934b02 100644 --- a/Modules/posixmodule.h +++ b/Modules/posixmodule.h @@ -14,8 +14,8 @@ extern "C" { #ifndef MS_WINDOWS PyAPI_FUNC(PyObject *) _PyLong_FromUid(uid_t); PyAPI_FUNC(PyObject *) _PyLong_FromGid(gid_t); -PyAPI_FUNC(int) _Py_Uid_Converter(PyObject *, void *); -PyAPI_FUNC(int) _Py_Gid_Converter(PyObject *, void *); +PyAPI_FUNC(int) _Py_Uid_Converter(PyObject *, uid_t *); +PyAPI_FUNC(int) _Py_Gid_Converter(PyObject *, gid_t *); #endif /* MS_WINDOWS */ #if defined(PYPTHREAD_SIGMASK) || defined(HAVE_SIGWAIT) || \ From 7a7f3e0d6a197c81fff83ad777c74324ceb4198f Mon Sep 17 00:00:00 2001 From: Andre Delfino Date: Thu, 31 Dec 2020 10:10:10 -0300 Subject: [PATCH 0857/1314] [3.9] bpo-41224: Add versionadded for Symbol.is_annotated (GH-23861). (GH-24017) (cherry picked from commit 2edfc86f69d8a74f4821974678f664ff94a9dc22) --- Doc/library/symtable.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Doc/library/symtable.rst b/Doc/library/symtable.rst index 3efdecb5af7102..e364232247c200 100644 --- a/Doc/library/symtable.rst +++ b/Doc/library/symtable.rst @@ -156,6 +156,12 @@ Examining Symbol Tables Return ``True`` if the symbol is local to its block. + .. method:: is_annotated() + + Return ``True`` if the symbol is annotated. + + .. versionadded:: 3.6 + .. method:: is_free() Return ``True`` if the symbol is referenced in its block, but not assigned From 55fadffb0b37480b44ae515a82f87d8fa298c173 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 31 Dec 2020 12:27:17 -0800 Subject: [PATCH 0858/1314] Fixes a typo in importlib.metadata. (GH-23921) (#24029) Signed-off-by: Tao He (cherry picked from commit 3631d6deab064de0bb286ef2943885dca3c3075e) Co-authored-by: Tao He Co-authored-by: Tao He --- Doc/library/importlib.metadata.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/library/importlib.metadata.rst b/Doc/library/importlib.metadata.rst index 21da143f3bebf9..0dd3daaa54892b 100644 --- a/Doc/library/importlib.metadata.rst +++ b/Doc/library/importlib.metadata.rst @@ -206,9 +206,9 @@ Thus, an alternative way to get the version number is through the There are all kinds of additional metadata available on the ``Distribution`` instance:: - >>> d.metadata['Requires-Python'] # doctest: +SKIP + >>> dist.metadata['Requires-Python'] # doctest: +SKIP '>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*' - >>> d.metadata['License'] # doctest: +SKIP + >>> dist.metadata['License'] # doctest: +SKIP 'MIT' The full set of available metadata is not described here. See :pep:`566` From 8333d421c0d7b90de3ff92002af9fd2c5d5f373c Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 31 Dec 2020 17:36:14 -0800 Subject: [PATCH 0859/1314] bpo-42781: Document the mechanics of cached_property from a user viewpoint (GH-24031) (#24035) --- Doc/library/functools.rst | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/Doc/library/functools.rst b/Doc/library/functools.rst index 4869b67cb94164..85d4e74698d2f1 100644 --- a/Doc/library/functools.rst +++ b/Doc/library/functools.rst @@ -62,16 +62,26 @@ The :mod:`functools` module defines the following functions: Example:: class DataSet: + def __init__(self, sequence_of_numbers): - self._data = sequence_of_numbers + self._data = tuple(sequence_of_numbers) @cached_property def stdev(self): return statistics.stdev(self._data) - @cached_property - def variance(self): - return statistics.variance(self._data) + The mechanics of :func:`cached_property` are somewhat different from + :func:`property`. A regular property blocks attribute writes unless a + setter is defined. In contrast, a *cached_property* allows writes. + + The *cached_property* decorator only runs on lookups and only when an + attribute of the same name doesn't exist. When it does run, the + *cached_property* writes to the attribute with the same name. Subsequent + attribute reads and writes take precedence over the *cached_property* + method and it works like a normal attribute. + + The cached value can be cleared by deleting the attribute. This + allows the *cached_property* method to run again. Note, this decorator interferes with the operation of :pep:`412` key-sharing dictionaries. This means that instance dictionaries From b20d5e5ce95248e0fa77c5d7bf8f6f5b1231fa53 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 1 Jan 2021 06:42:43 -0800 Subject: [PATCH 0860/1314] bpo-42794: Update test_nntplib to use offical group name for testing (GH-24037) (cherry picked from commit ec3165320e81ac87edcb85c86c452528ddbaec1c) Co-authored-by: Dong-hee Na --- Lib/test/test_nntplib.py | 10 +++++++--- .../Tests/2021-01-01-08-52-36.bpo-42794.-7-XGz.rst | 2 ++ 2 files changed, 9 insertions(+), 3 deletions(-) create mode 100644 Misc/NEWS.d/next/Tests/2021-01-01-08-52-36.bpo-42794.-7-XGz.rst diff --git a/Lib/test/test_nntplib.py b/Lib/test/test_nntplib.py index 1df64fa7c6b00b..99386ddbaedfa9 100644 --- a/Lib/test/test_nntplib.py +++ b/Lib/test/test_nntplib.py @@ -82,7 +82,7 @@ def _check_desc(desc): desc = self.server.description(self.GROUP_NAME) _check_desc(desc) # Another sanity check - self.assertIn("Python", desc) + self.assertIn(self.DESC, desc) # With a pattern desc = self.server.description(self.GROUP_PAT) _check_desc(desc) @@ -309,6 +309,7 @@ class NetworkedNNTPTests(NetworkedNNTPTestsMixin, unittest.TestCase): NNTP_HOST = 'news.trigofacile.com' GROUP_NAME = 'fr.comp.lang.python' GROUP_PAT = 'fr.comp.lang.*' + DESC = 'Python' NNTP_CLASS = NNTP @@ -343,8 +344,11 @@ class NetworkedNNTP_SSLTests(NetworkedNNTPTests): # 400 connections per day are accepted from each IP address." NNTP_HOST = 'nntp.aioe.org' - GROUP_NAME = 'comp.lang.python' - GROUP_PAT = 'comp.lang.*' + # bpo-42794: aioe.test is one of the official groups on this server + # used for testing: https://news.aioe.org/manual/aioe-hierarchy/ + GROUP_NAME = 'aioe.test' + GROUP_PAT = 'aioe.*' + DESC = 'test' NNTP_CLASS = getattr(nntplib, 'NNTP_SSL', None) diff --git a/Misc/NEWS.d/next/Tests/2021-01-01-08-52-36.bpo-42794.-7-XGz.rst b/Misc/NEWS.d/next/Tests/2021-01-01-08-52-36.bpo-42794.-7-XGz.rst new file mode 100644 index 00000000000000..577f2259e1f00c --- /dev/null +++ b/Misc/NEWS.d/next/Tests/2021-01-01-08-52-36.bpo-42794.-7-XGz.rst @@ -0,0 +1,2 @@ +Update test_nntplib to use offical group name of news.aioe.org for testing. +Patch by Dong-hee Na. From fa12749bcd20a9844e99819e361bc15af5eaf7e3 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 1 Jan 2021 09:27:48 -0800 Subject: [PATCH 0861/1314] Bring Python into the new year. (GH-24036) (cherry picked from commit de6f20a6de48d63066b2cf5b317f50629f01d74a) Co-authored-by: Dong-hee Na --- Doc/copyright.rst | 2 +- Doc/license.rst | 2 +- LICENSE | 2 +- Mac/IDLE/IDLE.app/Contents/Info.plist | 2 +- Mac/PythonLauncher/Info.plist.in | 2 +- Mac/Resources/app/Info.plist.in | 2 +- PC/python_ver_rc.h | 2 +- Python/getcopyright.c | 2 +- README.rst | 4 ++-- 9 files changed, 10 insertions(+), 10 deletions(-) diff --git a/Doc/copyright.rst b/Doc/copyright.rst index 1b90d9f172c992..4191c0bb63a2c1 100644 --- a/Doc/copyright.rst +++ b/Doc/copyright.rst @@ -4,7 +4,7 @@ Copyright Python and this documentation is: -Copyright © 2001-2020 Python Software Foundation. All rights reserved. +Copyright © 2001-2021 Python Software Foundation. All rights reserved. Copyright © 2000 BeOpen.com. All rights reserved. diff --git a/Doc/license.rst b/Doc/license.rst index 4030825bbd28ee..f487d98b2b43a3 100644 --- a/Doc/license.rst +++ b/Doc/license.rst @@ -100,7 +100,7 @@ PSF LICENSE AGREEMENT FOR PYTHON |release| analyze, test, perform and/or display publicly, prepare derivative works, distribute, and otherwise use Python |release| alone or in any derivative version, provided, however, that PSF's License Agreement and PSF's notice of - copyright, i.e., "Copyright © 2001-2020 Python Software Foundation; All Rights + copyright, i.e., "Copyright © 2001-2021 Python Software Foundation; All Rights Reserved" are retained in Python |release| alone or in any derivative version prepared by Licensee. diff --git a/LICENSE b/LICENSE index f42f8adbed845d..473861da1be7c5 100644 --- a/LICENSE +++ b/LICENSE @@ -84,7 +84,7 @@ analyze, test, perform and/or display publicly, prepare derivative works, distribute, and otherwise use Python alone or in any derivative version, provided, however, that PSF's License Agreement and PSF's notice of copyright, i.e., "Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, -2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020 Python Software Foundation; +2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021 Python Software Foundation; All Rights Reserved" are retained in Python alone or in any derivative version prepared by Licensee. diff --git a/Mac/IDLE/IDLE.app/Contents/Info.plist b/Mac/IDLE/IDLE.app/Contents/Info.plist index dcc48abdd2a395..f6b5cfe8d5451f 100644 --- a/Mac/IDLE/IDLE.app/Contents/Info.plist +++ b/Mac/IDLE/IDLE.app/Contents/Info.plist @@ -36,7 +36,7 @@ CFBundleExecutable IDLE CFBundleGetInfoString - %version%, © 2001-2020 Python Software Foundation + %version%, © 2001-2021 Python Software Foundation CFBundleIconFile IDLE.icns CFBundleIdentifier diff --git a/Mac/PythonLauncher/Info.plist.in b/Mac/PythonLauncher/Info.plist.in index 21a051535fb925..3d8bc3e4154ee2 100644 --- a/Mac/PythonLauncher/Info.plist.in +++ b/Mac/PythonLauncher/Info.plist.in @@ -40,7 +40,7 @@ CFBundleExecutable Python Launcher CFBundleGetInfoString - %VERSION%, © 2001-2020 Python Software Foundation + %VERSION%, © 2001-2021 Python Software Foundation CFBundleIconFile PythonLauncher.icns CFBundleIdentifier diff --git a/Mac/Resources/app/Info.plist.in b/Mac/Resources/app/Info.plist.in index 1d624984a85203..2c801332332b30 100644 --- a/Mac/Resources/app/Info.plist.in +++ b/Mac/Resources/app/Info.plist.in @@ -37,7 +37,7 @@ CFBundleInfoDictionaryVersion 6.0 CFBundleLongVersionString - %version%, (c) 2001-2020 Python Software Foundation. + %version%, (c) 2001-2021 Python Software Foundation. CFBundleName Python CFBundlePackageType diff --git a/PC/python_ver_rc.h b/PC/python_ver_rc.h index 060aecdc675cb9..90fc6ba1a1460c 100644 --- a/PC/python_ver_rc.h +++ b/PC/python_ver_rc.h @@ -5,7 +5,7 @@ #include "winver.h" #define PYTHON_COMPANY "Python Software Foundation" -#define PYTHON_COPYRIGHT "Copyright \xA9 2001-2016 Python Software Foundation. Copyright \xA9 2000 BeOpen.com. Copyright \xA9 1995-2001 CNRI. Copyright \xA9 1991-1995 SMC." +#define PYTHON_COPYRIGHT "Copyright \xA9 2001-2021 Python Software Foundation. Copyright \xA9 2000 BeOpen.com. Copyright \xA9 1995-2001 CNRI. Copyright \xA9 1991-1995 SMC." #define MS_WINDOWS #include "modsupport.h" diff --git a/Python/getcopyright.c b/Python/getcopyright.c index 299ccc08c44f83..7fdeb314d5261b 100644 --- a/Python/getcopyright.c +++ b/Python/getcopyright.c @@ -4,7 +4,7 @@ static const char cprt[] = "\ -Copyright (c) 2001-2020 Python Software Foundation.\n\ +Copyright (c) 2001-2021 Python Software Foundation.\n\ All Rights Reserved.\n\ \n\ Copyright (c) 2000 BeOpen.com.\n\ diff --git a/README.rst b/README.rst index a9ab26056c588a..bb43311ad2f95d 100644 --- a/README.rst +++ b/README.rst @@ -22,7 +22,7 @@ This is Python version 3.9.1 :target: https://python.zulipchat.com -Copyright (c) 2001-2020 Python Software Foundation. All rights reserved. +Copyright (c) 2001-2021 Python Software Foundation. All rights reserved. See the end of this file for further copyright and license information. @@ -250,7 +250,7 @@ See :pep:`596` for Python 3.9 release details. Copyright and License Information --------------------------------- -Copyright (c) 2001-2020 Python Software Foundation. All rights reserved. +Copyright (c) 2001-2021 Python Software Foundation. All rights reserved. Copyright (c) 2000 BeOpen.com. All rights reserved. From 0d6e40744ae40ff397883ff90ca235efd3b63f18 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 1 Jan 2021 12:42:44 -0800 Subject: [PATCH 0862/1314] bpo-39068: Fix race condition in base64 (GH-17627) There was a race condition in base64 in lazy initialization of multiple globals. (cherry picked from commit 9655434cca5dfbea97bf6d355aec028e840b289c) Co-authored-by: Brandon Stansbury --- Lib/base64.py | 4 ++-- Misc/ACKS | 1 + .../next/Library/2019-12-16-17-55-31.bpo-39068.Ti3f9P.rst | 2 ++ 3 files changed, 5 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2019-12-16-17-55-31.bpo-39068.Ti3f9P.rst diff --git a/Lib/base64.py b/Lib/base64.py index a28109f8a7f9c3..ec3823b724a37e 100755 --- a/Lib/base64.py +++ b/Lib/base64.py @@ -320,7 +320,7 @@ def a85encode(b, *, foldspaces=False, wrapcol=0, pad=False, adobe=False): global _a85chars, _a85chars2 # Delay the initialization of tables to not waste memory # if the function is never called - if _a85chars is None: + if _a85chars2 is None: _a85chars = [bytes((i,)) for i in range(33, 118)] _a85chars2 = [(a + b) for a in _a85chars for b in _a85chars] @@ -428,7 +428,7 @@ def b85encode(b, pad=False): global _b85chars, _b85chars2 # Delay the initialization of tables to not waste memory # if the function is never called - if _b85chars is None: + if _b85chars2 is None: _b85chars = [bytes((i,)) for i in _b85alphabet] _b85chars2 = [(a + b) for a in _b85chars for b in _b85chars] return _85encode(b, _b85chars, _b85chars2, pad) diff --git a/Misc/ACKS b/Misc/ACKS index a20c41f1cb189e..58a4accd13451a 100644 --- a/Misc/ACKS +++ b/Misc/ACKS @@ -1641,6 +1641,7 @@ Quentin Stafford-Fraser Frank Stajano Joel Stanley Kyle Stanley +Brandon Stansbury Anthony Starks David Steele Oliver Steele diff --git a/Misc/NEWS.d/next/Library/2019-12-16-17-55-31.bpo-39068.Ti3f9P.rst b/Misc/NEWS.d/next/Library/2019-12-16-17-55-31.bpo-39068.Ti3f9P.rst new file mode 100644 index 00000000000000..fe6503fdce6b63 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2019-12-16-17-55-31.bpo-39068.Ti3f9P.rst @@ -0,0 +1,2 @@ +Fix initialization race condition in :func:`a85encode` and :func:`b85encode` +in :mod:`base64`. Patch by Brandon Stansbury. From 69120613c071e9327a9dc6e4b1ff21b2e94d885e Mon Sep 17 00:00:00 2001 From: Ross Date: Sat, 2 Jan 2021 03:44:04 +0000 Subject: [PATCH 0863/1314] [3.9] bpo-42756: Configure LMTP Unix-domain socket to use global default timeout when timeout not provided (GH-23969) (GH-24050) --- Lib/smtplib.py | 3 ++- Lib/test/mock_socket.py | 7 +++++++ Lib/test/test_smtplib.py | 11 +++++++++++ .../Library/2020-12-27-21-22-01.bpo-42756.dHMPJ9.rst | 2 ++ 4 files changed, 22 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Library/2020-12-27-21-22-01.bpo-42756.dHMPJ9.rst diff --git a/Lib/smtplib.py b/Lib/smtplib.py index 7808ba01cba887..f0472317de9190 100755 --- a/Lib/smtplib.py +++ b/Lib/smtplib.py @@ -1082,7 +1082,8 @@ def connect(self, host='localhost', port=0, source_address=None): # Handle Unix-domain sockets. try: self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) - self.sock.settimeout(self.timeout) + if self.timeout is not socket._GLOBAL_DEFAULT_TIMEOUT: + self.sock.settimeout(self.timeout) self.file = None self.sock.connect(host) except OSError: diff --git a/Lib/test/mock_socket.py b/Lib/test/mock_socket.py index cda4db25cba594..c7abddcf5fafd3 100644 --- a/Lib/test/mock_socket.py +++ b/Lib/test/mock_socket.py @@ -107,6 +107,9 @@ def getpeername(self): def close(self): pass + def connect(self, host): + pass + def socket(family=None, type=None, proto=None): return MockSocket(family) @@ -152,8 +155,12 @@ def getaddrinfo(*args, **kw): # Constants +_GLOBAL_DEFAULT_TIMEOUT = socket_module._GLOBAL_DEFAULT_TIMEOUT AF_INET = socket_module.AF_INET AF_INET6 = socket_module.AF_INET6 SOCK_STREAM = socket_module.SOCK_STREAM SOL_SOCKET = None SO_REUSEADDR = None + +if hasattr(socket_module, 'AF_UNIX'): + AF_UNIX = socket_module.AF_UNIX diff --git a/Lib/test/test_smtplib.py b/Lib/test/test_smtplib.py index 576299900318d5..3451f3a411e9a5 100644 --- a/Lib/test/test_smtplib.py +++ b/Lib/test/test_smtplib.py @@ -165,6 +165,17 @@ class LMTPGeneralTests(GeneralTests, unittest.TestCase): client = smtplib.LMTP + @unittest.skipUnless(hasattr(socket, 'AF_UNIX'), "test requires Unix domain socket") + def testUnixDomainSocketTimeoutDefault(self): + local_host = '/some/local/lmtp/delivery/program' + mock_socket.reply_with(b"220 Hello world") + try: + client = self.client(local_host, self.port) + finally: + mock_socket.setdefaulttimeout(None) + self.assertIsNone(client.sock.gettimeout()) + client.close() + def testTimeoutZero(self): super().testTimeoutZero() local_host = '/some/local/lmtp/delivery/program' diff --git a/Misc/NEWS.d/next/Library/2020-12-27-21-22-01.bpo-42756.dHMPJ9.rst b/Misc/NEWS.d/next/Library/2020-12-27-21-22-01.bpo-42756.dHMPJ9.rst new file mode 100644 index 00000000000000..93a0bb010df2bb --- /dev/null +++ b/Misc/NEWS.d/next/Library/2020-12-27-21-22-01.bpo-42756.dHMPJ9.rst @@ -0,0 +1,2 @@ +Configure LMTP Unix-domain socket to use socket global default timeout when +a timeout is not explicitly provided. From 7695d832565914efcedcc885feb129f5102aec90 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sat, 2 Jan 2021 12:24:27 +0200 Subject: [PATCH 0864/1314] [3.9] bpo-42425: Fix possible leak in initialization of errmap for OSError (GH-23446). (GH-24057) (cherry picked from commit ed1007c0d74e658d1e6c9b51b12ce7501eb8cbf9) --- Objects/exceptions.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Objects/exceptions.c b/Objects/exceptions.c index e44ce727aff1e2..eb72de53e98c12 100644 --- a/Objects/exceptions.c +++ b/Objects/exceptions.c @@ -2531,8 +2531,10 @@ _PyExc_Init(void) do { \ PyObject *_code = PyLong_FromLong(CODE); \ assert(_PyObject_RealIsSubclass(PyExc_ ## TYPE, PyExc_OSError)); \ - if (!_code || PyDict_SetItem(errnomap, _code, PyExc_ ## TYPE)) \ + if (!_code || PyDict_SetItem(errnomap, _code, PyExc_ ## TYPE)) { \ + Py_XDECREF(_code); \ return _PyStatus_ERR("errmap insertion problem."); \ + } \ Py_DECREF(_code); \ } while (0) From 39a7578186d2f5eaa112a5854c46f84eae401522 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 2 Jan 2021 09:53:46 -0800 Subject: [PATCH 0865/1314] bpo-42809: Improve pickle tests for recursive data. (GH-24060) (cherry picked from commit a25011be8c6f62cb3333903befe6295d57f0bd30) Co-authored-by: Serhiy Storchaka --- Lib/test/pickletester.py | 340 +++++++++++++++++++++++++++++---------- 1 file changed, 253 insertions(+), 87 deletions(-) diff --git a/Lib/test/pickletester.py b/Lib/test/pickletester.py index 3d54617f68ba4a..7e279cc736a236 100644 --- a/Lib/test/pickletester.py +++ b/Lib/test/pickletester.py @@ -65,6 +65,10 @@ def count_opcode(code, pickle): return n +def identity(x): + return x + + class UnseekableIO(io.BytesIO): def peek(self, *args): raise NotImplementedError @@ -134,11 +138,12 @@ class E(C): def __getinitargs__(self): return () -class H(object): +# Simple mutable object. +class Object: pass -# Hashable mutable key -class K(object): +# Hashable immutable key object containing unheshable mutable data. +class K: def __init__(self, value): self.value = value @@ -153,10 +158,6 @@ def __reduce__(self): D.__module__ = "__main__" __main__.E = E E.__module__ = "__main__" -__main__.H = H -H.__module__ = "__main__" -__main__.K = K -K.__module__ = "__main__" class myint(int): def __init__(self, x): @@ -1492,54 +1493,182 @@ def dont_test_disassembly(self): got = filelike.getvalue() self.assertEqual(expected, got) - def test_recursive_list(self): - l = [] + def _test_recursive_list(self, cls, aslist=identity, minprotocol=0): + # List containing itself. + l = cls() l.append(l) - for proto in protocols: + for proto in range(minprotocol, pickle.HIGHEST_PROTOCOL + 1): s = self.dumps(l, proto) x = self.loads(s) - self.assertIsInstance(x, list) - self.assertEqual(len(x), 1) - self.assertIs(x[0], x) + self.assertIsInstance(x, cls) + y = aslist(x) + self.assertEqual(len(y), 1) + self.assertIs(y[0], x) - def test_recursive_tuple_and_list(self): - t = ([],) + def test_recursive_list(self): + self._test_recursive_list(list) + + def test_recursive_list_subclass(self): + self._test_recursive_list(MyList, minprotocol=2) + + def test_recursive_list_like(self): + self._test_recursive_list(REX_six, aslist=lambda x: x.items) + + def _test_recursive_tuple_and_list(self, cls, aslist=identity, minprotocol=0): + # Tuple containing a list containing the original tuple. + t = (cls(),) t[0].append(t) - for proto in protocols: + for proto in range(minprotocol, pickle.HIGHEST_PROTOCOL + 1): s = self.dumps(t, proto) x = self.loads(s) self.assertIsInstance(x, tuple) self.assertEqual(len(x), 1) - self.assertIsInstance(x[0], list) - self.assertEqual(len(x[0]), 1) - self.assertIs(x[0][0], x) + self.assertIsInstance(x[0], cls) + y = aslist(x[0]) + self.assertEqual(len(y), 1) + self.assertIs(y[0], x) + + # List containing a tuple containing the original list. + t, = t + for proto in range(minprotocol, pickle.HIGHEST_PROTOCOL + 1): + s = self.dumps(t, proto) + x = self.loads(s) + self.assertIsInstance(x, cls) + y = aslist(x) + self.assertEqual(len(y), 1) + self.assertIsInstance(y[0], tuple) + self.assertEqual(len(y[0]), 1) + self.assertIs(y[0][0], x) - def test_recursive_dict(self): - d = {} + def test_recursive_tuple_and_list(self): + self._test_recursive_tuple_and_list(list) + + def test_recursive_tuple_and_list_subclass(self): + self._test_recursive_tuple_and_list(MyList, minprotocol=2) + + def test_recursive_tuple_and_list_like(self): + self._test_recursive_tuple_and_list(REX_six, aslist=lambda x: x.items) + + def _test_recursive_dict(self, cls, asdict=identity, minprotocol=0): + # Dict containing itself. + d = cls() d[1] = d - for proto in protocols: + for proto in range(minprotocol, pickle.HIGHEST_PROTOCOL + 1): s = self.dumps(d, proto) x = self.loads(s) - self.assertIsInstance(x, dict) - self.assertEqual(list(x.keys()), [1]) - self.assertIs(x[1], x) + self.assertIsInstance(x, cls) + y = asdict(x) + self.assertEqual(list(y.keys()), [1]) + self.assertIs(y[1], x) - def test_recursive_dict_key(self): - d = {} - k = K(d) - d[k] = 1 - for proto in protocols: + def test_recursive_dict(self): + self._test_recursive_dict(dict) + + def test_recursive_dict_subclass(self): + self._test_recursive_dict(MyDict, minprotocol=2) + + def test_recursive_dict_like(self): + self._test_recursive_dict(REX_seven, asdict=lambda x: x.table) + + def _test_recursive_tuple_and_dict(self, cls, asdict=identity, minprotocol=0): + # Tuple containing a dict containing the original tuple. + t = (cls(),) + t[0][1] = t + for proto in range(minprotocol, pickle.HIGHEST_PROTOCOL + 1): + s = self.dumps(t, proto) + x = self.loads(s) + self.assertIsInstance(x, tuple) + self.assertEqual(len(x), 1) + self.assertIsInstance(x[0], cls) + y = asdict(x[0]) + self.assertEqual(list(y), [1]) + self.assertIs(y[1], x) + + # Dict containing a tuple containing the original dict. + t, = t + for proto in range(minprotocol, pickle.HIGHEST_PROTOCOL + 1): + s = self.dumps(t, proto) + x = self.loads(s) + self.assertIsInstance(x, cls) + y = asdict(x) + self.assertEqual(list(y), [1]) + self.assertIsInstance(y[1], tuple) + self.assertEqual(len(y[1]), 1) + self.assertIs(y[1][0], x) + + def test_recursive_tuple_and_dict(self): + self._test_recursive_tuple_and_dict(dict) + + def test_recursive_tuple_and_dict_subclass(self): + self._test_recursive_tuple_and_dict(MyDict, minprotocol=2) + + def test_recursive_tuple_and_dict_like(self): + self._test_recursive_tuple_and_dict(REX_seven, asdict=lambda x: x.table) + + def _test_recursive_dict_key(self, cls, asdict=identity, minprotocol=0): + # Dict containing an immutable object (as key) containing the original + # dict. + d = cls() + d[K(d)] = 1 + for proto in range(minprotocol, pickle.HIGHEST_PROTOCOL + 1): s = self.dumps(d, proto) x = self.loads(s) - self.assertIsInstance(x, dict) - self.assertEqual(len(x.keys()), 1) - self.assertIsInstance(list(x.keys())[0], K) - self.assertIs(list(x.keys())[0].value, x) + self.assertIsInstance(x, cls) + y = asdict(x) + self.assertEqual(len(y.keys()), 1) + self.assertIsInstance(list(y.keys())[0], K) + self.assertIs(list(y.keys())[0].value, x) + + def test_recursive_dict_key(self): + self._test_recursive_dict_key(dict) + + def test_recursive_dict_subclass_key(self): + self._test_recursive_dict_key(MyDict, minprotocol=2) + + def test_recursive_dict_like_key(self): + self._test_recursive_dict_key(REX_seven, asdict=lambda x: x.table) + + def _test_recursive_tuple_and_dict_key(self, cls, asdict=identity, minprotocol=0): + # Tuple containing a dict containing an immutable object (as key) + # containing the original tuple. + t = (cls(),) + t[0][K(t)] = 1 + for proto in range(minprotocol, pickle.HIGHEST_PROTOCOL + 1): + s = self.dumps(t, proto) + x = self.loads(s) + self.assertIsInstance(x, tuple) + self.assertEqual(len(x), 1) + self.assertIsInstance(x[0], cls) + y = asdict(x[0]) + self.assertEqual(len(y), 1) + self.assertIsInstance(list(y.keys())[0], K) + self.assertIs(list(y.keys())[0].value, x) + + # Dict containing an immutable object (as key) containing a tuple + # containing the original dict. + t, = t + for proto in range(minprotocol, pickle.HIGHEST_PROTOCOL + 1): + s = self.dumps(t, proto) + x = self.loads(s) + self.assertIsInstance(x, cls) + y = asdict(x) + self.assertEqual(len(y), 1) + self.assertIsInstance(list(y.keys())[0], K) + self.assertIs(list(y.keys())[0].value[0], x) + + def test_recursive_tuple_and_dict_key(self): + self._test_recursive_tuple_and_dict_key(dict) + + def test_recursive_tuple_and_dict_subclass_key(self): + self._test_recursive_tuple_and_dict_key(MyDict, minprotocol=2) + + def test_recursive_tuple_and_dict_like_key(self): + self._test_recursive_tuple_and_dict_key(REX_seven, asdict=lambda x: x.table) def test_recursive_set(self): + # Set containing an immutable object containing the original set. y = set() - k = K(y) - y.add(k) + y.add(K(y)) for proto in range(4, pickle.HIGHEST_PROTOCOL + 1): s = self.dumps(y, proto) x = self.loads(s) @@ -1548,52 +1677,31 @@ def test_recursive_set(self): self.assertIsInstance(list(x)[0], K) self.assertIs(list(x)[0].value, x) - def test_recursive_list_subclass(self): - y = MyList() - y.append(y) - for proto in range(2, pickle.HIGHEST_PROTOCOL + 1): + # Immutable object containing a set containing the original object. + y, = y + for proto in range(4, pickle.HIGHEST_PROTOCOL + 1): s = self.dumps(y, proto) x = self.loads(s) - self.assertIsInstance(x, MyList) - self.assertEqual(len(x), 1) - self.assertIs(x[0], x) - - def test_recursive_dict_subclass(self): - d = MyDict() - d[1] = d - for proto in range(2, pickle.HIGHEST_PROTOCOL + 1): - s = self.dumps(d, proto) - x = self.loads(s) - self.assertIsInstance(x, MyDict) - self.assertEqual(list(x.keys()), [1]) - self.assertIs(x[1], x) - - def test_recursive_dict_subclass_key(self): - d = MyDict() - k = K(d) - d[k] = 1 - for proto in range(2, pickle.HIGHEST_PROTOCOL + 1): - s = self.dumps(d, proto) - x = self.loads(s) - self.assertIsInstance(x, MyDict) - self.assertEqual(len(list(x.keys())), 1) - self.assertIsInstance(list(x.keys())[0], K) - self.assertIs(list(x.keys())[0].value, x) + self.assertIsInstance(x, K) + self.assertIsInstance(x.value, set) + self.assertEqual(len(x.value), 1) + self.assertIs(list(x.value)[0], x) def test_recursive_inst(self): - i = C() + # Mutable object containing itself. + i = Object() i.attr = i for proto in protocols: s = self.dumps(i, proto) x = self.loads(s) - self.assertIsInstance(x, C) + self.assertIsInstance(x, Object) self.assertEqual(dir(x), dir(i)) self.assertIs(x.attr, x) def test_recursive_multi(self): l = [] d = {1:l} - i = C() + i = Object() i.attr = d l.append(i) for proto in protocols: @@ -1603,49 +1711,94 @@ def test_recursive_multi(self): self.assertEqual(len(x), 1) self.assertEqual(dir(x[0]), dir(i)) self.assertEqual(list(x[0].attr.keys()), [1]) - self.assertTrue(x[0].attr[1] is x) - - def check_recursive_collection_and_inst(self, factory): - h = H() - y = factory([h]) - h.attr = y + self.assertIs(x[0].attr[1], x) + + def _test_recursive_collection_and_inst(self, factory): + # Mutable object containing a collection containing the original + # object. + o = Object() + o.attr = factory([o]) + t = type(o.attr) for proto in protocols: - s = self.dumps(y, proto) + s = self.dumps(o, proto) x = self.loads(s) - self.assertIsInstance(x, type(y)) + self.assertIsInstance(x.attr, t) + self.assertEqual(len(x.attr), 1) + self.assertIsInstance(list(x.attr)[0], Object) + self.assertIs(list(x.attr)[0], x) + + # Collection containing a mutable object containing the original + # collection. + o = o.attr + for proto in protocols: + s = self.dumps(o, proto) + x = self.loads(s) + self.assertIsInstance(x, t) self.assertEqual(len(x), 1) - self.assertIsInstance(list(x)[0], H) + self.assertIsInstance(list(x)[0], Object) self.assertIs(list(x)[0].attr, x) def test_recursive_list_and_inst(self): - self.check_recursive_collection_and_inst(list) + self._test_recursive_collection_and_inst(list) def test_recursive_tuple_and_inst(self): - self.check_recursive_collection_and_inst(tuple) + self._test_recursive_collection_and_inst(tuple) def test_recursive_dict_and_inst(self): - self.check_recursive_collection_and_inst(dict.fromkeys) + self._test_recursive_collection_and_inst(dict.fromkeys) def test_recursive_set_and_inst(self): - self.check_recursive_collection_and_inst(set) + self._test_recursive_collection_and_inst(set) def test_recursive_frozenset_and_inst(self): - self.check_recursive_collection_and_inst(frozenset) + self._test_recursive_collection_and_inst(frozenset) def test_recursive_list_subclass_and_inst(self): - self.check_recursive_collection_and_inst(MyList) + self._test_recursive_collection_and_inst(MyList) def test_recursive_tuple_subclass_and_inst(self): - self.check_recursive_collection_and_inst(MyTuple) + self._test_recursive_collection_and_inst(MyTuple) def test_recursive_dict_subclass_and_inst(self): - self.check_recursive_collection_and_inst(MyDict.fromkeys) + self._test_recursive_collection_and_inst(MyDict.fromkeys) def test_recursive_set_subclass_and_inst(self): - self.check_recursive_collection_and_inst(MySet) + self._test_recursive_collection_and_inst(MySet) def test_recursive_frozenset_subclass_and_inst(self): - self.check_recursive_collection_and_inst(MyFrozenSet) + self._test_recursive_collection_and_inst(MyFrozenSet) + + def test_recursive_inst_state(self): + # Mutable object containing itself. + y = REX_state() + y.state = y + for proto in protocols: + s = self.dumps(y, proto) + x = self.loads(s) + self.assertIsInstance(x, REX_state) + self.assertIs(x.state, x) + + def test_recursive_tuple_and_inst_state(self): + # Tuple containing a mutable object containing the original tuple. + t = (REX_state(),) + t[0].state = t + for proto in protocols: + s = self.dumps(t, proto) + x = self.loads(s) + self.assertIsInstance(x, tuple) + self.assertEqual(len(x), 1) + self.assertIsInstance(x[0], REX_state) + self.assertIs(x[0].state, x) + + # Mutable object containing a tuple containing the object. + t, = t + for proto in protocols: + s = self.dumps(t, proto) + x = self.loads(s) + self.assertIsInstance(x, REX_state) + self.assertIsInstance(x.state, tuple) + self.assertEqual(len(x.state), 1) + self.assertIs(x.state[0], x) def test_unicode(self): endcases = ['', '<\\u>', '<\\\u1234>', '<\n>', @@ -3058,6 +3211,19 @@ def __setitem__(self, key, value): def __reduce__(self): return type(self), (), None, None, iter(self.table.items()) +class REX_state(object): + """This class is used to check the 3th argument (state) of + the reduce protocol. + """ + def __init__(self, state=None): + self.state = state + def __eq__(self, other): + return type(self) is type(other) and self.state == other.state + def __setstate__(self, state): + self.state = state + def __reduce__(self): + return type(self), (), self.state + # Test classes for newobj From 9a608ac17c284008d3c2986a4a8b194f84488e56 Mon Sep 17 00:00:00 2001 From: Lysandros Nikolaou Date: Sun, 3 Jan 2021 02:59:39 +0200 Subject: [PATCH 0866/1314] [3.9] bpo-40631: Disallow single parenthesized star target (GH-24027) (GH-24068) (cherry picked from commit 2ea320dddd553298038bb7d6789e50e199332f66) Automerge-Triggered-By: GH:pablogsal --- Grammar/python.gram | 13 +- Lib/test/test_unpack_ex.py | 25 + .../2020-12-31-20-58-22.bpo-40631.deRMCx.rst | 2 + Parser/pegen/parse.c | 1327 ++++++++++------- 4 files changed, 823 insertions(+), 544 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2020-12-31-20-58-22.bpo-40631.deRMCx.rst diff --git a/Grammar/python.gram b/Grammar/python.gram index ce783971968dc5..64e205e7fd8154 100644 --- a/Grammar/python.gram +++ b/Grammar/python.gram @@ -563,18 +563,23 @@ star_targets[expr_ty]: | a=star_target !',' { a } | a=star_target b=(',' c=star_target { c })* [','] { _Py_Tuple(CHECK(_PyPegen_seq_insert_in_front(p, a, b)), Store, EXTRA) } -star_targets_seq[asdl_seq*]: a=','.star_target+ [','] { a } +star_targets_list_seq[asdl_seq*]: a=','.star_target+ [','] { a } +star_targets_tuple_seq[asdl_seq*]: + | a=star_target b=(',' c=star_target { c })+ [','] { _PyPegen_seq_insert_in_front(p, a, b) } + | a=star_target ',' { _PyPegen_singleton_seq(p, a) } star_target[expr_ty] (memo): | '*' a=(!'*' star_target) { _Py_Starred(CHECK(_PyPegen_set_expr_context(p, a, Store)), Store, EXTRA) } + | target_with_star_atom +target_with_star_atom[expr_ty] (memo): | a=t_primary '.' b=NAME !t_lookahead { _Py_Attribute(a, b->v.Name.id, Store, EXTRA) } | a=t_primary '[' b=slices ']' !t_lookahead { _Py_Subscript(a, b, Store, EXTRA) } | star_atom star_atom[expr_ty]: | a=NAME { _PyPegen_set_expr_context(p, a, Store) } - | '(' a=star_target ')' { _PyPegen_set_expr_context(p, a, Store) } - | '(' a=[star_targets_seq] ')' { _Py_Tuple(a, Store, EXTRA) } - | '[' a=[star_targets_seq] ']' { _Py_List(a, Store, EXTRA) } + | '(' a=target_with_star_atom ')' { _PyPegen_set_expr_context(p, a, Store) } + | '(' a=[star_targets_tuple_seq] ')' { _Py_Tuple(a, Store, EXTRA) } + | '[' a=[star_targets_list_seq] ']' { _Py_List(a, Store, EXTRA) } single_target[expr_ty]: | single_subscript_attribute_target diff --git a/Lib/test/test_unpack_ex.py b/Lib/test/test_unpack_ex.py index fcc93829cc3b84..049e48b13fa1f9 100644 --- a/Lib/test/test_unpack_ex.py +++ b/Lib/test/test_unpack_ex.py @@ -346,6 +346,31 @@ ... SyntaxError: can't use starred expression here + >>> (*x),y = 1, 2 # doctest:+ELLIPSIS + Traceback (most recent call last): + ... + SyntaxError: can't use starred expression here + + >>> (((*x))),y = 1, 2 # doctest:+ELLIPSIS + Traceback (most recent call last): + ... + SyntaxError: can't use starred expression here + + >>> z,(*x),y = 1, 2, 4 # doctest:+ELLIPSIS + Traceback (most recent call last): + ... + SyntaxError: can't use starred expression here + + >>> z,(*x) = 1, 2 # doctest:+ELLIPSIS + Traceback (most recent call last): + ... + SyntaxError: can't use starred expression here + + >>> ((*x),y) = 1, 2 # doctest:+ELLIPSIS + Traceback (most recent call last): + ... + SyntaxError: can't use starred expression here + Some size constraints (all fail.) >>> s = ", ".join("a%d" % i for i in range(1<<8)) + ", *rest = range(1<<8 + 1)" diff --git a/Misc/NEWS.d/next/Core and Builtins/2020-12-31-20-58-22.bpo-40631.deRMCx.rst b/Misc/NEWS.d/next/Core and Builtins/2020-12-31-20-58-22.bpo-40631.deRMCx.rst new file mode 100644 index 00000000000000..ac2db2938237f8 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2020-12-31-20-58-22.bpo-40631.deRMCx.rst @@ -0,0 +1,2 @@ +Fix regression where a single parenthesized starred expression was a valid +assignment target. diff --git a/Parser/pegen/parse.c b/Parser/pegen/parse.c index 0eb61db39a40a4..98008a5fc1462a 100644 --- a/Parser/pegen/parse.c +++ b/Parser/pegen/parse.c @@ -204,192 +204,196 @@ static KeywordToken *reserved_keywords[] = { #define kwarg_or_starred_type 1126 #define kwarg_or_double_starred_type 1127 #define star_targets_type 1128 -#define star_targets_seq_type 1129 -#define star_target_type 1130 -#define star_atom_type 1131 -#define single_target_type 1132 -#define single_subscript_attribute_target_type 1133 -#define del_targets_type 1134 -#define del_target_type 1135 -#define del_t_atom_type 1136 -#define targets_type 1137 -#define target_type 1138 -#define t_primary_type 1139 // Left-recursive -#define t_lookahead_type 1140 -#define t_atom_type 1141 -#define invalid_arguments_type 1142 -#define invalid_kwarg_type 1143 -#define invalid_named_expression_type 1144 -#define invalid_assignment_type 1145 -#define invalid_ann_assign_target_type 1146 -#define invalid_del_stmt_type 1147 -#define invalid_block_type 1148 -#define invalid_primary_type 1149 // Left-recursive -#define invalid_comprehension_type 1150 -#define invalid_dict_comprehension_type 1151 -#define invalid_parameters_type 1152 -#define invalid_lambda_parameters_type 1153 -#define invalid_star_etc_type 1154 -#define invalid_lambda_star_etc_type 1155 -#define invalid_double_type_comments_type 1156 -#define invalid_with_item_type 1157 -#define invalid_for_target_type 1158 -#define invalid_group_type 1159 -#define invalid_import_from_targets_type 1160 -#define _loop0_1_type 1161 -#define _loop0_2_type 1162 -#define _loop0_4_type 1163 -#define _gather_3_type 1164 -#define _loop0_6_type 1165 -#define _gather_5_type 1166 -#define _loop0_8_type 1167 -#define _gather_7_type 1168 -#define _loop0_10_type 1169 -#define _gather_9_type 1170 -#define _loop1_11_type 1171 -#define _loop0_13_type 1172 -#define _gather_12_type 1173 -#define _tmp_14_type 1174 -#define _tmp_15_type 1175 -#define _tmp_16_type 1176 -#define _tmp_17_type 1177 -#define _tmp_18_type 1178 -#define _tmp_19_type 1179 -#define _tmp_20_type 1180 -#define _tmp_21_type 1181 -#define _loop1_22_type 1182 -#define _tmp_23_type 1183 -#define _tmp_24_type 1184 -#define _loop0_26_type 1185 -#define _gather_25_type 1186 -#define _loop0_28_type 1187 -#define _gather_27_type 1188 -#define _tmp_29_type 1189 -#define _tmp_30_type 1190 -#define _loop0_31_type 1191 -#define _loop1_32_type 1192 -#define _loop0_34_type 1193 -#define _gather_33_type 1194 -#define _tmp_35_type 1195 -#define _loop0_37_type 1196 -#define _gather_36_type 1197 -#define _tmp_38_type 1198 -#define _loop0_40_type 1199 -#define _gather_39_type 1200 -#define _loop0_42_type 1201 -#define _gather_41_type 1202 -#define _loop0_44_type 1203 -#define _gather_43_type 1204 -#define _loop0_46_type 1205 -#define _gather_45_type 1206 -#define _tmp_47_type 1207 -#define _loop1_48_type 1208 -#define _tmp_49_type 1209 -#define _tmp_50_type 1210 -#define _tmp_51_type 1211 -#define _tmp_52_type 1212 -#define _tmp_53_type 1213 -#define _loop0_54_type 1214 -#define _loop0_55_type 1215 -#define _loop0_56_type 1216 -#define _loop1_57_type 1217 -#define _loop0_58_type 1218 -#define _loop1_59_type 1219 -#define _loop1_60_type 1220 -#define _loop1_61_type 1221 -#define _loop0_62_type 1222 -#define _loop1_63_type 1223 -#define _loop0_64_type 1224 -#define _loop1_65_type 1225 -#define _loop0_66_type 1226 -#define _loop1_67_type 1227 -#define _loop1_68_type 1228 -#define _tmp_69_type 1229 -#define _loop1_70_type 1230 -#define _loop0_72_type 1231 -#define _gather_71_type 1232 -#define _loop1_73_type 1233 -#define _loop0_74_type 1234 -#define _loop0_75_type 1235 -#define _loop0_76_type 1236 -#define _loop1_77_type 1237 -#define _loop0_78_type 1238 -#define _loop1_79_type 1239 -#define _loop1_80_type 1240 -#define _loop1_81_type 1241 -#define _loop0_82_type 1242 -#define _loop1_83_type 1243 -#define _loop0_84_type 1244 -#define _loop1_85_type 1245 -#define _loop0_86_type 1246 -#define _loop1_87_type 1247 -#define _loop1_88_type 1248 -#define _loop1_89_type 1249 -#define _loop1_90_type 1250 -#define _tmp_91_type 1251 -#define _loop0_93_type 1252 -#define _gather_92_type 1253 -#define _tmp_94_type 1254 -#define _tmp_95_type 1255 -#define _tmp_96_type 1256 -#define _tmp_97_type 1257 -#define _loop1_98_type 1258 -#define _tmp_99_type 1259 -#define _tmp_100_type 1260 -#define _loop0_102_type 1261 -#define _gather_101_type 1262 -#define _loop1_103_type 1263 -#define _loop0_104_type 1264 -#define _loop0_105_type 1265 -#define _loop0_107_type 1266 -#define _gather_106_type 1267 -#define _tmp_108_type 1268 -#define _loop0_110_type 1269 -#define _gather_109_type 1270 -#define _loop0_112_type 1271 -#define _gather_111_type 1272 -#define _loop0_114_type 1273 -#define _gather_113_type 1274 -#define _loop0_116_type 1275 -#define _gather_115_type 1276 -#define _loop0_117_type 1277 -#define _loop0_119_type 1278 -#define _gather_118_type 1279 -#define _tmp_120_type 1280 -#define _loop0_122_type 1281 -#define _gather_121_type 1282 -#define _loop0_124_type 1283 -#define _gather_123_type 1284 -#define _tmp_125_type 1285 -#define _loop0_126_type 1286 -#define _loop0_127_type 1287 -#define _loop0_128_type 1288 -#define _tmp_129_type 1289 -#define _tmp_130_type 1290 -#define _loop0_131_type 1291 -#define _tmp_132_type 1292 -#define _loop0_133_type 1293 -#define _tmp_134_type 1294 -#define _tmp_135_type 1295 -#define _tmp_136_type 1296 -#define _tmp_137_type 1297 -#define _tmp_138_type 1298 -#define _tmp_139_type 1299 -#define _tmp_140_type 1300 -#define _tmp_141_type 1301 -#define _tmp_142_type 1302 -#define _tmp_143_type 1303 -#define _tmp_144_type 1304 -#define _tmp_145_type 1305 -#define _tmp_146_type 1306 -#define _tmp_147_type 1307 -#define _tmp_148_type 1308 -#define _tmp_149_type 1309 -#define _tmp_150_type 1310 -#define _loop1_151_type 1311 -#define _loop1_152_type 1312 -#define _tmp_153_type 1313 -#define _tmp_154_type 1314 +#define star_targets_list_seq_type 1129 +#define star_targets_tuple_seq_type 1130 +#define star_target_type 1131 +#define target_with_star_atom_type 1132 +#define star_atom_type 1133 +#define single_target_type 1134 +#define single_subscript_attribute_target_type 1135 +#define del_targets_type 1136 +#define del_target_type 1137 +#define del_t_atom_type 1138 +#define targets_type 1139 +#define target_type 1140 +#define t_primary_type 1141 // Left-recursive +#define t_lookahead_type 1142 +#define t_atom_type 1143 +#define invalid_arguments_type 1144 +#define invalid_kwarg_type 1145 +#define invalid_named_expression_type 1146 +#define invalid_assignment_type 1147 +#define invalid_ann_assign_target_type 1148 +#define invalid_del_stmt_type 1149 +#define invalid_block_type 1150 +#define invalid_primary_type 1151 // Left-recursive +#define invalid_comprehension_type 1152 +#define invalid_dict_comprehension_type 1153 +#define invalid_parameters_type 1154 +#define invalid_lambda_parameters_type 1155 +#define invalid_star_etc_type 1156 +#define invalid_lambda_star_etc_type 1157 +#define invalid_double_type_comments_type 1158 +#define invalid_with_item_type 1159 +#define invalid_for_target_type 1160 +#define invalid_group_type 1161 +#define invalid_import_from_targets_type 1162 +#define _loop0_1_type 1163 +#define _loop0_2_type 1164 +#define _loop0_4_type 1165 +#define _gather_3_type 1166 +#define _loop0_6_type 1167 +#define _gather_5_type 1168 +#define _loop0_8_type 1169 +#define _gather_7_type 1170 +#define _loop0_10_type 1171 +#define _gather_9_type 1172 +#define _loop1_11_type 1173 +#define _loop0_13_type 1174 +#define _gather_12_type 1175 +#define _tmp_14_type 1176 +#define _tmp_15_type 1177 +#define _tmp_16_type 1178 +#define _tmp_17_type 1179 +#define _tmp_18_type 1180 +#define _tmp_19_type 1181 +#define _tmp_20_type 1182 +#define _tmp_21_type 1183 +#define _loop1_22_type 1184 +#define _tmp_23_type 1185 +#define _tmp_24_type 1186 +#define _loop0_26_type 1187 +#define _gather_25_type 1188 +#define _loop0_28_type 1189 +#define _gather_27_type 1190 +#define _tmp_29_type 1191 +#define _tmp_30_type 1192 +#define _loop0_31_type 1193 +#define _loop1_32_type 1194 +#define _loop0_34_type 1195 +#define _gather_33_type 1196 +#define _tmp_35_type 1197 +#define _loop0_37_type 1198 +#define _gather_36_type 1199 +#define _tmp_38_type 1200 +#define _loop0_40_type 1201 +#define _gather_39_type 1202 +#define _loop0_42_type 1203 +#define _gather_41_type 1204 +#define _loop0_44_type 1205 +#define _gather_43_type 1206 +#define _loop0_46_type 1207 +#define _gather_45_type 1208 +#define _tmp_47_type 1209 +#define _loop1_48_type 1210 +#define _tmp_49_type 1211 +#define _tmp_50_type 1212 +#define _tmp_51_type 1213 +#define _tmp_52_type 1214 +#define _tmp_53_type 1215 +#define _loop0_54_type 1216 +#define _loop0_55_type 1217 +#define _loop0_56_type 1218 +#define _loop1_57_type 1219 +#define _loop0_58_type 1220 +#define _loop1_59_type 1221 +#define _loop1_60_type 1222 +#define _loop1_61_type 1223 +#define _loop0_62_type 1224 +#define _loop1_63_type 1225 +#define _loop0_64_type 1226 +#define _loop1_65_type 1227 +#define _loop0_66_type 1228 +#define _loop1_67_type 1229 +#define _loop1_68_type 1230 +#define _tmp_69_type 1231 +#define _loop1_70_type 1232 +#define _loop0_72_type 1233 +#define _gather_71_type 1234 +#define _loop1_73_type 1235 +#define _loop0_74_type 1236 +#define _loop0_75_type 1237 +#define _loop0_76_type 1238 +#define _loop1_77_type 1239 +#define _loop0_78_type 1240 +#define _loop1_79_type 1241 +#define _loop1_80_type 1242 +#define _loop1_81_type 1243 +#define _loop0_82_type 1244 +#define _loop1_83_type 1245 +#define _loop0_84_type 1246 +#define _loop1_85_type 1247 +#define _loop0_86_type 1248 +#define _loop1_87_type 1249 +#define _loop1_88_type 1250 +#define _loop1_89_type 1251 +#define _loop1_90_type 1252 +#define _tmp_91_type 1253 +#define _loop0_93_type 1254 +#define _gather_92_type 1255 +#define _tmp_94_type 1256 +#define _tmp_95_type 1257 +#define _tmp_96_type 1258 +#define _tmp_97_type 1259 +#define _loop1_98_type 1260 +#define _tmp_99_type 1261 +#define _tmp_100_type 1262 +#define _loop0_102_type 1263 +#define _gather_101_type 1264 +#define _loop1_103_type 1265 +#define _loop0_104_type 1266 +#define _loop0_105_type 1267 +#define _loop0_107_type 1268 +#define _gather_106_type 1269 +#define _tmp_108_type 1270 +#define _loop0_110_type 1271 +#define _gather_109_type 1272 +#define _loop0_112_type 1273 +#define _gather_111_type 1274 +#define _loop0_114_type 1275 +#define _gather_113_type 1276 +#define _loop0_116_type 1277 +#define _gather_115_type 1278 +#define _loop0_117_type 1279 +#define _loop0_119_type 1280 +#define _gather_118_type 1281 +#define _loop1_120_type 1282 +#define _tmp_121_type 1283 +#define _loop0_123_type 1284 +#define _gather_122_type 1285 +#define _loop0_125_type 1286 +#define _gather_124_type 1287 +#define _tmp_126_type 1288 +#define _loop0_127_type 1289 +#define _loop0_128_type 1290 +#define _loop0_129_type 1291 +#define _tmp_130_type 1292 +#define _tmp_131_type 1293 +#define _loop0_132_type 1294 +#define _tmp_133_type 1295 +#define _loop0_134_type 1296 +#define _tmp_135_type 1297 +#define _tmp_136_type 1298 +#define _tmp_137_type 1299 +#define _tmp_138_type 1300 +#define _tmp_139_type 1301 +#define _tmp_140_type 1302 +#define _tmp_141_type 1303 +#define _tmp_142_type 1304 +#define _tmp_143_type 1305 +#define _tmp_144_type 1306 +#define _tmp_145_type 1307 +#define _tmp_146_type 1308 +#define _tmp_147_type 1309 +#define _tmp_148_type 1310 +#define _tmp_149_type 1311 +#define _tmp_150_type 1312 +#define _tmp_151_type 1313 +#define _tmp_152_type 1314 +#define _loop1_153_type 1315 +#define _loop1_154_type 1316 +#define _tmp_155_type 1317 +#define _tmp_156_type 1318 static mod_ty file_rule(Parser *p); static mod_ty interactive_rule(Parser *p); @@ -520,8 +524,10 @@ static expr_ty starred_expression_rule(Parser *p); static KeywordOrStarred* kwarg_or_starred_rule(Parser *p); static KeywordOrStarred* kwarg_or_double_starred_rule(Parser *p); static expr_ty star_targets_rule(Parser *p); -static asdl_seq* star_targets_seq_rule(Parser *p); +static asdl_seq* star_targets_list_seq_rule(Parser *p); +static asdl_seq* star_targets_tuple_seq_rule(Parser *p); static expr_ty star_target_rule(Parser *p); +static expr_ty target_with_star_atom_rule(Parser *p); static expr_ty star_atom_rule(Parser *p); static expr_ty single_target_rule(Parser *p); static expr_ty single_subscript_attribute_target_rule(Parser *p); @@ -671,21 +677,21 @@ static asdl_seq *_gather_115_rule(Parser *p); static asdl_seq *_loop0_117_rule(Parser *p); static asdl_seq *_loop0_119_rule(Parser *p); static asdl_seq *_gather_118_rule(Parser *p); -static void *_tmp_120_rule(Parser *p); -static asdl_seq *_loop0_122_rule(Parser *p); -static asdl_seq *_gather_121_rule(Parser *p); -static asdl_seq *_loop0_124_rule(Parser *p); -static asdl_seq *_gather_123_rule(Parser *p); -static void *_tmp_125_rule(Parser *p); -static asdl_seq *_loop0_126_rule(Parser *p); +static asdl_seq *_loop1_120_rule(Parser *p); +static void *_tmp_121_rule(Parser *p); +static asdl_seq *_loop0_123_rule(Parser *p); +static asdl_seq *_gather_122_rule(Parser *p); +static asdl_seq *_loop0_125_rule(Parser *p); +static asdl_seq *_gather_124_rule(Parser *p); +static void *_tmp_126_rule(Parser *p); static asdl_seq *_loop0_127_rule(Parser *p); static asdl_seq *_loop0_128_rule(Parser *p); -static void *_tmp_129_rule(Parser *p); +static asdl_seq *_loop0_129_rule(Parser *p); static void *_tmp_130_rule(Parser *p); -static asdl_seq *_loop0_131_rule(Parser *p); -static void *_tmp_132_rule(Parser *p); -static asdl_seq *_loop0_133_rule(Parser *p); -static void *_tmp_134_rule(Parser *p); +static void *_tmp_131_rule(Parser *p); +static asdl_seq *_loop0_132_rule(Parser *p); +static void *_tmp_133_rule(Parser *p); +static asdl_seq *_loop0_134_rule(Parser *p); static void *_tmp_135_rule(Parser *p); static void *_tmp_136_rule(Parser *p); static void *_tmp_137_rule(Parser *p); @@ -702,10 +708,12 @@ static void *_tmp_147_rule(Parser *p); static void *_tmp_148_rule(Parser *p); static void *_tmp_149_rule(Parser *p); static void *_tmp_150_rule(Parser *p); -static asdl_seq *_loop1_151_rule(Parser *p); -static asdl_seq *_loop1_152_rule(Parser *p); -static void *_tmp_153_rule(Parser *p); -static void *_tmp_154_rule(Parser *p); +static void *_tmp_151_rule(Parser *p); +static void *_tmp_152_rule(Parser *p); +static asdl_seq *_loop1_153_rule(Parser *p); +static asdl_seq *_loop1_154_rule(Parser *p); +static void *_tmp_155_rule(Parser *p); +static void *_tmp_156_rule(Parser *p); // file: statements? $ @@ -12791,9 +12799,9 @@ star_targets_rule(Parser *p) return _res; } -// star_targets_seq: ','.star_target+ ','? +// star_targets_list_seq: ','.star_target+ ','? static asdl_seq* -star_targets_seq_rule(Parser *p) +star_targets_list_seq_rule(Parser *p) { D(p->level++); if (p->error_indicator) { @@ -12807,7 +12815,7 @@ star_targets_seq_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> star_targets_seq[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','.star_target+ ','?")); + D(fprintf(stderr, "%*c> star_targets_list_seq[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','.star_target+ ','?")); void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings asdl_seq * a; @@ -12817,7 +12825,7 @@ star_targets_seq_rule(Parser *p) (_opt_var = _PyPegen_expect_token(p, 12), 1) // ','? ) { - D(fprintf(stderr, "%*c+ star_targets_seq[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','.star_target+ ','?")); + D(fprintf(stderr, "%*c+ star_targets_list_seq[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','.star_target+ ','?")); _res = a; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -12827,7 +12835,7 @@ star_targets_seq_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s star_targets_seq[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s star_targets_list_seq[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "','.star_target+ ','?")); } _res = NULL; @@ -12836,11 +12844,82 @@ star_targets_seq_rule(Parser *p) return _res; } -// star_target: -// | '*' (!'*' star_target) -// | t_primary '.' NAME !t_lookahead -// | t_primary '[' slices ']' !t_lookahead -// | star_atom +// star_targets_tuple_seq: star_target ((',' star_target))+ ','? | star_target ',' +static asdl_seq* +star_targets_tuple_seq_rule(Parser *p) +{ + D(p->level++); + if (p->error_indicator) { + D(p->level--); + return NULL; + } + asdl_seq* _res = NULL; + int _mark = p->mark; + { // star_target ((',' star_target))+ ','? + if (p->error_indicator) { + D(p->level--); + return NULL; + } + D(fprintf(stderr, "%*c> star_targets_tuple_seq[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_target ((',' star_target))+ ','?")); + void *_opt_var; + UNUSED(_opt_var); // Silence compiler warnings + expr_ty a; + asdl_seq * b; + if ( + (a = star_target_rule(p)) // star_target + && + (b = _loop1_120_rule(p)) // ((',' star_target))+ + && + (_opt_var = _PyPegen_expect_token(p, 12), 1) // ','? + ) + { + D(fprintf(stderr, "%*c+ star_targets_tuple_seq[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_target ((',' star_target))+ ','?")); + _res = _PyPegen_seq_insert_in_front ( p , a , b ); + if (_res == NULL && PyErr_Occurred()) { + p->error_indicator = 1; + D(p->level--); + return NULL; + } + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s star_targets_tuple_seq[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_target ((',' star_target))+ ','?")); + } + { // star_target ',' + if (p->error_indicator) { + D(p->level--); + return NULL; + } + D(fprintf(stderr, "%*c> star_targets_tuple_seq[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_target ','")); + Token * _literal; + expr_ty a; + if ( + (a = star_target_rule(p)) // star_target + && + (_literal = _PyPegen_expect_token(p, 12)) // token=',' + ) + { + D(fprintf(stderr, "%*c+ star_targets_tuple_seq[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_target ','")); + _res = _PyPegen_singleton_seq ( p , a ); + if (_res == NULL && PyErr_Occurred()) { + p->error_indicator = 1; + D(p->level--); + return NULL; + } + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s star_targets_tuple_seq[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_target ','")); + } + _res = NULL; + done: + D(p->level--); + return _res; +} + +// star_target: '*' (!'*' star_target) | target_with_star_atom static expr_ty star_target_rule(Parser *p) { @@ -12875,7 +12954,7 @@ star_target_rule(Parser *p) if ( (_literal = _PyPegen_expect_token(p, 16)) // token='*' && - (a = _tmp_120_rule(p)) // !'*' star_target + (a = _tmp_121_rule(p)) // !'*' star_target ) { D(fprintf(stderr, "%*c+ star_target[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'*' (!'*' star_target)")); @@ -12900,12 +12979,65 @@ star_target_rule(Parser *p) D(fprintf(stderr, "%*c%s star_target[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'*' (!'*' star_target)")); } + { // target_with_star_atom + if (p->error_indicator) { + D(p->level--); + return NULL; + } + D(fprintf(stderr, "%*c> star_target[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "target_with_star_atom")); + expr_ty target_with_star_atom_var; + if ( + (target_with_star_atom_var = target_with_star_atom_rule(p)) // target_with_star_atom + ) + { + D(fprintf(stderr, "%*c+ star_target[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "target_with_star_atom")); + _res = target_with_star_atom_var; + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s star_target[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "target_with_star_atom")); + } + _res = NULL; + done: + _PyPegen_insert_memo(p, _mark, star_target_type, _res); + D(p->level--); + return _res; +} + +// target_with_star_atom: +// | t_primary '.' NAME !t_lookahead +// | t_primary '[' slices ']' !t_lookahead +// | star_atom +static expr_ty +target_with_star_atom_rule(Parser *p) +{ + D(p->level++); + if (p->error_indicator) { + D(p->level--); + return NULL; + } + expr_ty _res = NULL; + if (_PyPegen_is_memoized(p, target_with_star_atom_type, &_res)) { + D(p->level--); + return _res; + } + int _mark = p->mark; + if (p->mark == p->fill && _PyPegen_fill_token(p) < 0) { + p->error_indicator = 1; + D(p->level--); + return NULL; + } + int _start_lineno = p->tokens[_mark]->lineno; + UNUSED(_start_lineno); // Only used by EXTRA macro + int _start_col_offset = p->tokens[_mark]->col_offset; + UNUSED(_start_col_offset); // Only used by EXTRA macro { // t_primary '.' NAME !t_lookahead if (p->error_indicator) { D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> star_target[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "t_primary '.' NAME !t_lookahead")); + D(fprintf(stderr, "%*c> target_with_star_atom[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "t_primary '.' NAME !t_lookahead")); Token * _literal; expr_ty a; expr_ty b; @@ -12919,7 +13051,7 @@ star_target_rule(Parser *p) _PyPegen_lookahead(0, t_lookahead_rule, p) ) { - D(fprintf(stderr, "%*c+ star_target[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "t_primary '.' NAME !t_lookahead")); + D(fprintf(stderr, "%*c+ target_with_star_atom[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "t_primary '.' NAME !t_lookahead")); Token *_token = _PyPegen_get_last_nonnwhitespace_token(p); if (_token == NULL) { D(p->level--); @@ -12938,7 +13070,7 @@ star_target_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s star_target[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s target_with_star_atom[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "t_primary '.' NAME !t_lookahead")); } { // t_primary '[' slices ']' !t_lookahead @@ -12946,7 +13078,7 @@ star_target_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> star_target[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "t_primary '[' slices ']' !t_lookahead")); + D(fprintf(stderr, "%*c> target_with_star_atom[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "t_primary '[' slices ']' !t_lookahead")); Token * _literal; Token * _literal_1; expr_ty a; @@ -12963,7 +13095,7 @@ star_target_rule(Parser *p) _PyPegen_lookahead(0, t_lookahead_rule, p) ) { - D(fprintf(stderr, "%*c+ star_target[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "t_primary '[' slices ']' !t_lookahead")); + D(fprintf(stderr, "%*c+ target_with_star_atom[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "t_primary '[' slices ']' !t_lookahead")); Token *_token = _PyPegen_get_last_nonnwhitespace_token(p); if (_token == NULL) { D(p->level--); @@ -12982,7 +13114,7 @@ star_target_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s star_target[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s target_with_star_atom[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "t_primary '[' slices ']' !t_lookahead")); } { // star_atom @@ -12990,32 +13122,32 @@ star_target_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> star_target[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_atom")); + D(fprintf(stderr, "%*c> target_with_star_atom[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_atom")); expr_ty star_atom_var; if ( (star_atom_var = star_atom_rule(p)) // star_atom ) { - D(fprintf(stderr, "%*c+ star_target[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_atom")); + D(fprintf(stderr, "%*c+ target_with_star_atom[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_atom")); _res = star_atom_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s star_target[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s target_with_star_atom[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_atom")); } _res = NULL; done: - _PyPegen_insert_memo(p, _mark, star_target_type, _res); + _PyPegen_insert_memo(p, _mark, target_with_star_atom_type, _res); D(p->level--); return _res; } // star_atom: // | NAME -// | '(' star_target ')' -// | '(' star_targets_seq? ')' -// | '[' star_targets_seq? ']' +// | '(' target_with_star_atom ')' +// | '(' star_targets_tuple_seq? ')' +// | '[' star_targets_list_seq? ']' static expr_ty star_atom_rule(Parser *p) { @@ -13059,24 +13191,24 @@ star_atom_rule(Parser *p) D(fprintf(stderr, "%*c%s star_atom[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "NAME")); } - { // '(' star_target ')' + { // '(' target_with_star_atom ')' if (p->error_indicator) { D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> star_atom[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'(' star_target ')'")); + D(fprintf(stderr, "%*c> star_atom[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'(' target_with_star_atom ')'")); Token * _literal; Token * _literal_1; expr_ty a; if ( (_literal = _PyPegen_expect_token(p, 7)) // token='(' && - (a = star_target_rule(p)) // star_target + (a = target_with_star_atom_rule(p)) // target_with_star_atom && (_literal_1 = _PyPegen_expect_token(p, 8)) // token=')' ) { - D(fprintf(stderr, "%*c+ star_atom[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'(' star_target ')'")); + D(fprintf(stderr, "%*c+ star_atom[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'(' target_with_star_atom ')'")); _res = _PyPegen_set_expr_context ( p , a , Store ); if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -13087,26 +13219,26 @@ star_atom_rule(Parser *p) } p->mark = _mark; D(fprintf(stderr, "%*c%s star_atom[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'(' star_target ')'")); + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'(' target_with_star_atom ')'")); } - { // '(' star_targets_seq? ')' + { // '(' star_targets_tuple_seq? ')' if (p->error_indicator) { D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> star_atom[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'(' star_targets_seq? ')'")); + D(fprintf(stderr, "%*c> star_atom[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'(' star_targets_tuple_seq? ')'")); Token * _literal; Token * _literal_1; void *a; if ( (_literal = _PyPegen_expect_token(p, 7)) // token='(' && - (a = star_targets_seq_rule(p), 1) // star_targets_seq? + (a = star_targets_tuple_seq_rule(p), 1) // star_targets_tuple_seq? && (_literal_1 = _PyPegen_expect_token(p, 8)) // token=')' ) { - D(fprintf(stderr, "%*c+ star_atom[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'(' star_targets_seq? ')'")); + D(fprintf(stderr, "%*c+ star_atom[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'(' star_targets_tuple_seq? ')'")); Token *_token = _PyPegen_get_last_nonnwhitespace_token(p); if (_token == NULL) { D(p->level--); @@ -13126,26 +13258,26 @@ star_atom_rule(Parser *p) } p->mark = _mark; D(fprintf(stderr, "%*c%s star_atom[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'(' star_targets_seq? ')'")); + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'(' star_targets_tuple_seq? ')'")); } - { // '[' star_targets_seq? ']' + { // '[' star_targets_list_seq? ']' if (p->error_indicator) { D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> star_atom[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'[' star_targets_seq? ']'")); + D(fprintf(stderr, "%*c> star_atom[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'[' star_targets_list_seq? ']'")); Token * _literal; Token * _literal_1; void *a; if ( (_literal = _PyPegen_expect_token(p, 9)) // token='[' && - (a = star_targets_seq_rule(p), 1) // star_targets_seq? + (a = star_targets_list_seq_rule(p), 1) // star_targets_list_seq? && (_literal_1 = _PyPegen_expect_token(p, 10)) // token=']' ) { - D(fprintf(stderr, "%*c+ star_atom[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'[' star_targets_seq? ']'")); + D(fprintf(stderr, "%*c+ star_atom[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'[' star_targets_list_seq? ']'")); Token *_token = _PyPegen_get_last_nonnwhitespace_token(p); if (_token == NULL) { D(p->level--); @@ -13165,7 +13297,7 @@ star_atom_rule(Parser *p) } p->mark = _mark; D(fprintf(stderr, "%*c%s star_atom[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'[' star_targets_seq? ']'")); + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'[' star_targets_list_seq? ']'")); } _res = NULL; done: @@ -13397,7 +13529,7 @@ del_targets_rule(Parser *p) UNUSED(_opt_var); // Silence compiler warnings asdl_seq * a; if ( - (a = _gather_121_rule(p)) // ','.del_target+ + (a = _gather_122_rule(p)) // ','.del_target+ && (_opt_var = _PyPegen_expect_token(p, 12), 1) // ','? ) @@ -13738,7 +13870,7 @@ targets_rule(Parser *p) UNUSED(_opt_var); // Silence compiler warnings asdl_seq * a; if ( - (a = _gather_123_rule(p)) // ','.target+ + (a = _gather_124_rule(p)) // ','.target+ && (_opt_var = _PyPegen_expect_token(p, 12), 1) // ','? ) @@ -14452,7 +14584,7 @@ invalid_arguments_rule(Parser *p) && (_literal = _PyPegen_expect_token(p, 12)) // token=',' && - (_opt_var = _tmp_125_rule(p), 1) // [args | expression for_if_clauses] + (_opt_var = _tmp_126_rule(p), 1) // [args | expression for_if_clauses] ) { D(fprintf(stderr, "%*c+ invalid_arguments[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression for_if_clauses ',' [args | expression for_if_clauses]")); @@ -14710,7 +14842,7 @@ invalid_assignment_rule(Parser *p) D(fprintf(stderr, "%*c> invalid_assignment[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_named_expression ',' star_named_expressions* ':' expression")); Token * _literal; Token * _literal_1; - asdl_seq * _loop0_126_var; + asdl_seq * _loop0_127_var; expr_ty a; expr_ty expression_var; if ( @@ -14718,7 +14850,7 @@ invalid_assignment_rule(Parser *p) && (_literal = _PyPegen_expect_token(p, 12)) // token=',' && - (_loop0_126_var = _loop0_126_rule(p)) // star_named_expressions* + (_loop0_127_var = _loop0_127_rule(p)) // star_named_expressions* && (_literal_1 = _PyPegen_expect_token(p, 11)) // token=':' && @@ -14775,10 +14907,10 @@ invalid_assignment_rule(Parser *p) } D(fprintf(stderr, "%*c> invalid_assignment[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "((star_targets '='))* star_expressions '='")); Token * _literal; - asdl_seq * _loop0_127_var; + asdl_seq * _loop0_128_var; expr_ty a; if ( - (_loop0_127_var = _loop0_127_rule(p)) // ((star_targets '='))* + (_loop0_128_var = _loop0_128_rule(p)) // ((star_targets '='))* && (a = star_expressions_rule(p)) // star_expressions && @@ -14805,10 +14937,10 @@ invalid_assignment_rule(Parser *p) } D(fprintf(stderr, "%*c> invalid_assignment[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "((star_targets '='))* yield_expr '='")); Token * _literal; - asdl_seq * _loop0_128_var; + asdl_seq * _loop0_129_var; expr_ty a; if ( - (_loop0_128_var = _loop0_128_rule(p)) // ((star_targets '='))* + (_loop0_129_var = _loop0_129_rule(p)) // ((star_targets '='))* && (a = yield_expr_rule(p)) // yield_expr && @@ -14834,7 +14966,7 @@ invalid_assignment_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> invalid_assignment[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_expressions augassign (yield_expr | star_expressions)")); - void *_tmp_129_var; + void *_tmp_130_var; expr_ty a; AugOperator* augassign_var; if ( @@ -14842,7 +14974,7 @@ invalid_assignment_rule(Parser *p) && (augassign_var = augassign_rule(p)) // augassign && - (_tmp_129_var = _tmp_129_rule(p)) // yield_expr | star_expressions + (_tmp_130_var = _tmp_130_rule(p)) // yield_expr | star_expressions ) { D(fprintf(stderr, "%*c+ invalid_assignment[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_expressions augassign (yield_expr | star_expressions)")); @@ -15098,11 +15230,11 @@ invalid_comprehension_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> invalid_comprehension[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('[' | '(' | '{') starred_expression for_if_clauses")); - void *_tmp_130_var; + void *_tmp_131_var; expr_ty a; asdl_seq* for_if_clauses_var; if ( - (_tmp_130_var = _tmp_130_rule(p)) // '[' | '(' | '{' + (_tmp_131_var = _tmp_131_rule(p)) // '[' | '(' | '{' && (a = starred_expression_rule(p)) // starred_expression && @@ -15199,13 +15331,13 @@ invalid_parameters_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> invalid_parameters[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_no_default* (slash_with_default | param_with_default+) param_no_default")); - asdl_seq * _loop0_131_var; - void *_tmp_132_var; + asdl_seq * _loop0_132_var; + void *_tmp_133_var; arg_ty param_no_default_var; if ( - (_loop0_131_var = _loop0_131_rule(p)) // param_no_default* + (_loop0_132_var = _loop0_132_rule(p)) // param_no_default* && - (_tmp_132_var = _tmp_132_rule(p)) // slash_with_default | param_with_default+ + (_tmp_133_var = _tmp_133_rule(p)) // slash_with_default | param_with_default+ && (param_no_default_var = param_no_default_rule(p)) // param_no_default ) @@ -15247,13 +15379,13 @@ invalid_lambda_parameters_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> invalid_lambda_parameters[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default* (lambda_slash_with_default | lambda_param_with_default+) lambda_param_no_default")); - asdl_seq * _loop0_133_var; - void *_tmp_134_var; + asdl_seq * _loop0_134_var; + void *_tmp_135_var; arg_ty lambda_param_no_default_var; if ( - (_loop0_133_var = _loop0_133_rule(p)) // lambda_param_no_default* + (_loop0_134_var = _loop0_134_rule(p)) // lambda_param_no_default* && - (_tmp_134_var = _tmp_134_rule(p)) // lambda_slash_with_default | lambda_param_with_default+ + (_tmp_135_var = _tmp_135_rule(p)) // lambda_slash_with_default | lambda_param_with_default+ && (lambda_param_no_default_var = lambda_param_no_default_rule(p)) // lambda_param_no_default ) @@ -15295,11 +15427,11 @@ invalid_star_etc_rule(Parser *p) } D(fprintf(stderr, "%*c> invalid_star_etc[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'*' (')' | ',' (')' | '**'))")); Token * _literal; - void *_tmp_135_var; + void *_tmp_136_var; if ( (_literal = _PyPegen_expect_token(p, 16)) // token='*' && - (_tmp_135_var = _tmp_135_rule(p)) // ')' | ',' (')' | '**') + (_tmp_136_var = _tmp_136_rule(p)) // ')' | ',' (')' | '**') ) { D(fprintf(stderr, "%*c+ invalid_star_etc[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'*' (')' | ',' (')' | '**'))")); @@ -15369,11 +15501,11 @@ invalid_lambda_star_etc_rule(Parser *p) } D(fprintf(stderr, "%*c> invalid_lambda_star_etc[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'*' (':' | ',' (':' | '**'))")); Token * _literal; - void *_tmp_136_var; + void *_tmp_137_var; if ( (_literal = _PyPegen_expect_token(p, 16)) // token='*' && - (_tmp_136_var = _tmp_136_rule(p)) // ':' | ',' (':' | '**') + (_tmp_137_var = _tmp_137_rule(p)) // ':' | ',' (':' | '**') ) { D(fprintf(stderr, "%*c+ invalid_lambda_star_etc[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'*' (':' | ',' (':' | '**'))")); @@ -16882,12 +17014,12 @@ _loop1_22_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> _loop1_22[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(star_targets '=')")); - void *_tmp_137_var; + void *_tmp_138_var; while ( - (_tmp_137_var = _tmp_137_rule(p)) // star_targets '=' + (_tmp_138_var = _tmp_138_rule(p)) // star_targets '=' ) { - _res = _tmp_137_var; + _res = _tmp_138_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -17390,12 +17522,12 @@ _loop0_31_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> _loop0_31[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('.' | '...')")); - void *_tmp_138_var; + void *_tmp_139_var; while ( - (_tmp_138_var = _tmp_138_rule(p)) // '.' | '...' + (_tmp_139_var = _tmp_139_rule(p)) // '.' | '...' ) { - _res = _tmp_138_var; + _res = _tmp_139_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -17456,12 +17588,12 @@ _loop1_32_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> _loop1_32[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('.' | '...')")); - void *_tmp_139_var; + void *_tmp_140_var; while ( - (_tmp_139_var = _tmp_139_rule(p)) // '.' | '...' + (_tmp_140_var = _tmp_140_rule(p)) // '.' | '...' ) { - _res = _tmp_139_var; + _res = _tmp_140_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -19618,12 +19750,12 @@ _loop1_68_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> _loop1_68[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('@' named_expression NEWLINE)")); - void *_tmp_140_var; + void *_tmp_141_var; while ( - (_tmp_140_var = _tmp_140_rule(p)) // '@' named_expression NEWLINE + (_tmp_141_var = _tmp_141_rule(p)) // '@' named_expression NEWLINE ) { - _res = _tmp_140_var; + _res = _tmp_141_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -19736,12 +19868,12 @@ _loop1_70_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> _loop1_70[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(',' star_expression)")); - void *_tmp_141_var; + void *_tmp_142_var; while ( - (_tmp_141_var = _tmp_141_rule(p)) // ',' star_expression + (_tmp_142_var = _tmp_142_rule(p)) // ',' star_expression ) { - _res = _tmp_141_var; + _res = _tmp_142_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -19921,12 +20053,12 @@ _loop1_73_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> _loop1_73[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(',' expression)")); - void *_tmp_142_var; + void *_tmp_143_var; while ( - (_tmp_142_var = _tmp_142_rule(p)) // ',' expression + (_tmp_143_var = _tmp_143_rule(p)) // ',' expression ) { - _res = _tmp_142_var; + _res = _tmp_143_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -20951,12 +21083,12 @@ _loop1_88_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> _loop1_88[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('or' conjunction)")); - void *_tmp_143_var; + void *_tmp_144_var; while ( - (_tmp_143_var = _tmp_143_rule(p)) // 'or' conjunction + (_tmp_144_var = _tmp_144_rule(p)) // 'or' conjunction ) { - _res = _tmp_143_var; + _res = _tmp_144_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -21022,12 +21154,12 @@ _loop1_89_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> _loop1_89[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('and' inversion)")); - void *_tmp_144_var; + void *_tmp_145_var; while ( - (_tmp_144_var = _tmp_144_rule(p)) // 'and' inversion + (_tmp_145_var = _tmp_145_rule(p)) // 'and' inversion ) { - _res = _tmp_144_var; + _res = _tmp_145_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -21943,12 +22075,12 @@ _loop0_104_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> _loop0_104[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('if' disjunction)")); - void *_tmp_145_var; + void *_tmp_146_var; while ( - (_tmp_145_var = _tmp_145_rule(p)) // 'if' disjunction + (_tmp_146_var = _tmp_146_rule(p)) // 'if' disjunction ) { - _res = _tmp_145_var; + _res = _tmp_146_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -22009,12 +22141,12 @@ _loop0_105_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> _loop0_105[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('if' disjunction)")); - void *_tmp_146_var; + void *_tmp_147_var; while ( - (_tmp_146_var = _tmp_146_rule(p)) // 'if' disjunction + (_tmp_147_var = _tmp_147_rule(p)) // 'if' disjunction ) { - _res = _tmp_146_var; + _res = _tmp_147_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -22080,7 +22212,7 @@ _loop0_107_rule(Parser *p) while ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' && - (elem = _tmp_147_rule(p)) // starred_expression | named_expression !'=' + (elem = _tmp_148_rule(p)) // starred_expression | named_expression !'=' ) { _res = elem; @@ -22143,7 +22275,7 @@ _gather_106_rule(Parser *p) void *elem; asdl_seq * seq; if ( - (elem = _tmp_147_rule(p)) // starred_expression | named_expression !'=' + (elem = _tmp_148_rule(p)) // starred_expression | named_expression !'=' && (seq = _loop0_107_rule(p)) // _loop0_107 ) @@ -22689,12 +22821,12 @@ _loop0_117_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> _loop0_117[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(',' star_target)")); - void *_tmp_148_var; + void *_tmp_149_var; while ( - (_tmp_148_var = _tmp_148_rule(p)) // ',' star_target + (_tmp_149_var = _tmp_149_rule(p)) // ',' star_target ) { - _res = _tmp_148_var; + _res = _tmp_149_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -22842,9 +22974,80 @@ _gather_118_rule(Parser *p) return _res; } -// _tmp_120: !'*' star_target +// _loop1_120: (',' star_target) +static asdl_seq * +_loop1_120_rule(Parser *p) +{ + D(p->level++); + if (p->error_indicator) { + D(p->level--); + return NULL; + } + void *_res = NULL; + int _mark = p->mark; + int _start_mark = p->mark; + void **_children = PyMem_Malloc(sizeof(void *)); + if (!_children) { + p->error_indicator = 1; + PyErr_NoMemory(); + D(p->level--); + return NULL; + } + ssize_t _children_capacity = 1; + ssize_t _n = 0; + { // (',' star_target) + if (p->error_indicator) { + D(p->level--); + return NULL; + } + D(fprintf(stderr, "%*c> _loop1_120[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(',' star_target)")); + void *_tmp_150_var; + while ( + (_tmp_150_var = _tmp_150_rule(p)) // ',' star_target + ) + { + _res = _tmp_150_var; + if (_n == _children_capacity) { + _children_capacity *= 2; + void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); + if (!_new_children) { + p->error_indicator = 1; + PyErr_NoMemory(); + D(p->level--); + return NULL; + } + _children = _new_children; + } + _children[_n++] = _res; + _mark = p->mark; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s _loop1_120[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(',' star_target)")); + } + if (_n == 0 || p->error_indicator) { + PyMem_Free(_children); + D(p->level--); + return NULL; + } + asdl_seq *_seq = _Py_asdl_seq_new(_n, p->arena); + if (!_seq) { + PyMem_Free(_children); + p->error_indicator = 1; + PyErr_NoMemory(); + D(p->level--); + return NULL; + } + for (int i = 0; i < _n; i++) asdl_seq_SET(_seq, i, _children[i]); + PyMem_Free(_children); + _PyPegen_insert_memo(p, _start_mark, _loop1_120_type, _seq); + D(p->level--); + return _seq; +} + +// _tmp_121: !'*' star_target static void * -_tmp_120_rule(Parser *p) +_tmp_121_rule(Parser *p) { D(p->level++); if (p->error_indicator) { @@ -22858,7 +23061,7 @@ _tmp_120_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _tmp_120[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "!'*' star_target")); + D(fprintf(stderr, "%*c> _tmp_121[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "!'*' star_target")); expr_ty star_target_var; if ( _PyPegen_lookahead_with_int(0, _PyPegen_expect_token, p, 16) // token='*' @@ -22866,12 +23069,12 @@ _tmp_120_rule(Parser *p) (star_target_var = star_target_rule(p)) // star_target ) { - D(fprintf(stderr, "%*c+ _tmp_120[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "!'*' star_target")); + D(fprintf(stderr, "%*c+ _tmp_121[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "!'*' star_target")); _res = star_target_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_120[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_121[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "!'*' star_target")); } _res = NULL; @@ -22880,9 +23083,9 @@ _tmp_120_rule(Parser *p) return _res; } -// _loop0_122: ',' del_target +// _loop0_123: ',' del_target static asdl_seq * -_loop0_122_rule(Parser *p) +_loop0_123_rule(Parser *p) { D(p->level++); if (p->error_indicator) { @@ -22906,7 +23109,7 @@ _loop0_122_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _loop0_122[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' del_target")); + D(fprintf(stderr, "%*c> _loop0_123[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' del_target")); Token * _literal; expr_ty elem; while ( @@ -22937,7 +23140,7 @@ _loop0_122_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_122[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_123[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' del_target")); } asdl_seq *_seq = _Py_asdl_seq_new(_n, p->arena); @@ -22950,14 +23153,14 @@ _loop0_122_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_122_type, _seq); + _PyPegen_insert_memo(p, _start_mark, _loop0_123_type, _seq); D(p->level--); return _seq; } -// _gather_121: del_target _loop0_122 +// _gather_122: del_target _loop0_123 static asdl_seq * -_gather_121_rule(Parser *p) +_gather_122_rule(Parser *p) { D(p->level++); if (p->error_indicator) { @@ -22966,27 +23169,27 @@ _gather_121_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // del_target _loop0_122 + { // del_target _loop0_123 if (p->error_indicator) { D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _gather_121[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "del_target _loop0_122")); + D(fprintf(stderr, "%*c> _gather_122[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "del_target _loop0_123")); expr_ty elem; asdl_seq * seq; if ( (elem = del_target_rule(p)) // del_target && - (seq = _loop0_122_rule(p)) // _loop0_122 + (seq = _loop0_123_rule(p)) // _loop0_123 ) { - D(fprintf(stderr, "%*c+ _gather_121[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "del_target _loop0_122")); + D(fprintf(stderr, "%*c+ _gather_122[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "del_target _loop0_123")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_121[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "del_target _loop0_122")); + D(fprintf(stderr, "%*c%s _gather_122[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "del_target _loop0_123")); } _res = NULL; done: @@ -22994,9 +23197,9 @@ _gather_121_rule(Parser *p) return _res; } -// _loop0_124: ',' target +// _loop0_125: ',' target static asdl_seq * -_loop0_124_rule(Parser *p) +_loop0_125_rule(Parser *p) { D(p->level++); if (p->error_indicator) { @@ -23020,7 +23223,7 @@ _loop0_124_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _loop0_124[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' target")); + D(fprintf(stderr, "%*c> _loop0_125[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' target")); Token * _literal; expr_ty elem; while ( @@ -23051,7 +23254,7 @@ _loop0_124_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_124[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_125[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' target")); } asdl_seq *_seq = _Py_asdl_seq_new(_n, p->arena); @@ -23064,14 +23267,14 @@ _loop0_124_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_124_type, _seq); + _PyPegen_insert_memo(p, _start_mark, _loop0_125_type, _seq); D(p->level--); return _seq; } -// _gather_123: target _loop0_124 +// _gather_124: target _loop0_125 static asdl_seq * -_gather_123_rule(Parser *p) +_gather_124_rule(Parser *p) { D(p->level++); if (p->error_indicator) { @@ -23080,27 +23283,27 @@ _gather_123_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // target _loop0_124 + { // target _loop0_125 if (p->error_indicator) { D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _gather_123[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "target _loop0_124")); + D(fprintf(stderr, "%*c> _gather_124[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "target _loop0_125")); expr_ty elem; asdl_seq * seq; if ( (elem = target_rule(p)) // target && - (seq = _loop0_124_rule(p)) // _loop0_124 + (seq = _loop0_125_rule(p)) // _loop0_125 ) { - D(fprintf(stderr, "%*c+ _gather_123[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "target _loop0_124")); + D(fprintf(stderr, "%*c+ _gather_124[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "target _loop0_125")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_123[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "target _loop0_124")); + D(fprintf(stderr, "%*c%s _gather_124[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "target _loop0_125")); } _res = NULL; done: @@ -23108,9 +23311,9 @@ _gather_123_rule(Parser *p) return _res; } -// _tmp_125: args | expression for_if_clauses +// _tmp_126: args | expression for_if_clauses static void * -_tmp_125_rule(Parser *p) +_tmp_126_rule(Parser *p) { D(p->level++); if (p->error_indicator) { @@ -23124,18 +23327,18 @@ _tmp_125_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _tmp_125[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "args")); + D(fprintf(stderr, "%*c> _tmp_126[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "args")); expr_ty args_var; if ( (args_var = args_rule(p)) // args ) { - D(fprintf(stderr, "%*c+ _tmp_125[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "args")); + D(fprintf(stderr, "%*c+ _tmp_126[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "args")); _res = args_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_125[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_126[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "args")); } { // expression for_if_clauses @@ -23143,7 +23346,7 @@ _tmp_125_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _tmp_125[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression for_if_clauses")); + D(fprintf(stderr, "%*c> _tmp_126[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression for_if_clauses")); expr_ty expression_var; asdl_seq* for_if_clauses_var; if ( @@ -23152,12 +23355,12 @@ _tmp_125_rule(Parser *p) (for_if_clauses_var = for_if_clauses_rule(p)) // for_if_clauses ) { - D(fprintf(stderr, "%*c+ _tmp_125[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression for_if_clauses")); + D(fprintf(stderr, "%*c+ _tmp_126[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression for_if_clauses")); _res = _PyPegen_dummy_name(p, expression_var, for_if_clauses_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_125[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_126[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "expression for_if_clauses")); } _res = NULL; @@ -23166,9 +23369,9 @@ _tmp_125_rule(Parser *p) return _res; } -// _loop0_126: star_named_expressions +// _loop0_127: star_named_expressions static asdl_seq * -_loop0_126_rule(Parser *p) +_loop0_127_rule(Parser *p) { D(p->level++); if (p->error_indicator) { @@ -23192,7 +23395,7 @@ _loop0_126_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _loop0_126[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_named_expressions")); + D(fprintf(stderr, "%*c> _loop0_127[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_named_expressions")); asdl_seq* star_named_expressions_var; while ( (star_named_expressions_var = star_named_expressions_rule(p)) // star_named_expressions @@ -23214,7 +23417,7 @@ _loop0_126_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_126[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_127[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_named_expressions")); } asdl_seq *_seq = _Py_asdl_seq_new(_n, p->arena); @@ -23227,14 +23430,14 @@ _loop0_126_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_126_type, _seq); + _PyPegen_insert_memo(p, _start_mark, _loop0_127_type, _seq); D(p->level--); return _seq; } -// _loop0_127: (star_targets '=') +// _loop0_128: (star_targets '=') static asdl_seq * -_loop0_127_rule(Parser *p) +_loop0_128_rule(Parser *p) { D(p->level++); if (p->error_indicator) { @@ -23258,13 +23461,13 @@ _loop0_127_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _loop0_127[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(star_targets '=')")); - void *_tmp_149_var; + D(fprintf(stderr, "%*c> _loop0_128[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(star_targets '=')")); + void *_tmp_151_var; while ( - (_tmp_149_var = _tmp_149_rule(p)) // star_targets '=' + (_tmp_151_var = _tmp_151_rule(p)) // star_targets '=' ) { - _res = _tmp_149_var; + _res = _tmp_151_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -23280,7 +23483,7 @@ _loop0_127_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_127[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_128[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(star_targets '=')")); } asdl_seq *_seq = _Py_asdl_seq_new(_n, p->arena); @@ -23293,14 +23496,14 @@ _loop0_127_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_127_type, _seq); + _PyPegen_insert_memo(p, _start_mark, _loop0_128_type, _seq); D(p->level--); return _seq; } -// _loop0_128: (star_targets '=') +// _loop0_129: (star_targets '=') static asdl_seq * -_loop0_128_rule(Parser *p) +_loop0_129_rule(Parser *p) { D(p->level++); if (p->error_indicator) { @@ -23324,13 +23527,13 @@ _loop0_128_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _loop0_128[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(star_targets '=')")); - void *_tmp_150_var; + D(fprintf(stderr, "%*c> _loop0_129[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(star_targets '=')")); + void *_tmp_152_var; while ( - (_tmp_150_var = _tmp_150_rule(p)) // star_targets '=' + (_tmp_152_var = _tmp_152_rule(p)) // star_targets '=' ) { - _res = _tmp_150_var; + _res = _tmp_152_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -23346,7 +23549,7 @@ _loop0_128_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_128[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_129[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(star_targets '=')")); } asdl_seq *_seq = _Py_asdl_seq_new(_n, p->arena); @@ -23359,14 +23562,14 @@ _loop0_128_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_128_type, _seq); + _PyPegen_insert_memo(p, _start_mark, _loop0_129_type, _seq); D(p->level--); return _seq; } -// _tmp_129: yield_expr | star_expressions +// _tmp_130: yield_expr | star_expressions static void * -_tmp_129_rule(Parser *p) +_tmp_130_rule(Parser *p) { D(p->level++); if (p->error_indicator) { @@ -23380,18 +23583,18 @@ _tmp_129_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _tmp_129[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "yield_expr")); + D(fprintf(stderr, "%*c> _tmp_130[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "yield_expr")); expr_ty yield_expr_var; if ( (yield_expr_var = yield_expr_rule(p)) // yield_expr ) { - D(fprintf(stderr, "%*c+ _tmp_129[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "yield_expr")); + D(fprintf(stderr, "%*c+ _tmp_130[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "yield_expr")); _res = yield_expr_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_129[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_130[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "yield_expr")); } { // star_expressions @@ -23399,18 +23602,18 @@ _tmp_129_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _tmp_129[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_expressions")); + D(fprintf(stderr, "%*c> _tmp_130[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_expressions")); expr_ty star_expressions_var; if ( (star_expressions_var = star_expressions_rule(p)) // star_expressions ) { - D(fprintf(stderr, "%*c+ _tmp_129[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_expressions")); + D(fprintf(stderr, "%*c+ _tmp_130[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_expressions")); _res = star_expressions_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_129[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_130[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_expressions")); } _res = NULL; @@ -23419,9 +23622,9 @@ _tmp_129_rule(Parser *p) return _res; } -// _tmp_130: '[' | '(' | '{' +// _tmp_131: '[' | '(' | '{' static void * -_tmp_130_rule(Parser *p) +_tmp_131_rule(Parser *p) { D(p->level++); if (p->error_indicator) { @@ -23435,18 +23638,18 @@ _tmp_130_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _tmp_130[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'['")); + D(fprintf(stderr, "%*c> _tmp_131[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'['")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 9)) // token='[' ) { - D(fprintf(stderr, "%*c+ _tmp_130[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'['")); + D(fprintf(stderr, "%*c+ _tmp_131[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'['")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_130[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_131[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'['")); } { // '(' @@ -23454,18 +23657,18 @@ _tmp_130_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _tmp_130[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'('")); + D(fprintf(stderr, "%*c> _tmp_131[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'('")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 7)) // token='(' ) { - D(fprintf(stderr, "%*c+ _tmp_130[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'('")); + D(fprintf(stderr, "%*c+ _tmp_131[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'('")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_130[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_131[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'('")); } { // '{' @@ -23473,18 +23676,18 @@ _tmp_130_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _tmp_130[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'{'")); + D(fprintf(stderr, "%*c> _tmp_131[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'{'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 25)) // token='{' ) { - D(fprintf(stderr, "%*c+ _tmp_130[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'{'")); + D(fprintf(stderr, "%*c+ _tmp_131[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'{'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_130[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_131[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'{'")); } _res = NULL; @@ -23493,9 +23696,9 @@ _tmp_130_rule(Parser *p) return _res; } -// _loop0_131: param_no_default +// _loop0_132: param_no_default static asdl_seq * -_loop0_131_rule(Parser *p) +_loop0_132_rule(Parser *p) { D(p->level++); if (p->error_indicator) { @@ -23519,7 +23722,7 @@ _loop0_131_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _loop0_131[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_no_default")); + D(fprintf(stderr, "%*c> _loop0_132[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_no_default")); arg_ty param_no_default_var; while ( (param_no_default_var = param_no_default_rule(p)) // param_no_default @@ -23541,7 +23744,7 @@ _loop0_131_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_131[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_132[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "param_no_default")); } asdl_seq *_seq = _Py_asdl_seq_new(_n, p->arena); @@ -23554,14 +23757,14 @@ _loop0_131_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_131_type, _seq); + _PyPegen_insert_memo(p, _start_mark, _loop0_132_type, _seq); D(p->level--); return _seq; } -// _tmp_132: slash_with_default | param_with_default+ +// _tmp_133: slash_with_default | param_with_default+ static void * -_tmp_132_rule(Parser *p) +_tmp_133_rule(Parser *p) { D(p->level++); if (p->error_indicator) { @@ -23575,18 +23778,18 @@ _tmp_132_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _tmp_132[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "slash_with_default")); + D(fprintf(stderr, "%*c> _tmp_133[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "slash_with_default")); SlashWithDefault* slash_with_default_var; if ( (slash_with_default_var = slash_with_default_rule(p)) // slash_with_default ) { - D(fprintf(stderr, "%*c+ _tmp_132[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "slash_with_default")); + D(fprintf(stderr, "%*c+ _tmp_133[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "slash_with_default")); _res = slash_with_default_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_132[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_133[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "slash_with_default")); } { // param_with_default+ @@ -23594,18 +23797,18 @@ _tmp_132_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _tmp_132[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_with_default+")); - asdl_seq * _loop1_151_var; + D(fprintf(stderr, "%*c> _tmp_133[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_with_default+")); + asdl_seq * _loop1_153_var; if ( - (_loop1_151_var = _loop1_151_rule(p)) // param_with_default+ + (_loop1_153_var = _loop1_153_rule(p)) // param_with_default+ ) { - D(fprintf(stderr, "%*c+ _tmp_132[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "param_with_default+")); - _res = _loop1_151_var; + D(fprintf(stderr, "%*c+ _tmp_133[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "param_with_default+")); + _res = _loop1_153_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_132[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_133[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "param_with_default+")); } _res = NULL; @@ -23614,9 +23817,9 @@ _tmp_132_rule(Parser *p) return _res; } -// _loop0_133: lambda_param_no_default +// _loop0_134: lambda_param_no_default static asdl_seq * -_loop0_133_rule(Parser *p) +_loop0_134_rule(Parser *p) { D(p->level++); if (p->error_indicator) { @@ -23640,7 +23843,7 @@ _loop0_133_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _loop0_133[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default")); + D(fprintf(stderr, "%*c> _loop0_134[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default")); arg_ty lambda_param_no_default_var; while ( (lambda_param_no_default_var = lambda_param_no_default_rule(p)) // lambda_param_no_default @@ -23662,7 +23865,7 @@ _loop0_133_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_133[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_134[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_no_default")); } asdl_seq *_seq = _Py_asdl_seq_new(_n, p->arena); @@ -23675,14 +23878,14 @@ _loop0_133_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_133_type, _seq); + _PyPegen_insert_memo(p, _start_mark, _loop0_134_type, _seq); D(p->level--); return _seq; } -// _tmp_134: lambda_slash_with_default | lambda_param_with_default+ +// _tmp_135: lambda_slash_with_default | lambda_param_with_default+ static void * -_tmp_134_rule(Parser *p) +_tmp_135_rule(Parser *p) { D(p->level++); if (p->error_indicator) { @@ -23696,18 +23899,18 @@ _tmp_134_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _tmp_134[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_slash_with_default")); + D(fprintf(stderr, "%*c> _tmp_135[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_slash_with_default")); SlashWithDefault* lambda_slash_with_default_var; if ( (lambda_slash_with_default_var = lambda_slash_with_default_rule(p)) // lambda_slash_with_default ) { - D(fprintf(stderr, "%*c+ _tmp_134[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "lambda_slash_with_default")); + D(fprintf(stderr, "%*c+ _tmp_135[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "lambda_slash_with_default")); _res = lambda_slash_with_default_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_134[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_135[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_slash_with_default")); } { // lambda_param_with_default+ @@ -23715,18 +23918,18 @@ _tmp_134_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _tmp_134[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_with_default+")); - asdl_seq * _loop1_152_var; + D(fprintf(stderr, "%*c> _tmp_135[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_with_default+")); + asdl_seq * _loop1_154_var; if ( - (_loop1_152_var = _loop1_152_rule(p)) // lambda_param_with_default+ + (_loop1_154_var = _loop1_154_rule(p)) // lambda_param_with_default+ ) { - D(fprintf(stderr, "%*c+ _tmp_134[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "lambda_param_with_default+")); - _res = _loop1_152_var; + D(fprintf(stderr, "%*c+ _tmp_135[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "lambda_param_with_default+")); + _res = _loop1_154_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_134[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_135[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_with_default+")); } _res = NULL; @@ -23735,9 +23938,9 @@ _tmp_134_rule(Parser *p) return _res; } -// _tmp_135: ')' | ',' (')' | '**') +// _tmp_136: ')' | ',' (')' | '**') static void * -_tmp_135_rule(Parser *p) +_tmp_136_rule(Parser *p) { D(p->level++); if (p->error_indicator) { @@ -23751,18 +23954,18 @@ _tmp_135_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _tmp_135[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "')'")); + D(fprintf(stderr, "%*c> _tmp_136[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "')'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 8)) // token=')' ) { - D(fprintf(stderr, "%*c+ _tmp_135[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "')'")); + D(fprintf(stderr, "%*c+ _tmp_136[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "')'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_135[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_136[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "')'")); } { // ',' (')' | '**') @@ -23770,21 +23973,21 @@ _tmp_135_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _tmp_135[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (')' | '**')")); + D(fprintf(stderr, "%*c> _tmp_136[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (')' | '**')")); Token * _literal; - void *_tmp_153_var; + void *_tmp_155_var; if ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' && - (_tmp_153_var = _tmp_153_rule(p)) // ')' | '**' + (_tmp_155_var = _tmp_155_rule(p)) // ')' | '**' ) { - D(fprintf(stderr, "%*c+ _tmp_135[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' (')' | '**')")); - _res = _PyPegen_dummy_name(p, _literal, _tmp_153_var); + D(fprintf(stderr, "%*c+ _tmp_136[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' (')' | '**')")); + _res = _PyPegen_dummy_name(p, _literal, _tmp_155_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_135[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_136[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' (')' | '**')")); } _res = NULL; @@ -23793,9 +23996,9 @@ _tmp_135_rule(Parser *p) return _res; } -// _tmp_136: ':' | ',' (':' | '**') +// _tmp_137: ':' | ',' (':' | '**') static void * -_tmp_136_rule(Parser *p) +_tmp_137_rule(Parser *p) { D(p->level++); if (p->error_indicator) { @@ -23809,18 +24012,18 @@ _tmp_136_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _tmp_136[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); + D(fprintf(stderr, "%*c> _tmp_137[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 11)) // token=':' ) { - D(fprintf(stderr, "%*c+ _tmp_136[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); + D(fprintf(stderr, "%*c+ _tmp_137[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_136[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_137[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "':'")); } { // ',' (':' | '**') @@ -23828,21 +24031,21 @@ _tmp_136_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _tmp_136[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (':' | '**')")); + D(fprintf(stderr, "%*c> _tmp_137[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (':' | '**')")); Token * _literal; - void *_tmp_154_var; + void *_tmp_156_var; if ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' && - (_tmp_154_var = _tmp_154_rule(p)) // ':' | '**' + (_tmp_156_var = _tmp_156_rule(p)) // ':' | '**' ) { - D(fprintf(stderr, "%*c+ _tmp_136[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' (':' | '**')")); - _res = _PyPegen_dummy_name(p, _literal, _tmp_154_var); + D(fprintf(stderr, "%*c+ _tmp_137[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' (':' | '**')")); + _res = _PyPegen_dummy_name(p, _literal, _tmp_156_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_136[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_137[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' (':' | '**')")); } _res = NULL; @@ -23851,9 +24054,9 @@ _tmp_136_rule(Parser *p) return _res; } -// _tmp_137: star_targets '=' +// _tmp_138: star_targets '=' static void * -_tmp_137_rule(Parser *p) +_tmp_138_rule(Parser *p) { D(p->level++); if (p->error_indicator) { @@ -23867,7 +24070,7 @@ _tmp_137_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _tmp_137[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_targets '='")); + D(fprintf(stderr, "%*c> _tmp_138[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_targets '='")); Token * _literal; expr_ty z; if ( @@ -23876,7 +24079,7 @@ _tmp_137_rule(Parser *p) (_literal = _PyPegen_expect_token(p, 22)) // token='=' ) { - D(fprintf(stderr, "%*c+ _tmp_137[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_targets '='")); + D(fprintf(stderr, "%*c+ _tmp_138[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_targets '='")); _res = z; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -23886,7 +24089,7 @@ _tmp_137_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_137[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_138[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_targets '='")); } _res = NULL; @@ -23895,9 +24098,9 @@ _tmp_137_rule(Parser *p) return _res; } -// _tmp_138: '.' | '...' +// _tmp_139: '.' | '...' static void * -_tmp_138_rule(Parser *p) +_tmp_139_rule(Parser *p) { D(p->level++); if (p->error_indicator) { @@ -23911,18 +24114,18 @@ _tmp_138_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _tmp_138[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'.'")); + D(fprintf(stderr, "%*c> _tmp_139[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'.'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 23)) // token='.' ) { - D(fprintf(stderr, "%*c+ _tmp_138[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'.'")); + D(fprintf(stderr, "%*c+ _tmp_139[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'.'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_138[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_139[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'.'")); } { // '...' @@ -23930,18 +24133,18 @@ _tmp_138_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _tmp_138[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'...'")); + D(fprintf(stderr, "%*c> _tmp_139[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'...'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 52)) // token='...' ) { - D(fprintf(stderr, "%*c+ _tmp_138[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'...'")); + D(fprintf(stderr, "%*c+ _tmp_139[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'...'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_138[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_139[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'...'")); } _res = NULL; @@ -23950,9 +24153,9 @@ _tmp_138_rule(Parser *p) return _res; } -// _tmp_139: '.' | '...' +// _tmp_140: '.' | '...' static void * -_tmp_139_rule(Parser *p) +_tmp_140_rule(Parser *p) { D(p->level++); if (p->error_indicator) { @@ -23966,18 +24169,18 @@ _tmp_139_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _tmp_139[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'.'")); + D(fprintf(stderr, "%*c> _tmp_140[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'.'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 23)) // token='.' ) { - D(fprintf(stderr, "%*c+ _tmp_139[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'.'")); + D(fprintf(stderr, "%*c+ _tmp_140[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'.'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_139[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_140[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'.'")); } { // '...' @@ -23985,18 +24188,18 @@ _tmp_139_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _tmp_139[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'...'")); + D(fprintf(stderr, "%*c> _tmp_140[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'...'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 52)) // token='...' ) { - D(fprintf(stderr, "%*c+ _tmp_139[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'...'")); + D(fprintf(stderr, "%*c+ _tmp_140[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'...'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_139[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_140[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'...'")); } _res = NULL; @@ -24005,9 +24208,9 @@ _tmp_139_rule(Parser *p) return _res; } -// _tmp_140: '@' named_expression NEWLINE +// _tmp_141: '@' named_expression NEWLINE static void * -_tmp_140_rule(Parser *p) +_tmp_141_rule(Parser *p) { D(p->level++); if (p->error_indicator) { @@ -24021,7 +24224,7 @@ _tmp_140_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _tmp_140[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'@' named_expression NEWLINE")); + D(fprintf(stderr, "%*c> _tmp_141[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'@' named_expression NEWLINE")); Token * _literal; expr_ty f; Token * newline_var; @@ -24033,7 +24236,7 @@ _tmp_140_rule(Parser *p) (newline_var = _PyPegen_expect_token(p, NEWLINE)) // token='NEWLINE' ) { - D(fprintf(stderr, "%*c+ _tmp_140[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'@' named_expression NEWLINE")); + D(fprintf(stderr, "%*c+ _tmp_141[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'@' named_expression NEWLINE")); _res = f; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -24043,7 +24246,7 @@ _tmp_140_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_140[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_141[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'@' named_expression NEWLINE")); } _res = NULL; @@ -24052,9 +24255,9 @@ _tmp_140_rule(Parser *p) return _res; } -// _tmp_141: ',' star_expression +// _tmp_142: ',' star_expression static void * -_tmp_141_rule(Parser *p) +_tmp_142_rule(Parser *p) { D(p->level++); if (p->error_indicator) { @@ -24068,7 +24271,7 @@ _tmp_141_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _tmp_141[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' star_expression")); + D(fprintf(stderr, "%*c> _tmp_142[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' star_expression")); Token * _literal; expr_ty c; if ( @@ -24077,7 +24280,7 @@ _tmp_141_rule(Parser *p) (c = star_expression_rule(p)) // star_expression ) { - D(fprintf(stderr, "%*c+ _tmp_141[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' star_expression")); + D(fprintf(stderr, "%*c+ _tmp_142[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' star_expression")); _res = c; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -24087,7 +24290,7 @@ _tmp_141_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_141[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_142[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' star_expression")); } _res = NULL; @@ -24096,9 +24299,9 @@ _tmp_141_rule(Parser *p) return _res; } -// _tmp_142: ',' expression +// _tmp_143: ',' expression static void * -_tmp_142_rule(Parser *p) +_tmp_143_rule(Parser *p) { D(p->level++); if (p->error_indicator) { @@ -24112,7 +24315,7 @@ _tmp_142_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _tmp_142[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' expression")); + D(fprintf(stderr, "%*c> _tmp_143[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' expression")); Token * _literal; expr_ty c; if ( @@ -24121,7 +24324,7 @@ _tmp_142_rule(Parser *p) (c = expression_rule(p)) // expression ) { - D(fprintf(stderr, "%*c+ _tmp_142[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' expression")); + D(fprintf(stderr, "%*c+ _tmp_143[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' expression")); _res = c; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -24131,7 +24334,7 @@ _tmp_142_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_142[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_143[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' expression")); } _res = NULL; @@ -24140,9 +24343,9 @@ _tmp_142_rule(Parser *p) return _res; } -// _tmp_143: 'or' conjunction +// _tmp_144: 'or' conjunction static void * -_tmp_143_rule(Parser *p) +_tmp_144_rule(Parser *p) { D(p->level++); if (p->error_indicator) { @@ -24156,7 +24359,7 @@ _tmp_143_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _tmp_143[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'or' conjunction")); + D(fprintf(stderr, "%*c> _tmp_144[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'or' conjunction")); Token * _keyword; expr_ty c; if ( @@ -24165,7 +24368,7 @@ _tmp_143_rule(Parser *p) (c = conjunction_rule(p)) // conjunction ) { - D(fprintf(stderr, "%*c+ _tmp_143[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'or' conjunction")); + D(fprintf(stderr, "%*c+ _tmp_144[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'or' conjunction")); _res = c; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -24175,7 +24378,7 @@ _tmp_143_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_143[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_144[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'or' conjunction")); } _res = NULL; @@ -24184,9 +24387,9 @@ _tmp_143_rule(Parser *p) return _res; } -// _tmp_144: 'and' inversion +// _tmp_145: 'and' inversion static void * -_tmp_144_rule(Parser *p) +_tmp_145_rule(Parser *p) { D(p->level++); if (p->error_indicator) { @@ -24200,7 +24403,7 @@ _tmp_144_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _tmp_144[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'and' inversion")); + D(fprintf(stderr, "%*c> _tmp_145[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'and' inversion")); Token * _keyword; expr_ty c; if ( @@ -24209,7 +24412,7 @@ _tmp_144_rule(Parser *p) (c = inversion_rule(p)) // inversion ) { - D(fprintf(stderr, "%*c+ _tmp_144[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'and' inversion")); + D(fprintf(stderr, "%*c+ _tmp_145[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'and' inversion")); _res = c; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -24219,7 +24422,7 @@ _tmp_144_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_144[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_145[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'and' inversion")); } _res = NULL; @@ -24228,9 +24431,9 @@ _tmp_144_rule(Parser *p) return _res; } -// _tmp_145: 'if' disjunction +// _tmp_146: 'if' disjunction static void * -_tmp_145_rule(Parser *p) +_tmp_146_rule(Parser *p) { D(p->level++); if (p->error_indicator) { @@ -24244,7 +24447,7 @@ _tmp_145_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _tmp_145[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'if' disjunction")); + D(fprintf(stderr, "%*c> _tmp_146[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'if' disjunction")); Token * _keyword; expr_ty z; if ( @@ -24253,7 +24456,7 @@ _tmp_145_rule(Parser *p) (z = disjunction_rule(p)) // disjunction ) { - D(fprintf(stderr, "%*c+ _tmp_145[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'if' disjunction")); + D(fprintf(stderr, "%*c+ _tmp_146[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'if' disjunction")); _res = z; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -24263,7 +24466,7 @@ _tmp_145_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_145[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_146[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'if' disjunction")); } _res = NULL; @@ -24272,9 +24475,9 @@ _tmp_145_rule(Parser *p) return _res; } -// _tmp_146: 'if' disjunction +// _tmp_147: 'if' disjunction static void * -_tmp_146_rule(Parser *p) +_tmp_147_rule(Parser *p) { D(p->level++); if (p->error_indicator) { @@ -24288,7 +24491,7 @@ _tmp_146_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _tmp_146[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'if' disjunction")); + D(fprintf(stderr, "%*c> _tmp_147[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'if' disjunction")); Token * _keyword; expr_ty z; if ( @@ -24297,7 +24500,7 @@ _tmp_146_rule(Parser *p) (z = disjunction_rule(p)) // disjunction ) { - D(fprintf(stderr, "%*c+ _tmp_146[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'if' disjunction")); + D(fprintf(stderr, "%*c+ _tmp_147[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'if' disjunction")); _res = z; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -24307,7 +24510,7 @@ _tmp_146_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_146[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_147[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'if' disjunction")); } _res = NULL; @@ -24316,9 +24519,9 @@ _tmp_146_rule(Parser *p) return _res; } -// _tmp_147: starred_expression | named_expression !'=' +// _tmp_148: starred_expression | named_expression !'=' static void * -_tmp_147_rule(Parser *p) +_tmp_148_rule(Parser *p) { D(p->level++); if (p->error_indicator) { @@ -24332,18 +24535,18 @@ _tmp_147_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _tmp_147[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "starred_expression")); + D(fprintf(stderr, "%*c> _tmp_148[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "starred_expression")); expr_ty starred_expression_var; if ( (starred_expression_var = starred_expression_rule(p)) // starred_expression ) { - D(fprintf(stderr, "%*c+ _tmp_147[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "starred_expression")); + D(fprintf(stderr, "%*c+ _tmp_148[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "starred_expression")); _res = starred_expression_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_147[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_148[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "starred_expression")); } { // named_expression !'=' @@ -24351,7 +24554,7 @@ _tmp_147_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _tmp_147[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "named_expression !'='")); + D(fprintf(stderr, "%*c> _tmp_148[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "named_expression !'='")); expr_ty named_expression_var; if ( (named_expression_var = named_expression_rule(p)) // named_expression @@ -24359,12 +24562,12 @@ _tmp_147_rule(Parser *p) _PyPegen_lookahead_with_int(0, _PyPegen_expect_token, p, 22) // token='=' ) { - D(fprintf(stderr, "%*c+ _tmp_147[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "named_expression !'='")); + D(fprintf(stderr, "%*c+ _tmp_148[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "named_expression !'='")); _res = named_expression_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_147[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_148[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "named_expression !'='")); } _res = NULL; @@ -24373,9 +24576,9 @@ _tmp_147_rule(Parser *p) return _res; } -// _tmp_148: ',' star_target +// _tmp_149: ',' star_target static void * -_tmp_148_rule(Parser *p) +_tmp_149_rule(Parser *p) { D(p->level++); if (p->error_indicator) { @@ -24389,7 +24592,7 @@ _tmp_148_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _tmp_148[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' star_target")); + D(fprintf(stderr, "%*c> _tmp_149[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' star_target")); Token * _literal; expr_ty c; if ( @@ -24398,7 +24601,7 @@ _tmp_148_rule(Parser *p) (c = star_target_rule(p)) // star_target ) { - D(fprintf(stderr, "%*c+ _tmp_148[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' star_target")); + D(fprintf(stderr, "%*c+ _tmp_149[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' star_target")); _res = c; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -24408,7 +24611,7 @@ _tmp_148_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_148[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_149[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' star_target")); } _res = NULL; @@ -24417,9 +24620,53 @@ _tmp_148_rule(Parser *p) return _res; } -// _tmp_149: star_targets '=' +// _tmp_150: ',' star_target static void * -_tmp_149_rule(Parser *p) +_tmp_150_rule(Parser *p) +{ + D(p->level++); + if (p->error_indicator) { + D(p->level--); + return NULL; + } + void * _res = NULL; + int _mark = p->mark; + { // ',' star_target + if (p->error_indicator) { + D(p->level--); + return NULL; + } + D(fprintf(stderr, "%*c> _tmp_150[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' star_target")); + Token * _literal; + expr_ty c; + if ( + (_literal = _PyPegen_expect_token(p, 12)) // token=',' + && + (c = star_target_rule(p)) // star_target + ) + { + D(fprintf(stderr, "%*c+ _tmp_150[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' star_target")); + _res = c; + if (_res == NULL && PyErr_Occurred()) { + p->error_indicator = 1; + D(p->level--); + return NULL; + } + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s _tmp_150[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' star_target")); + } + _res = NULL; + done: + D(p->level--); + return _res; +} + +// _tmp_151: star_targets '=' +static void * +_tmp_151_rule(Parser *p) { D(p->level++); if (p->error_indicator) { @@ -24433,7 +24680,7 @@ _tmp_149_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _tmp_149[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_targets '='")); + D(fprintf(stderr, "%*c> _tmp_151[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_targets '='")); Token * _literal; expr_ty star_targets_var; if ( @@ -24442,12 +24689,12 @@ _tmp_149_rule(Parser *p) (_literal = _PyPegen_expect_token(p, 22)) // token='=' ) { - D(fprintf(stderr, "%*c+ _tmp_149[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_targets '='")); + D(fprintf(stderr, "%*c+ _tmp_151[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_targets '='")); _res = _PyPegen_dummy_name(p, star_targets_var, _literal); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_149[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_151[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_targets '='")); } _res = NULL; @@ -24456,9 +24703,9 @@ _tmp_149_rule(Parser *p) return _res; } -// _tmp_150: star_targets '=' +// _tmp_152: star_targets '=' static void * -_tmp_150_rule(Parser *p) +_tmp_152_rule(Parser *p) { D(p->level++); if (p->error_indicator) { @@ -24472,7 +24719,7 @@ _tmp_150_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _tmp_150[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_targets '='")); + D(fprintf(stderr, "%*c> _tmp_152[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_targets '='")); Token * _literal; expr_ty star_targets_var; if ( @@ -24481,12 +24728,12 @@ _tmp_150_rule(Parser *p) (_literal = _PyPegen_expect_token(p, 22)) // token='=' ) { - D(fprintf(stderr, "%*c+ _tmp_150[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_targets '='")); + D(fprintf(stderr, "%*c+ _tmp_152[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_targets '='")); _res = _PyPegen_dummy_name(p, star_targets_var, _literal); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_150[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_152[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_targets '='")); } _res = NULL; @@ -24495,9 +24742,9 @@ _tmp_150_rule(Parser *p) return _res; } -// _loop1_151: param_with_default +// _loop1_153: param_with_default static asdl_seq * -_loop1_151_rule(Parser *p) +_loop1_153_rule(Parser *p) { D(p->level++); if (p->error_indicator) { @@ -24521,7 +24768,7 @@ _loop1_151_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _loop1_151[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_with_default")); + D(fprintf(stderr, "%*c> _loop1_153[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_with_default")); NameDefaultPair* param_with_default_var; while ( (param_with_default_var = param_with_default_rule(p)) // param_with_default @@ -24543,7 +24790,7 @@ _loop1_151_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_151[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_153[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "param_with_default")); } if (_n == 0 || p->error_indicator) { @@ -24561,14 +24808,14 @@ _loop1_151_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop1_151_type, _seq); + _PyPegen_insert_memo(p, _start_mark, _loop1_153_type, _seq); D(p->level--); return _seq; } -// _loop1_152: lambda_param_with_default +// _loop1_154: lambda_param_with_default static asdl_seq * -_loop1_152_rule(Parser *p) +_loop1_154_rule(Parser *p) { D(p->level++); if (p->error_indicator) { @@ -24592,7 +24839,7 @@ _loop1_152_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _loop1_152[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_with_default")); + D(fprintf(stderr, "%*c> _loop1_154[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_with_default")); NameDefaultPair* lambda_param_with_default_var; while ( (lambda_param_with_default_var = lambda_param_with_default_rule(p)) // lambda_param_with_default @@ -24614,7 +24861,7 @@ _loop1_152_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_152[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_154[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_with_default")); } if (_n == 0 || p->error_indicator) { @@ -24632,14 +24879,14 @@ _loop1_152_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop1_152_type, _seq); + _PyPegen_insert_memo(p, _start_mark, _loop1_154_type, _seq); D(p->level--); return _seq; } -// _tmp_153: ')' | '**' +// _tmp_155: ')' | '**' static void * -_tmp_153_rule(Parser *p) +_tmp_155_rule(Parser *p) { D(p->level++); if (p->error_indicator) { @@ -24653,18 +24900,18 @@ _tmp_153_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _tmp_153[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "')'")); + D(fprintf(stderr, "%*c> _tmp_155[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "')'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 8)) // token=')' ) { - D(fprintf(stderr, "%*c+ _tmp_153[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "')'")); + D(fprintf(stderr, "%*c+ _tmp_155[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "')'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_153[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_155[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "')'")); } { // '**' @@ -24672,18 +24919,18 @@ _tmp_153_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _tmp_153[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'**'")); + D(fprintf(stderr, "%*c> _tmp_155[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'**'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 35)) // token='**' ) { - D(fprintf(stderr, "%*c+ _tmp_153[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'**'")); + D(fprintf(stderr, "%*c+ _tmp_155[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'**'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_153[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_155[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'**'")); } _res = NULL; @@ -24692,9 +24939,9 @@ _tmp_153_rule(Parser *p) return _res; } -// _tmp_154: ':' | '**' +// _tmp_156: ':' | '**' static void * -_tmp_154_rule(Parser *p) +_tmp_156_rule(Parser *p) { D(p->level++); if (p->error_indicator) { @@ -24708,18 +24955,18 @@ _tmp_154_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _tmp_154[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); + D(fprintf(stderr, "%*c> _tmp_156[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 11)) // token=':' ) { - D(fprintf(stderr, "%*c+ _tmp_154[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); + D(fprintf(stderr, "%*c+ _tmp_156[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_154[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_156[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "':'")); } { // '**' @@ -24727,18 +24974,18 @@ _tmp_154_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _tmp_154[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'**'")); + D(fprintf(stderr, "%*c> _tmp_156[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'**'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 35)) // token='**' ) { - D(fprintf(stderr, "%*c+ _tmp_154[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'**'")); + D(fprintf(stderr, "%*c+ _tmp_156[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'**'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_154[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_156[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'**'")); } _res = NULL; From bfc413ce4fa37ccb889757388102c7755e057bf5 Mon Sep 17 00:00:00 2001 From: Pablo Galindo Date: Sun, 3 Jan 2021 01:32:43 +0000 Subject: [PATCH 0867/1314] [3.9] bpo-42806: Fix ast locations of f-strings inside parentheses (GH-24067) (GH-24069) (cherry picked from commit bd2728b1e8a99ba8f8c2d481f88aeb99b8b8360f) Co-authored-by: Pablo Galindo --- Lib/test/test_fstring.py | 53 +++++++++++++++++++ .../2021-01-03-00-20-38.bpo-42806.mLAobJ.rst | 2 + Parser/pegen/parse_string.c | 2 +- 3 files changed, 56 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2021-01-03-00-20-38.bpo-42806.mLAobJ.rst diff --git a/Lib/test/test_fstring.py b/Lib/test/test_fstring.py index 2ae815aab18f6d..2f08d35f26dc3b 100644 --- a/Lib/test/test_fstring.py +++ b/Lib/test/test_fstring.py @@ -332,6 +332,59 @@ def test_ast_line_numbers_multiline_fstring(self): self.assertEqual(binop.left.col_offset, 4) self.assertEqual(binop.right.col_offset, 7) + def test_ast_line_numbers_with_parentheses(self): + expr = """ +x = ( + f" {test(t)}" +)""" + t = ast.parse(expr) + self.assertEqual(type(t), ast.Module) + self.assertEqual(len(t.body), 1) + # check the test(t) location + call = t.body[0].value.values[1].value + self.assertEqual(type(call), ast.Call) + self.assertEqual(call.lineno, 3) + self.assertEqual(call.end_lineno, 3) + self.assertEqual(call.col_offset, 8) + self.assertEqual(call.end_col_offset, 15) + + expr = """ +x = ( + 'PERL_MM_OPT', ( + f'wat' + f'some_string={f(x)} ' + f'wat' + ), +) +""" + t = ast.parse(expr) + self.assertEqual(type(t), ast.Module) + self.assertEqual(len(t.body), 1) + # check the fstring + fstring = t.body[0].value.elts[1] + self.assertEqual(type(fstring), ast.JoinedStr) + self.assertEqual(len(fstring.values), 3) + wat1, middle, wat2 = fstring.values + # check the first wat + self.assertEqual(type(wat1), ast.Constant) + self.assertEqual(wat1.lineno, 4) + self.assertEqual(wat1.end_lineno, 6) + self.assertEqual(wat1.col_offset, 12) + self.assertEqual(wat1.end_col_offset, 18) + # check the call + call = middle.value + self.assertEqual(type(call), ast.Call) + self.assertEqual(call.lineno, 5) + self.assertEqual(call.end_lineno, 5) + self.assertEqual(call.col_offset, 27) + self.assertEqual(call.end_col_offset, 31) + # check the second wat + self.assertEqual(type(wat2), ast.Constant) + self.assertEqual(wat2.lineno, 4) + self.assertEqual(wat2.end_lineno, 6) + self.assertEqual(wat2.col_offset, 12) + self.assertEqual(wat2.end_col_offset, 18) + def test_docstring(self): def f(): f'''Not a docstring''' diff --git a/Misc/NEWS.d/next/Core and Builtins/2021-01-03-00-20-38.bpo-42806.mLAobJ.rst b/Misc/NEWS.d/next/Core and Builtins/2021-01-03-00-20-38.bpo-42806.mLAobJ.rst new file mode 100644 index 00000000000000..10314fd650fa66 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2021-01-03-00-20-38.bpo-42806.mLAobJ.rst @@ -0,0 +1,2 @@ +Fix the column offsets for f-strings :mod:`ast` nodes surrounded by +parentheses and for nodes that spawn multiple lines. Patch by Pablo Galindo. diff --git a/Parser/pegen/parse_string.c b/Parser/pegen/parse_string.c index fb0c4aff9d3d00..c852e5b827c0cc 100644 --- a/Parser/pegen/parse_string.c +++ b/Parser/pegen/parse_string.c @@ -410,7 +410,7 @@ fstring_compile_expr(Parser *p, const char *expr_start, const char *expr_end, Parser *p2 = _PyPegen_Parser_New(tok, Py_fstring_input, p->flags, p->feature_version, NULL, p->arena); p2->starting_lineno = t->lineno + lines - 1; - p2->starting_col_offset = p->tok->first_lineno == p->tok->lineno ? t->col_offset + cols : cols; + p2->starting_col_offset = t->col_offset + cols; expr = _PyPegen_run_parser(p2); From 0303008ebceb6ac6035cd9722d1393267304171d Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sun, 3 Jan 2021 22:54:44 +0200 Subject: [PATCH 0868/1314] [3.9] bpo-42789: Don't skip curses tests on non-tty. (GH-24009) (GH-24076) If __stdout__ is not attached to terminal, try to use __stderr__ if it is attached to terminal, or open the terminal device, or use regular file as terminal, but some functions will be untested in the latter case. (cherry picked from commit 607501abb488fb37e33cf9d35260ab7baefa192f) --- Lib/test/test_curses.py | 102 +++++++++++++++++++++++++--------------- 1 file changed, 63 insertions(+), 39 deletions(-) diff --git a/Lib/test/test_curses.py b/Lib/test/test_curses.py index 5e619d13836d26..cbab331d707b03 100644 --- a/Lib/test/test_curses.py +++ b/Lib/test/test_curses.py @@ -47,37 +47,57 @@ class TestCurses(unittest.TestCase): @classmethod def setUpClass(cls): - if not sys.__stdout__.isatty(): - # Temporary skip tests on non-tty - raise unittest.SkipTest('sys.__stdout__ is not a tty') - cls.tmp = tempfile.TemporaryFile() - fd = cls.tmp.fileno() - else: - cls.tmp = None - fd = sys.__stdout__.fileno() # testing setupterm() inside initscr/endwin # causes terminal breakage - curses.setupterm(fd=fd) - - @classmethod - def tearDownClass(cls): - if cls.tmp: - cls.tmp.close() - del cls.tmp + stdout_fd = sys.__stdout__.fileno() + curses.setupterm(fd=stdout_fd) def setUp(self): + self.isatty = True + self.output = sys.__stdout__ + stdout_fd = sys.__stdout__.fileno() + if not sys.__stdout__.isatty(): + # initstr() unconditionally uses C stdout. + # If it is redirected to file or pipe, try to attach it + # to terminal. + # First, save a copy of the file descriptor of stdout, so it + # can be restored after finishing the test. + dup_fd = os.dup(stdout_fd) + self.addCleanup(os.close, dup_fd) + self.addCleanup(os.dup2, dup_fd, stdout_fd) + + if sys.__stderr__.isatty(): + # If stderr is connected to terminal, use it. + tmp = sys.__stderr__ + self.output = sys.__stderr__ + else: + try: + # Try to open the terminal device. + tmp = open('/dev/tty', 'wb', buffering=0) + except OSError: + # As a fallback, use regular file to write control codes. + # Some functions (like savetty) will not work, but at + # least the garbage control sequences will not be mixed + # with the testing report. + tmp = tempfile.TemporaryFile(mode='wb', buffering=0) + self.isatty = False + self.addCleanup(tmp.close) + self.output = None + os.dup2(tmp.fileno(), stdout_fd) + self.save_signals = SaveSignals() self.save_signals.save() - if verbose: + self.addCleanup(self.save_signals.restore) + if verbose and self.output is not None: # just to make the test output a little more readable - print() + sys.stderr.flush() + sys.stdout.flush() + print(file=self.output, flush=True) self.stdscr = curses.initscr() - curses.savetty() - - def tearDown(self): - curses.resetty() - curses.endwin() - self.save_signals.restore() + if self.isatty: + curses.savetty() + self.addCleanup(curses.endwin) + self.addCleanup(curses.resetty) def test_window_funcs(self): "Test the methods of windows" @@ -95,7 +115,7 @@ def test_window_funcs(self): for meth in [stdscr.clear, stdscr.clrtobot, stdscr.clrtoeol, stdscr.cursyncup, stdscr.delch, stdscr.deleteln, stdscr.erase, stdscr.getbegyx, - stdscr.getbkgd, stdscr.getkey, stdscr.getmaxyx, + stdscr.getbkgd, stdscr.getmaxyx, stdscr.getparyx, stdscr.getyx, stdscr.inch, stdscr.insertln, stdscr.instr, stdscr.is_wintouched, win.noutrefresh, stdscr.redrawwin, stdscr.refresh, @@ -206,6 +226,11 @@ def test_window_funcs(self): if hasattr(stdscr, 'enclose'): stdscr.enclose(10, 10) + with tempfile.TemporaryFile() as f: + self.stdscr.putwin(f) + f.seek(0) + curses.getwin(f) + self.assertRaises(ValueError, stdscr.getstr, -400) self.assertRaises(ValueError, stdscr.getstr, 2, 3, -400) self.assertRaises(ValueError, stdscr.instr, -2) @@ -224,16 +249,19 @@ def test_embedded_null_chars(self): def test_module_funcs(self): "Test module-level functions" for func in [curses.baudrate, curses.beep, curses.can_change_color, - curses.cbreak, curses.def_prog_mode, curses.doupdate, - curses.flash, curses.flushinp, + curses.doupdate, curses.flash, curses.flushinp, curses.has_colors, curses.has_ic, curses.has_il, curses.isendwin, curses.killchar, curses.longname, - curses.nocbreak, curses.noecho, curses.nonl, - curses.noqiflush, curses.noraw, - curses.reset_prog_mode, curses.termattrs, - curses.termname, curses.erasechar]: + curses.noecho, curses.nonl, curses.noqiflush, + curses.termattrs, curses.termname, curses.erasechar]: with self.subTest(func=func.__qualname__): func() + if self.isatty: + for func in [curses.cbreak, curses.def_prog_mode, + curses.nocbreak, curses.noraw, + curses.reset_prog_mode]: + with self.subTest(func=func.__qualname__): + func() if hasattr(curses, 'filter'): curses.filter() if hasattr(curses, 'getsyx'): @@ -245,13 +273,9 @@ def test_module_funcs(self): curses.delay_output(1) curses.echo() ; curses.echo(1) - with tempfile.TemporaryFile() as f: - self.stdscr.putwin(f) - f.seek(0) - curses.getwin(f) - curses.halfdelay(1) - curses.intrflush(1) + if self.isatty: + curses.intrflush(1) curses.meta(1) curses.napms(100) curses.newpad(50,50) @@ -260,7 +284,8 @@ def test_module_funcs(self): curses.nl() ; curses.nl(1) curses.putp(b'abc') curses.qiflush() - curses.raw() ; curses.raw(1) + if self.isatty: + curses.raw() ; curses.raw(1) curses.set_escdelay(25) self.assertEqual(curses.get_escdelay(), 25) curses.set_tabsize(4) @@ -286,7 +311,7 @@ def test_colors_funcs(self): curses.init_pair(2, 1,1) curses.color_content(1) curses.color_pair(2) - curses.pair_content(curses.COLOR_PAIRS - 1) + curses.pair_content(min(curses.COLOR_PAIRS - 1, 0x7fff)) curses.pair_number(0) if hasattr(curses, 'use_default_colors'): @@ -358,7 +383,6 @@ def test_resize_term(self): @requires_curses_func('resizeterm') def test_resizeterm(self): - stdscr = self.stdscr lines, cols = curses.LINES, curses.COLS new_lines = lines - 1 new_cols = cols + 1 From b0ee2b492dbf550fbd2a63b82de0a4dc9d67f32e Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Mon, 4 Jan 2021 00:55:23 +0200 Subject: [PATCH 0869/1314] [3.9] bpo-42681: Fix range checks for color and pair numbers in curses (GH-23874). (GH-24077) (cherry picked from commit 1470edd6131c29b8a09ce012cdfee3afa269d553) --- Doc/library/curses.rst | 14 +- Lib/test/test_curses.py | 133 ++++++++++++++++-- .../2020-12-20-22-50-15.bpo-42681.lDO6jb.rst | 1 + Modules/_cursesmodule.c | 44 +++--- Modules/clinic/_cursesmodule.c.h | 26 ++-- 5 files changed, 157 insertions(+), 61 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2020-12-20-22-50-15.bpo-42681.lDO6jb.rst diff --git a/Doc/library/curses.rst b/Doc/library/curses.rst index 7a13295f482eeb..c72840a07c192e 100644 --- a/Doc/library/curses.rst +++ b/Doc/library/curses.rst @@ -112,14 +112,15 @@ The module :mod:`curses` defines the following functions: .. function:: color_content(color_number) Return the intensity of the red, green, and blue (RGB) components in the color - *color_number*, which must be between ``0`` and :const:`COLORS`. Return a 3-tuple, + *color_number*, which must be between ``0`` and ``COLORS - 1``. Return a 3-tuple, containing the R,G,B values for the given color, which will be between ``0`` (no component) and ``1000`` (maximum amount of component). -.. function:: color_pair(color_number) +.. function:: color_pair(pair_number) - Return the attribute value for displaying text in the specified color. This + Return the attribute value for displaying text in the specified color pair. + Only the first 256 color pairs are supported. This attribute value can be combined with :const:`A_STANDOUT`, :const:`A_REVERSE`, and the other :const:`A_\*` attributes. :func:`pair_number` is the counterpart to this function. @@ -278,7 +279,7 @@ The module :mod:`curses` defines the following functions: Change the definition of a color, taking the number of the color to be changed followed by three RGB values (for the amounts of red, green, and blue components). The value of *color_number* must be between ``0`` and - :const:`COLORS`. Each of *r*, *g*, *b*, must be a value between ``0`` and + `COLORS - 1`. Each of *r*, *g*, *b*, must be a value between ``0`` and ``1000``. When :func:`init_color` is used, all occurrences of that color on the screen immediately change to the new definition. This function is a no-op on most terminals; it is active only if :func:`can_change_color` returns ``True``. @@ -291,7 +292,8 @@ The module :mod:`curses` defines the following functions: color number. The value of *pair_number* must be between ``1`` and ``COLOR_PAIRS - 1`` (the ``0`` color pair is wired to white on black and cannot be changed). The value of *fg* and *bg* arguments must be between ``0`` and - :const:`COLORS`. If the color-pair was previously initialized, the screen is + ``COLORS - 1``, or, after calling :func:`use_default_colors`, ``-1``. + If the color-pair was previously initialized, the screen is refreshed and all occurrences of that color-pair are changed to the new definition. @@ -441,7 +443,7 @@ The module :mod:`curses` defines the following functions: .. function:: pair_content(pair_number) Return a tuple ``(fg, bg)`` containing the colors for the requested color pair. - The value of *pair_number* must be between ``1`` and ``COLOR_PAIRS - 1``. + The value of *pair_number* must be between ``0`` and ``COLOR_PAIRS - 1``. .. function:: pair_number(attr) diff --git a/Lib/test/test_curses.py b/Lib/test/test_curses.py index cbab331d707b03..e310d191f97e90 100644 --- a/Lib/test/test_curses.py +++ b/Lib/test/test_curses.py @@ -4,8 +4,7 @@ # This script doesn't actually display anything very coherent. but it # does call (nearly) every method and function. # -# Functions not tested: {def,reset}_{shell,prog}_mode, getch(), getstr(), -# init_color() +# Functions not tested: {def,reset}_{shell,prog}_mode, getch(), getstr() # Only called, not tested: getmouse(), ungetmouse() # @@ -13,6 +12,7 @@ import string import sys import tempfile +import functools import unittest from test.support import requires, import_module, verbose, SaveSignals @@ -36,7 +36,17 @@ def requires_curses_func(name): return unittest.skipUnless(hasattr(curses, name), 'requires curses.%s' % name) +def requires_colors(test): + @functools.wraps(test) + def wrapped(self, *args, **kwargs): + if not curses.has_colors(): + self.skipTest('requires colors support') + curses.start_color() + test(self, *args, **kwargs) + return wrapped + term = os.environ.get('TERM') +SHORT_MAX = 0x7fff # If newterm was supported we could use it instead of initscr and not exit @unittest.skipIf(not term or term == 'unknown', @@ -47,6 +57,8 @@ class TestCurses(unittest.TestCase): @classmethod def setUpClass(cls): + if verbose: + print(f'TERM={term}', file=sys.stderr, flush=True) # testing setupterm() inside initscr/endwin # causes terminal breakage stdout_fd = sys.__stdout__.fileno() @@ -304,18 +316,111 @@ def test_module_funcs(self): curses.use_env(1) # Functions only available on a few platforms - def test_colors_funcs(self): - if not curses.has_colors(): - self.skipTest('requires colors support') - curses.start_color() - curses.init_pair(2, 1,1) - curses.color_content(1) - curses.color_pair(2) - curses.pair_content(min(curses.COLOR_PAIRS - 1, 0x7fff)) - curses.pair_number(0) - - if hasattr(curses, 'use_default_colors'): - curses.use_default_colors() + + def bad_colors(self): + return (-2**31 - 1, 2**31, -2**63 - 1, 2**63, 2**64) + + def bad_pairs(self): + return (-2**31 - 1, 2**31, -2**63 - 1, 2**63, 2**64) + + @requires_colors + def test_color_content(self): + self.assertEqual(curses.color_content(curses.COLOR_BLACK), (0, 0, 0)) + curses.color_content(0) + curses.color_content(min(curses.COLORS - 1, SHORT_MAX)) + + for color in self.bad_colors(): + self.assertRaises(OverflowError, curses.color_content, color) + if curses.COLORS <= SHORT_MAX: + self.assertRaises(curses.error, curses.color_content, curses.COLORS) + self.assertRaises(curses.error, curses.color_content, -1) + + @requires_colors + def test_init_color(self): + if not curses.can_change_color: + self.skipTest('cannot change color') + + old = curses.color_content(0) + try: + curses.init_color(0, *old) + except curses.error: + self.skipTest('cannot change color (init_color() failed)') + self.addCleanup(curses.init_color, 0, *old) + curses.init_color(0, 0, 0, 0) + self.assertEqual(curses.color_content(0), (0, 0, 0)) + curses.init_color(0, 1000, 1000, 1000) + self.assertEqual(curses.color_content(0), (1000, 1000, 1000)) + + maxcolor = min(curses.COLORS - 1, SHORT_MAX) + old = curses.color_content(maxcolor) + curses.init_color(maxcolor, *old) + self.addCleanup(curses.init_color, maxcolor, *old) + curses.init_color(maxcolor, 0, 500, 1000) + self.assertEqual(curses.color_content(maxcolor), (0, 500, 1000)) + + for color in self.bad_colors(): + self.assertRaises(OverflowError, curses.init_color, color, 0, 0, 0) + if curses.COLORS <= SHORT_MAX: + self.assertRaises(curses.error, curses.init_color, curses.COLORS, 0, 0, 0) + self.assertRaises(curses.error, curses.init_color, -1, 0, 0, 0) + for comp in (-1, 1001): + self.assertRaises(curses.error, curses.init_color, 0, comp, 0, 0) + self.assertRaises(curses.error, curses.init_color, 0, 0, comp, 0) + self.assertRaises(curses.error, curses.init_color, 0, 0, 0, comp) + + @requires_colors + def test_pair_content(self): + if not hasattr(curses, 'use_default_colors'): + self.assertEqual(curses.pair_content(0), + (curses.COLOR_WHITE, curses.COLOR_BLACK)) + curses.pair_content(0) + curses.pair_content(min(curses.COLOR_PAIRS - 1, SHORT_MAX)) + + for pair in self.bad_pairs(): + self.assertRaises(OverflowError, curses.pair_content, pair) + self.assertRaises(curses.error, curses.pair_content, -1) + + @requires_colors + def test_init_pair(self): + old = curses.pair_content(1) + curses.init_pair(1, *old) + self.addCleanup(curses.init_pair, 1, *old) + + curses.init_pair(1, 0, 0) + self.assertEqual(curses.pair_content(1), (0, 0)) + maxcolor = min(curses.COLORS - 1, SHORT_MAX) + curses.init_pair(1, maxcolor, maxcolor) + self.assertEqual(curses.pair_content(1), (maxcolor, maxcolor)) + maxpair = min(curses.COLOR_PAIRS - 1, SHORT_MAX) + curses.init_pair(maxpair, 2, 3) + self.assertEqual(curses.pair_content(maxpair), (2, 3)) + + for pair in self.bad_pairs(): + self.assertRaises(OverflowError, curses.init_pair, pair, 0, 0) + self.assertRaises(curses.error, curses.init_pair, -1, 0, 0) + for color in self.bad_colors(): + self.assertRaises(OverflowError, curses.init_pair, 1, color, 0) + self.assertRaises(OverflowError, curses.init_pair, 1, 0, color) + if curses.COLORS <= SHORT_MAX: + self.assertRaises(curses.error, curses.init_pair, 1, curses.COLORS, 0) + self.assertRaises(curses.error, curses.init_pair, 1, 0, curses.COLORS) + + @requires_colors + def test_color_attrs(self): + for pair in 0, 1, 255: + attr = curses.color_pair(pair) + self.assertEqual(curses.pair_number(attr), pair, attr) + self.assertEqual(curses.pair_number(attr | curses.A_BOLD), pair) + self.assertEqual(curses.color_pair(0), 0) + self.assertEqual(curses.pair_number(0), 0) + + @requires_curses_func('use_default_colors') + @requires_colors + def test_use_default_colors(self): + self.assertIn(curses.pair_content(0), + ((curses.COLOR_WHITE, curses.COLOR_BLACK), (-1, -1))) + curses.use_default_colors() + self.assertEqual(curses.pair_content(0), (-1, -1)) @requires_curses_func('keyname') def test_keyname(self): diff --git a/Misc/NEWS.d/next/Library/2020-12-20-22-50-15.bpo-42681.lDO6jb.rst b/Misc/NEWS.d/next/Library/2020-12-20-22-50-15.bpo-42681.lDO6jb.rst new file mode 100644 index 00000000000000..34ea74a5a323d8 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2020-12-20-22-50-15.bpo-42681.lDO6jb.rst @@ -0,0 +1 @@ +Fixed range checks for color and pair numbers in :mod:`curses`. diff --git a/Modules/_cursesmodule.c b/Modules/_cursesmodule.c index c70b0e2a19fadc..0914e20466fab0 100644 --- a/Modules/_cursesmodule.c +++ b/Modules/_cursesmodule.c @@ -176,18 +176,6 @@ static char *screen_encoding = NULL; /* Utility Functions */ -static inline int -color_pair_to_attr(short color_number) -{ - return ((int)color_number << 8); -} - -static inline short -attr_to_color_pair(int attr) -{ - return (short)((attr & A_COLOR) >> 8); -} - /* * Check the return code from a curses function and return None * or raise an exception as appropriate. These are exported using the @@ -618,7 +606,7 @@ _curses_window_addch_impl(PyCursesWindowObject *self, int group_left_1, if (type == 2) { funcname = "add_wch"; wstr[1] = L'\0'; - setcchar(&wcval, wstr, attr, attr_to_color_pair(attr), NULL); + setcchar(&wcval, wstr, attr, PAIR_NUMBER(attr), NULL); if (coordinates_group) rtn = mvwadd_wch(self->win,y,x, &wcval); else { @@ -2586,7 +2574,7 @@ NoArgOrFlagNoReturnFunctionBody(cbreak, flag) _curses.color_content color_number: short - The number of the color (0 - COLORS). + The number of the color (0 - (COLORS-1)). / Return the red, green, and blue (RGB) components of the specified color. @@ -2597,7 +2585,7 @@ which will be between 0 (no component) and 1000 (maximum amount of component). static PyObject * _curses_color_content_impl(PyObject *module, short color_number) -/*[clinic end generated code: output=cb15cf3120d4bfc1 input=5555abb1c11e11b7]*/ +/*[clinic end generated code: output=cb15cf3120d4bfc1 input=630f6737514db6ad]*/ { short r,g,b; @@ -2616,8 +2604,8 @@ _curses_color_content_impl(PyObject *module, short color_number) /*[clinic input] _curses.color_pair - color_number: short - The number of the color (0 - COLORS). + pair_number: short + The number of the color pair. / Return the attribute value for displaying text in the specified color. @@ -2627,13 +2615,13 @@ other A_* attributes. pair_number() is the counterpart to this function. [clinic start generated code]*/ static PyObject * -_curses_color_pair_impl(PyObject *module, short color_number) -/*[clinic end generated code: output=6a84cb6b29ecaf9a input=a9d3eb6f50e4dc12]*/ +_curses_color_pair_impl(PyObject *module, short pair_number) +/*[clinic end generated code: output=ce609d238b70dc11 input=8dd0d5da94cb15b5]*/ { PyCursesInitialised; PyCursesInitialisedColor; - return PyLong_FromLong(color_pair_to_attr(color_number)); + return PyLong_FromLong(COLOR_PAIR(pair_number)); } /*[clinic input] @@ -3028,7 +3016,7 @@ _curses_has_key_impl(PyObject *module, int key) _curses.init_color color_number: short - The number of the color to be changed (0 - COLORS). + The number of the color to be changed (0 - (COLORS-1)). r: short Red component (0 - 1000). g: short @@ -3041,13 +3029,13 @@ Change the definition of a color. When init_color() is used, all occurrences of that color on the screen immediately change to the new definition. This function is a no-op on -most terminals; it is active only if can_change_color() returns 1. +most terminals; it is active only if can_change_color() returns true. [clinic start generated code]*/ static PyObject * _curses_init_color_impl(PyObject *module, short color_number, short r, short g, short b) -/*[clinic end generated code: output=280236f5efe9776a input=f3a05bd38f619175]*/ +/*[clinic end generated code: output=280236f5efe9776a input=128601b5dc76d548]*/ { PyCursesInitialised; PyCursesInitialisedColor; @@ -3061,9 +3049,9 @@ _curses.init_pair pair_number: short The number of the color-pair to be changed (1 - (COLOR_PAIRS-1)). fg: short - Foreground color number (0 - COLORS). + Foreground color number (-1 - (COLORS-1)). bg: short - Background color number (0 - COLORS). + Background color number (-1 - (COLORS-1)). / Change the definition of a color-pair. @@ -3075,7 +3063,7 @@ all occurrences of that color-pair are changed to the new definition. static PyObject * _curses_init_pair_impl(PyObject *module, short pair_number, short fg, short bg) -/*[clinic end generated code: output=9c2ce39c22f376b6 input=c9f0b11b17a2ac6d]*/ +/*[clinic end generated code: output=9c2ce39c22f376b6 input=12c320ec14396ea2]*/ { PyCursesInitialised; PyCursesInitialisedColor; @@ -3715,7 +3703,7 @@ _curses_pair_content_impl(PyObject *module, short pair_number) if (pair_content(pair_number, &f, &b)==ERR) { PyErr_SetString(PyCursesError, - "Argument 1 was out of range. (1..COLOR_PAIRS-1)"); + "Argument 1 was out of range. (0..COLOR_PAIRS-1)"); return NULL; } @@ -3740,7 +3728,7 @@ _curses_pair_number_impl(PyObject *module, int attr) PyCursesInitialised; PyCursesInitialisedColor; - return PyLong_FromLong(attr_to_color_pair(attr)); + return PyLong_FromLong(PAIR_NUMBER(attr)); } /*[clinic input] diff --git a/Modules/clinic/_cursesmodule.c.h b/Modules/clinic/_cursesmodule.c.h index 50d7f213e04e6d..66ffcdfdb3f99b 100644 --- a/Modules/clinic/_cursesmodule.c.h +++ b/Modules/clinic/_cursesmodule.c.h @@ -2028,7 +2028,7 @@ PyDoc_STRVAR(_curses_color_content__doc__, "Return the red, green, and blue (RGB) components of the specified color.\n" "\n" " color_number\n" -" The number of the color (0 - COLORS).\n" +" The number of the color (0 - (COLORS-1)).\n" "\n" "A 3-tuple is returned, containing the R, G, B values for the given color,\n" "which will be between 0 (no component) and 1000 (maximum amount of component)."); @@ -2076,13 +2076,13 @@ _curses_color_content(PyObject *module, PyObject *arg) } PyDoc_STRVAR(_curses_color_pair__doc__, -"color_pair($module, color_number, /)\n" +"color_pair($module, pair_number, /)\n" "--\n" "\n" "Return the attribute value for displaying text in the specified color.\n" "\n" -" color_number\n" -" The number of the color (0 - COLORS).\n" +" pair_number\n" +" The number of the color pair.\n" "\n" "This attribute value can be combined with A_STANDOUT, A_REVERSE, and the\n" "other A_* attributes. pair_number() is the counterpart to this function."); @@ -2091,13 +2091,13 @@ PyDoc_STRVAR(_curses_color_pair__doc__, {"color_pair", (PyCFunction)_curses_color_pair, METH_O, _curses_color_pair__doc__}, static PyObject * -_curses_color_pair_impl(PyObject *module, short color_number); +_curses_color_pair_impl(PyObject *module, short pair_number); static PyObject * _curses_color_pair(PyObject *module, PyObject *arg) { PyObject *return_value = NULL; - short color_number; + short pair_number; if (PyFloat_Check(arg)) { PyErr_SetString(PyExc_TypeError, @@ -2120,10 +2120,10 @@ _curses_color_pair(PyObject *module, PyObject *arg) goto exit; } else { - color_number = (short) ival; + pair_number = (short) ival; } } - return_value = _curses_color_pair_impl(module, color_number); + return_value = _curses_color_pair_impl(module, pair_number); exit: return return_value; @@ -2699,7 +2699,7 @@ PyDoc_STRVAR(_curses_init_color__doc__, "Change the definition of a color.\n" "\n" " color_number\n" -" The number of the color to be changed (0 - COLORS).\n" +" The number of the color to be changed (0 - (COLORS-1)).\n" " r\n" " Red component (0 - 1000).\n" " g\n" @@ -2709,7 +2709,7 @@ PyDoc_STRVAR(_curses_init_color__doc__, "\n" "When init_color() is used, all occurrences of that color on the screen\n" "immediately change to the new definition. This function is a no-op on\n" -"most terminals; it is active only if can_change_color() returns 1."); +"most terminals; it is active only if can_change_color() returns true."); #define _CURSES_INIT_COLOR_METHODDEF \ {"init_color", (PyCFunction)(void(*)(void))_curses_init_color, METH_FASTCALL, _curses_init_color__doc__}, @@ -2841,9 +2841,9 @@ PyDoc_STRVAR(_curses_init_pair__doc__, " pair_number\n" " The number of the color-pair to be changed (1 - (COLOR_PAIRS-1)).\n" " fg\n" -" Foreground color number (0 - COLORS).\n" +" Foreground color number (-1 - (COLORS-1)).\n" " bg\n" -" Background color number (0 - COLORS).\n" +" Background color number (-1 - (COLORS-1)).\n" "\n" "If the color-pair was previously initialized, the screen is refreshed and\n" "all occurrences of that color-pair are changed to the new definition."); @@ -4713,4 +4713,4 @@ _curses_use_default_colors(PyObject *module, PyObject *Py_UNUSED(ignored)) #ifndef _CURSES_USE_DEFAULT_COLORS_METHODDEF #define _CURSES_USE_DEFAULT_COLORS_METHODDEF #endif /* !defined(_CURSES_USE_DEFAULT_COLORS_METHODDEF) */ -/*[clinic end generated code: output=b53652f8acafd817 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=5e739120041df368 input=a9049054013a1b77]*/ From cb882f97bc142380460ea519829dc4baf0eb01f2 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 4 Jan 2021 02:17:30 -0800 Subject: [PATCH 0870/1314] bpo-42361: Update macOS installer build to use Tcl/Tk 8.6.11 (GH-24081) As of 2021-01-03, Tcl/Tk 8.6.11rc2 is expected to be the final release. (cherry picked from commit a38e04b566879a5040ea97428d7ee4331d76513f) Co-authored-by: Ned Deily --- Mac/BuildScript/build-installer.py | 6 +++--- .../next/macOS/2021-01-04-01-17-17.bpo-42361.eolZAi.rst | 2 ++ 2 files changed, 5 insertions(+), 3 deletions(-) create mode 100644 Misc/NEWS.d/next/macOS/2021-01-04-01-17-17.bpo-42361.eolZAi.rst diff --git a/Mac/BuildScript/build-installer.py b/Mac/BuildScript/build-installer.py index 16816d1cf86a44..38c66801de885a 100755 --- a/Mac/BuildScript/build-installer.py +++ b/Mac/BuildScript/build-installer.py @@ -263,10 +263,10 @@ def library_recipes(): tk_patches = ['tk868_on_10_8_10_9.patch'] else: - tcl_tk_ver='8.6.10' - tcl_checksum='97c55573f8520bcab74e21bfd8d0aadc' + tcl_tk_ver='8.6.11' + tcl_checksum='8a4c004f48984a03a7747e9ba06e4da4' - tk_checksum='602a47ad9ecac7bf655ada729d140a94' + tk_checksum='c7ee71a2d05bba78dfffd76528dc17c6' tk_patches = [ ] diff --git a/Misc/NEWS.d/next/macOS/2021-01-04-01-17-17.bpo-42361.eolZAi.rst b/Misc/NEWS.d/next/macOS/2021-01-04-01-17-17.bpo-42361.eolZAi.rst new file mode 100644 index 00000000000000..39526b32935b8c --- /dev/null +++ b/Misc/NEWS.d/next/macOS/2021-01-04-01-17-17.bpo-42361.eolZAi.rst @@ -0,0 +1,2 @@ +Update macOS installer build to use Tcl/Tk 8.6.11 (rc2, expected to be final +release). From fd235de6d3700da98cee370fb486957c04212c30 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 4 Jan 2021 02:22:07 -0800 Subject: [PATCH 0871/1314] Update Sphinx version for macOS installer build. (GH-24082) (GH-24087) (cherry picked from commit 0f3b96b368dd7ebb5dcd3759a30322dbd027f292) Co-authored-by: Ned Deily --- Mac/BuildScript/build-installer.py | 1 - 1 file changed, 1 deletion(-) diff --git a/Mac/BuildScript/build-installer.py b/Mac/BuildScript/build-installer.py index 38c66801de885a..cb3398964e0433 100755 --- a/Mac/BuildScript/build-installer.py +++ b/Mac/BuildScript/build-installer.py @@ -1138,7 +1138,6 @@ def buildPythonDocs(): if not os.path.exists(htmlDir): # Create virtual environment for docs builds with blurb and sphinx runCommand('make venv') - runCommand('venv/bin/python3 -m pip install -U Sphinx==2.3.1') runCommand('make html PYTHON=venv/bin/python') os.rename(htmlDir, docdir) os.chdir(curDir) From 76489dd2998ac70ffb300d612792a7238c03438c Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 4 Jan 2021 02:28:29 -0800 Subject: [PATCH 0872/1314] bpo-41837: Update macOS installer build to use OpenSSL 1.1.1i. (GH-24080) (GH-24083) (cherry picked from commit 14097a2785414c728d41d8d730a469a8c46ecdb9) Co-authored-by: Ned Deily --- Mac/BuildScript/build-installer.py | 9 ++-- Mac/BuildScript/openssl-mac-arm64.patch | 41 ------------------- .../2021-01-04-00-48-08.bpo-41837.dX-unJ.rst | 1 + 3 files changed, 4 insertions(+), 47 deletions(-) delete mode 100644 Mac/BuildScript/openssl-mac-arm64.patch create mode 100644 Misc/NEWS.d/next/macOS/2021-01-04-00-48-08.bpo-41837.dX-unJ.rst diff --git a/Mac/BuildScript/build-installer.py b/Mac/BuildScript/build-installer.py index cb3398964e0433..b51859823a4a0b 100755 --- a/Mac/BuildScript/build-installer.py +++ b/Mac/BuildScript/build-installer.py @@ -242,15 +242,12 @@ def library_recipes(): result.extend([ dict( - name="OpenSSL 1.1.1g", - url="https://www.openssl.org/source/openssl-1.1.1g.tar.gz", - checksum='76766e98997660138cdaf13a187bd234', + name="OpenSSL 1.1.1i", + url="https://www.openssl.org/source/openssl-1.1.1i.tar.gz", + checksum='08987c3cf125202e2b0840035efb392c', buildrecipe=build_universal_openssl, configure=None, install=None, - patches=[ - "openssl-mac-arm64.patch", - ], ), ]) diff --git a/Mac/BuildScript/openssl-mac-arm64.patch b/Mac/BuildScript/openssl-mac-arm64.patch deleted file mode 100644 index 11267fb118744a..00000000000000 --- a/Mac/BuildScript/openssl-mac-arm64.patch +++ /dev/null @@ -1,41 +0,0 @@ -diff -ur openssl-1.1.1g-orig/Configurations/10-main.conf openssl-1.1.1g/Configurations/10-main.conf ---- openssl-1.1.1g-orig/Configurations/10-main.conf 2020-04-21 14:22:39.000000000 +0200 -+++ openssl-1.1.1g/Configurations/10-main.conf 2020-07-26 12:21:32.000000000 +0200 -@@ -1557,6 +1557,14 @@ - bn_ops => "SIXTY_FOUR_BIT_LONG", - perlasm_scheme => "macosx", - }, -+ "darwin64-arm64-cc" => { -+ inherit_from => [ "darwin-common", asm("aarch64_asm") ], -+ CFLAGS => add("-Wall"), -+ cflags => add("-arch arm64"), -+ lib_cppflags => add("-DL_ENDIAN"), -+ bn_ops => "SIXTY_FOUR_BIT_LONG", -+ perlasm_scheme => "ios64", -+ }, - - ##### GNU Hurd - "hurd-x86" => { -diff -ur openssl-1.1.1g-orig/config openssl-1.1.1g/config ---- openssl-1.1.1g-orig/config 2020-04-21 14:22:39.000000000 +0200 -+++ openssl-1.1.1g/config 2020-07-26 12:21:59.000000000 +0200 -@@ -255,6 +255,9 @@ - ;; - x86_64) - echo "x86_64-apple-darwin${VERSION}" -+ ;; -+ arm64) -+ echo "arm64-apple-darwin${VERSION}" - ;; - *) - echo "i686-apple-darwin${VERSION}" -@@ -497,6 +500,9 @@ - else - OUT="darwin64-x86_64-cc" - fi ;; -+ x86_64-apple-darwin*) -+ OUT="darwin64-arm64-cc" -+ ;; - armv6+7-*-iphoneos) - __CNF_CFLAGS="$__CNF_CFLAGS -arch armv6 -arch armv7" - __CNF_CXXFLAGS="$__CNF_CXXFLAGS -arch armv6 -arch armv7" diff --git a/Misc/NEWS.d/next/macOS/2021-01-04-00-48-08.bpo-41837.dX-unJ.rst b/Misc/NEWS.d/next/macOS/2021-01-04-00-48-08.bpo-41837.dX-unJ.rst new file mode 100644 index 00000000000000..3f9415f4a36064 --- /dev/null +++ b/Misc/NEWS.d/next/macOS/2021-01-04-00-48-08.bpo-41837.dX-unJ.rst @@ -0,0 +1 @@ +Update macOS installer build to use OpenSSL 1.1.1i. From eedeaef1f22d27264ce9b031da80fe2485e85e69 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 4 Jan 2021 03:00:43 -0800 Subject: [PATCH 0873/1314] bpo-42692: fix __builtin_available check on older compilers (GH-23873) (GH-24090) A compiler that doesn't define `__has_builtin` will error out when it is used on the same line as the check for it. Automerge-Triggered-By: GH:ronaldoussoren (cherry picked from commit df21f502fdccec234282bf0a211af979fd23def4) Co-authored-by: Joshua Root --- .../next/Build/2021-01-04-05-07-30.bpo-42692.OO11SN.rst | 1 + Modules/posixmodule.c | 8 +++++++- 2 files changed, 8 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Build/2021-01-04-05-07-30.bpo-42692.OO11SN.rst diff --git a/Misc/NEWS.d/next/Build/2021-01-04-05-07-30.bpo-42692.OO11SN.rst b/Misc/NEWS.d/next/Build/2021-01-04-05-07-30.bpo-42692.OO11SN.rst new file mode 100644 index 00000000000000..91582b945b803f --- /dev/null +++ b/Misc/NEWS.d/next/Build/2021-01-04-05-07-30.bpo-42692.OO11SN.rst @@ -0,0 +1 @@ +Fix __builtin_available check on older compilers. Patch by Joshua Root. diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index d2ce8339e61f06..5e33502721c192 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -56,7 +56,13 @@ */ #if defined(__APPLE__) -#if defined(__has_builtin) && __has_builtin(__builtin_available) +#if defined(__has_builtin) +#if __has_builtin(__builtin_available) +#define HAVE_BUILTIN_AVAILABLE 1 +#endif +#endif + +#ifdef HAVE_BUILTIN_AVAILABLE # define HAVE_FSTATAT_RUNTIME __builtin_available(macOS 10.10, iOS 8.0, *) # define HAVE_FACCESSAT_RUNTIME __builtin_available(macOS 10.10, iOS 8.0, *) # define HAVE_FCHMODAT_RUNTIME __builtin_available(macOS 10.10, iOS 8.0, *) From e6d0107e13ed957109e79b796984d3d026a8660d Mon Sep 17 00:00:00 2001 From: Julien Palard Date: Mon, 4 Jan 2021 17:19:27 +0100 Subject: [PATCH 0874/1314] Revert "[3.9] [doc] Fix erroneous backslashes in signatures and names (GH-23658)" (GH-24092) This partially reverts commit e89993cff4e60fcf32643fc613d0544f3dbcd98a, which was removing backslashes in documentations compiled with Sphinx < 3, used for Python 3.8 and 3.9 docs. --- Doc/library/asyncio-stream.rst | 2 +- Doc/library/base64.rst | 2 +- Doc/library/difflib.rst | 6 +++--- Doc/library/email.header.rst | 2 +- Doc/library/functions.rst | 2 +- Doc/library/http.cookies.rst | 2 +- Doc/library/io.rst | 2 +- Doc/library/xml.dom.minidom.rst | 2 +- 8 files changed, 10 insertions(+), 10 deletions(-) diff --git a/Doc/library/asyncio-stream.rst b/Doc/library/asyncio-stream.rst index 584bf10fc042bc..714de8d41a3503 100644 --- a/Doc/library/asyncio-stream.rst +++ b/Doc/library/asyncio-stream.rst @@ -192,7 +192,7 @@ StreamReader can be read. Use the :attr:`IncompleteReadError.partial` attribute to get the partially read data. - .. coroutinemethod:: readuntil(separator=b'\n') + .. coroutinemethod:: readuntil(separator=b'\\n') Read data from the stream until *separator* is found. diff --git a/Doc/library/base64.rst b/Doc/library/base64.rst index e6934431626a36..1ff22a00d6199d 100644 --- a/Doc/library/base64.rst +++ b/Doc/library/base64.rst @@ -178,7 +178,7 @@ The modern interface provides: .. versionadded:: 3.4 -.. function:: a85decode(b, *, foldspaces=False, adobe=False, ignorechars=b' \t\n\r\v') +.. function:: a85decode(b, *, foldspaces=False, adobe=False, ignorechars=b' \\t\\n\\r\\v') Decode the Ascii85 encoded :term:`bytes-like object` or ASCII string *b* and return the decoded :class:`bytes`. diff --git a/Doc/library/difflib.rst b/Doc/library/difflib.rst index a5ee0fb5389793..aa08988c8b36f7 100644 --- a/Doc/library/difflib.rst +++ b/Doc/library/difflib.rst @@ -149,7 +149,7 @@ diffs. For comparing directories and files, see also, the :mod:`filecmp` module. contains a good example of its use. -.. function:: context_diff(a, b, fromfile='', tofile='', fromfiledate='', tofiledate='', n=3, lineterm='\n') +.. function:: context_diff(a, b, fromfile='', tofile='', fromfiledate='', tofiledate='', n=3, lineterm='\\n') Compare *a* and *b* (lists of strings); return a delta (a :term:`generator` generating the delta lines) in context diff format. @@ -279,7 +279,7 @@ diffs. For comparing directories and files, see also, the :mod:`filecmp` module. emu -.. function:: unified_diff(a, b, fromfile='', tofile='', fromfiledate='', tofiledate='', n=3, lineterm='\n') +.. function:: unified_diff(a, b, fromfile='', tofile='', fromfiledate='', tofiledate='', n=3, lineterm='\\n') Compare *a* and *b* (lists of strings); return a delta (a :term:`generator` generating the delta lines) in unified diff format. @@ -321,7 +321,7 @@ diffs. For comparing directories and files, see also, the :mod:`filecmp` module. See :ref:`difflib-interface` for a more detailed example. -.. function:: diff_bytes(dfunc, a, b, fromfile=b'', tofile=b'', fromfiledate=b'', tofiledate=b'', n=3, lineterm=b'\n') +.. function:: diff_bytes(dfunc, a, b, fromfile=b'', tofile=b'', fromfiledate=b'', tofiledate=b'', n=3, lineterm=b'\\n') Compare *a* and *b* (lists of bytes objects) using *dfunc*; yield a sequence of delta lines (also bytes) in the format returned by *dfunc*. diff --git a/Doc/library/email.header.rst b/Doc/library/email.header.rst index e093f138936b36..07152c224f2ff0 100644 --- a/Doc/library/email.header.rst +++ b/Doc/library/email.header.rst @@ -116,7 +116,7 @@ Here is the :class:`Header` class description: if *s* is a byte string. - .. method:: encode(splitchars=';, \t', maxlinelen=None, linesep='\n') + .. method:: encode(splitchars=';, \\t', maxlinelen=None, linesep='\\n') Encode a message header into an RFC-compliant format, possibly wrapping long lines and encapsulating non-ASCII parts in base64 or quoted-printable diff --git a/Doc/library/functions.rst b/Doc/library/functions.rst index 548ef59a47c6da..9c12b6c48d8ff0 100644 --- a/Doc/library/functions.rst +++ b/Doc/library/functions.rst @@ -1316,7 +1316,7 @@ are always available. They are listed here in alphabetical order. supported. -.. function:: print(*objects, sep=' ', end='\n', file=sys.stdout, flush=False) +.. function:: print(*objects, sep=' ', end='\\n', file=sys.stdout, flush=False) Print *objects* to the text stream *file*, separated by *sep* and followed by *end*. *sep*, *end*, *file* and *flush*, if present, must be given as keyword diff --git a/Doc/library/http.cookies.rst b/Doc/library/http.cookies.rst index a2c1eb00d8b33d..17792b200599bd 100644 --- a/Doc/library/http.cookies.rst +++ b/Doc/library/http.cookies.rst @@ -93,7 +93,7 @@ Cookie Objects :meth:`value_decode` are inverses on the range of *value_decode*. -.. method:: BaseCookie.output(attrs=None, header='Set-Cookie:', sep='\r\n') +.. method:: BaseCookie.output(attrs=None, header='Set-Cookie:', sep='\\r\\n') Return a string representation suitable to be sent as HTTP headers. *attrs* and *header* are sent to each :class:`Morsel`'s :meth:`output` method. *sep* is used diff --git a/Doc/library/io.rst b/Doc/library/io.rst index 048cb2a7ff6924..aecbec56866d73 100644 --- a/Doc/library/io.rst +++ b/Doc/library/io.rst @@ -964,7 +964,7 @@ Text I/O .. versionadded:: 3.7 -.. class:: StringIO(initial_value='', newline='\n') +.. class:: StringIO(initial_value='', newline='\\n') A text stream using an in-memory text buffer. It inherits :class:`TextIOBase`. diff --git a/Doc/library/xml.dom.minidom.rst b/Doc/library/xml.dom.minidom.rst index e1cc96794221ad..bf72c46561b7c7 100644 --- a/Doc/library/xml.dom.minidom.rst +++ b/Doc/library/xml.dom.minidom.rst @@ -174,7 +174,7 @@ module documentation. This section lists the differences between the API and The :meth:`toxml` method now preserves the attribute order specified by the user. -.. method:: Node.toprettyxml(indent="\t", newl="\n", encoding=None, \ +.. method:: Node.toprettyxml(indent="\\t", newl="\\n", encoding=None, \ standalone=None) Return a pretty-printed version of the document. *indent* specifies the From def7dc3b715d92ccc3e8a6a58ac36779435e41c9 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 4 Jan 2021 13:17:05 -0800 Subject: [PATCH 0875/1314] Do not remove x bit from published directories (GH-24101) (cherry picked from commit af4cd16479f2d55bee3db899e7679d7cde1d2ab7) Co-authored-by: Steve Dower --- Tools/msi/uploadrelease.ps1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Tools/msi/uploadrelease.ps1 b/Tools/msi/uploadrelease.ps1 index d3673b4582983c..7c825c443f2287 100644 --- a/Tools/msi/uploadrelease.ps1 +++ b/Tools/msi/uploadrelease.ps1 @@ -90,7 +90,7 @@ if (-not $skipupload) { $d = "$target/$($p[0])/" & $plink -batch $user@$server mkdir $d & $plink -batch $user@$server chgrp downloads $d - & $plink -batch $user@$server chmod g-x,o+rx $d + & $plink -batch $user@$server chmod o+rx $d & $pscp -batch $chm.FullName "$user@${server}:$d" if (-not $?) { throw "Failed to upload $chm" } @@ -115,7 +115,7 @@ if (-not $skipupload) { $sd = "$d$($a.Name)$($p[1])/" & $plink -batch $user@$server mkdir $sd & $plink -batch $user@$server chgrp downloads $sd - & $plink -batch $user@$server chmod g-x,o+rx $sd + & $plink -batch $user@$server chmod o+rx $sd & $pscp -batch $msi.FullName "$user@${server}:$sd" if (-not $?) { throw "Failed to upload $msi" } & $plink -batch $user@$server chgrp downloads $sd* From 80e5732d31bb7362c7b647acc618df701b3ae951 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 4 Jan 2021 15:41:03 -0800 Subject: [PATCH 0876/1314] bpo-40810: Fix CheckTraceCallbackContent for SQLite pre 3.7.15 (GH-20530) Ref. [SQLite 3.7.15 changelog](https://sqlite.org/changes.htmlGH-version_3_7_15): _"Avoid invoking the sqlite3_trace() callback multiple times when a statement is automatically reprepared due to SQLITE_SCHEMA errors."_ (cherry picked from commit f7f0ed59bcc41ed20674d4b2aa443d3b79e725f4) Co-authored-by: Erlend Egeberg Aasland --- Lib/sqlite3/test/hooks.py | 8 ++++++++ .../next/Tests/2020-05-30-10-56-38.bpo-40810.LPqDLQ.rst | 1 + 2 files changed, 9 insertions(+) create mode 100644 Misc/NEWS.d/next/Tests/2020-05-30-10-56-38.bpo-40810.LPqDLQ.rst diff --git a/Lib/sqlite3/test/hooks.py b/Lib/sqlite3/test/hooks.py index d74e74bf272275..214205c1167a41 100644 --- a/Lib/sqlite3/test/hooks.py +++ b/Lib/sqlite3/test/hooks.py @@ -265,6 +265,14 @@ def trace(statement): cur.execute(queries[0]) con2.execute("create table bar(x)") cur.execute(queries[1]) + + # Extract from SQLite 3.7.15 changelog: + # Avoid invoking the sqlite3_trace() callback multiple times when a + # statement is automatically reprepared due to SQLITE_SCHEMA errors. + # + # See bpo-40810 + if sqlite.sqlite_version_info < (3, 7, 15): + queries.append(queries[-1]) self.assertEqual(traced_statements, queries) diff --git a/Misc/NEWS.d/next/Tests/2020-05-30-10-56-38.bpo-40810.LPqDLQ.rst b/Misc/NEWS.d/next/Tests/2020-05-30-10-56-38.bpo-40810.LPqDLQ.rst new file mode 100644 index 00000000000000..1965ecd6ef511f --- /dev/null +++ b/Misc/NEWS.d/next/Tests/2020-05-30-10-56-38.bpo-40810.LPqDLQ.rst @@ -0,0 +1 @@ +In :mod:`sqlite3`, fix `CheckTraceCallbackContent` for SQLite pre 3.7.15. From 30e9ee3f438e1fcd2d26c89881228886de06afd6 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 5 Jan 2021 00:18:17 -0800 Subject: [PATCH 0877/1314] Fix broken NEWS markup (GH-24110) (cherry picked from commit cde988e893793f58bf87e7a8c014926fd2e32904) Co-authored-by: Brandt Bucher --- Misc/NEWS.d/next/Tests/2020-05-30-10-56-38.bpo-40810.LPqDLQ.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Misc/NEWS.d/next/Tests/2020-05-30-10-56-38.bpo-40810.LPqDLQ.rst b/Misc/NEWS.d/next/Tests/2020-05-30-10-56-38.bpo-40810.LPqDLQ.rst index 1965ecd6ef511f..eafd94cabede93 100644 --- a/Misc/NEWS.d/next/Tests/2020-05-30-10-56-38.bpo-40810.LPqDLQ.rst +++ b/Misc/NEWS.d/next/Tests/2020-05-30-10-56-38.bpo-40810.LPqDLQ.rst @@ -1 +1 @@ -In :mod:`sqlite3`, fix `CheckTraceCallbackContent` for SQLite pre 3.7.15. +In :mod:`sqlite3`, fix ``CheckTraceCallbackContent`` for SQLite pre 3.7.15. From d82392facefe0564dd55aa2adf04bf21c704858d Mon Sep 17 00:00:00 2001 From: Terry Jan Reedy Date: Tue, 5 Jan 2021 03:25:57 -0500 Subject: [PATCH 0878/1314] [3.9] bpo-32631: IDLE: Enable zzdummy example extension module (GH-14491) Make menu items work with formatter, add docstrings, add 100% tests. Co-authored-by: Terry Jan Reedy (cherry picked from commit e40e2a2cc94c554e7e245a8ca5a7432d31a95766) Co-authored-by: Cheryl Sabella --- Lib/idlelib/NEWS.txt | 3 + Lib/idlelib/configdialog.py | 10 +- Lib/idlelib/extend.txt | 18 +-- Lib/idlelib/idle_test/test_zzdummy.py | 152 ++++++++++++++++++ Lib/idlelib/zzdummy.py | 73 ++++++--- .../2019-06-30-20-31-09.bpo-32631.e7_4BG.rst | 2 + 6 files changed, 227 insertions(+), 31 deletions(-) create mode 100644 Lib/idlelib/idle_test/test_zzdummy.py create mode 100644 Misc/NEWS.d/next/IDLE/2019-06-30-20-31-09.bpo-32631.e7_4BG.rst diff --git a/Lib/idlelib/NEWS.txt b/Lib/idlelib/NEWS.txt index 869be0a62b7dba..c466fe9cc77766 100644 --- a/Lib/idlelib/NEWS.txt +++ b/Lib/idlelib/NEWS.txt @@ -3,6 +3,9 @@ Released on 2020-12-07? ====================================== +bpo-32631: Finish zzdummy example extension module: make menu entries +work; add docstrings and tests with 100% coverage. + bpo-42508: Keep IDLE running on macOS. Remove obsolete workaround that prevented running files with shortcuts when using new universal2 installers built on macOS 11. diff --git a/Lib/idlelib/configdialog.py b/Lib/idlelib/configdialog.py index a84e1c5668f99f..73e64852c69dfd 100644 --- a/Lib/idlelib/configdialog.py +++ b/Lib/idlelib/configdialog.py @@ -2316,7 +2316,15 @@ def detach(self): Shell Preferences: Auto-Squeeze Min. Lines is the minimum number of lines of output to automatically "squeeze". -''' +''', + 'Extensions': ''' +ZzDummy: This extension is provided as an example for how to create and +use an extension. Enable indicates whether the extension is active or +not; likewise enable_editor and enable_shell indicate which windows it +will be active on. For this extension, z-text is the text that will be +inserted at or removed from the beginning of the lines of selected text, +or the current line if no selection. +''', } diff --git a/Lib/idlelib/extend.txt b/Lib/idlelib/extend.txt index c9cb2e8297eb35..b482f76c4fb0f7 100644 --- a/Lib/idlelib/extend.txt +++ b/Lib/idlelib/extend.txt @@ -28,8 +28,8 @@ variables: (There are a few more, but they are rarely useful.) The extension class must not directly bind Window Manager (e.g. X) events. -Rather, it must define one or more virtual events, e.g. <>, and -corresponding methods, e.g. zoom_height_event(). The virtual events will be +Rather, it must define one or more virtual events, e.g. <>, and +corresponding methods, e.g. z_in_event(). The virtual events will be bound to the corresponding methods, and Window Manager events can then be bound to the virtual events. (This indirection is done so that the key bindings can easily be changed, and so that other sources of virtual events can exist, such @@ -54,21 +54,21 @@ Extensions are not required to define menu entries for all the events they implement. (They are also not required to create keybindings, but in that case there must be empty bindings in cofig-extensions.def) -Here is a complete example: +Here is a partial example from zzdummy.py: -class ZoomHeight: +class ZzDummy: menudefs = [ - ('edit', [ - None, # Separator - ('_Zoom Height', '<>'), - ]) + ('format', [ + ('Z in', '<>'), + ('Z out', '<>'), + ] ) ] def __init__(self, editwin): self.editwin = editwin - def zoom_height_event(self, event): + def z_in_event(self, event=None): "...Do what you want here..." The final piece of the puzzle is the file "config-extensions.def", which is diff --git a/Lib/idlelib/idle_test/test_zzdummy.py b/Lib/idlelib/idle_test/test_zzdummy.py new file mode 100644 index 00000000000000..1013cdc3c46f4f --- /dev/null +++ b/Lib/idlelib/idle_test/test_zzdummy.py @@ -0,0 +1,152 @@ +"Test zzdummy, coverage 100%." + +from idlelib import zzdummy +import unittest +from test.support import requires +from tkinter import Tk, Text +from unittest import mock +from idlelib import config +from idlelib import editor +from idlelib import format + + +usercfg = zzdummy.idleConf.userCfg +testcfg = { + 'main': config.IdleUserConfParser(''), + 'highlight': config.IdleUserConfParser(''), + 'keys': config.IdleUserConfParser(''), + 'extensions': config.IdleUserConfParser(''), +} +code_sample = """\ + +class C1(): + # Class comment. + def __init__(self, a, b): + self.a = a + self.b = b +""" + + +class DummyEditwin: + get_selection_indices = editor.EditorWindow.get_selection_indices + def __init__(self, root, text): + self.root = root + self.top = root + self.text = text + self.fregion = format.FormatRegion(self) + self.text.undo_block_start = mock.Mock() + self.text.undo_block_stop = mock.Mock() + + +class ZZDummyTest(unittest.TestCase): + + @classmethod + def setUpClass(cls): + requires('gui') + root = cls.root = Tk() + root.withdraw() + text = cls.text = Text(cls.root) + cls.editor = DummyEditwin(root, text) + zzdummy.idleConf.userCfg = testcfg + + @classmethod + def tearDownClass(cls): + zzdummy.idleConf.userCfg = usercfg + del cls.editor, cls.text + cls.root.update_idletasks() + for id in cls.root.tk.call('after', 'info'): + cls.root.after_cancel(id) # Need for EditorWindow. + cls.root.destroy() + del cls.root + + def setUp(self): + text = self.text + text.insert('1.0', code_sample) + text.undo_block_start.reset_mock() + text.undo_block_stop.reset_mock() + zz = self.zz = zzdummy.ZzDummy(self.editor) + zzdummy.ZzDummy.ztext = '# ignore #' + + def tearDown(self): + self.text.delete('1.0', 'end') + del self.zz + + def checklines(self, text, value): + # Verify that there are lines being checked. + end_line = int(float(text.index('end'))) + + # Check each line for the starting text. + actual = [] + for line in range(1, end_line): + txt = text.get(f'{line}.0', f'{line}.end') + actual.append(txt.startswith(value)) + return actual + + def test_init(self): + zz = self.zz + self.assertEqual(zz.editwin, self.editor) + self.assertEqual(zz.text, self.editor.text) + + def test_reload(self): + self.assertEqual(self.zz.ztext, '# ignore #') + testcfg['extensions'].SetOption('ZzDummy', 'z-text', 'spam') + zzdummy.ZzDummy.reload() + self.assertEqual(self.zz.ztext, 'spam') + + def test_z_in_event(self): + eq = self.assertEqual + zz = self.zz + text = zz.text + eq(self.zz.ztext, '# ignore #') + + # No lines have the leading text. + expected = [False, False, False, False, False, False, False] + actual = self.checklines(text, zz.ztext) + eq(expected, actual) + + text.tag_add('sel', '2.0', '4.end') + eq(zz.z_in_event(), 'break') + expected = [False, True, True, True, False, False, False] + actual = self.checklines(text, zz.ztext) + eq(expected, actual) + + text.undo_block_start.assert_called_once() + text.undo_block_stop.assert_called_once() + + def test_z_out_event(self): + eq = self.assertEqual + zz = self.zz + text = zz.text + eq(self.zz.ztext, '# ignore #') + + # Prepend text. + text.tag_add('sel', '2.0', '5.end') + zz.z_in_event() + text.undo_block_start.reset_mock() + text.undo_block_stop.reset_mock() + + # Select a few lines to remove text. + text.tag_remove('sel', '1.0', 'end') + text.tag_add('sel', '3.0', '4.end') + eq(zz.z_out_event(), 'break') + expected = [False, True, False, False, True, False, False] + actual = self.checklines(text, zz.ztext) + eq(expected, actual) + + text.undo_block_start.assert_called_once() + text.undo_block_stop.assert_called_once() + + def test_roundtrip(self): + # Insert and remove to all code should give back original text. + zz = self.zz + text = zz.text + + text.tag_add('sel', '1.0', 'end-1c') + zz.z_in_event() + zz.z_out_event() + + self.assertEqual(text.get('1.0', 'end-1c'), code_sample) + + +if __name__ == '__main__': + unittest.main(verbosity=2) diff --git a/Lib/idlelib/zzdummy.py b/Lib/idlelib/zzdummy.py index 3c4b1d23b0d379..1247e8f1cc0528 100644 --- a/Lib/idlelib/zzdummy.py +++ b/Lib/idlelib/zzdummy.py @@ -1,42 +1,73 @@ -"Example extension, also used for testing." +"""Example extension, also used for testing. + +See extend.txt for more details on creating an extension. +See config-extension.def for configuring an extension. +""" from idlelib.config import idleConf +from functools import wraps + + +def format_selection(format_line): + "Apply a formatting function to all of the selected lines." + + @wraps(format_line) + def apply(self, event=None): + head, tail, chars, lines = self.formatter.get_region() + for pos in range(len(lines) - 1): + line = lines[pos] + lines[pos] = format_line(self, line) + self.formatter.set_region(head, tail, chars, lines) + return 'break' -ztext = idleConf.GetOption('extensions', 'ZzDummy', 'z-text') + return apply class ZzDummy: + """Prepend or remove initial text from selected lines.""" -## menudefs = [ -## ('format', [ -## ('Z in', '<>'), -## ('Z out', '<>'), -## ] ) -## ] + # Extend the format menu. + menudefs = [ + ('format', [ + ('Z in', '<>'), + ('Z out', '<>'), + ] ) + ] def __init__(self, editwin): + "Initialize the settings for this extension." + self.editwin = editwin self.text = editwin.text - z_in = False + self.formatter = editwin.fregion @classmethod def reload(cls): + "Load class variables from config." cls.ztext = idleConf.GetOption('extensions', 'ZzDummy', 'z-text') - def z_in_event(self, event): + @format_selection + def z_in_event(self, line): + """Insert text at the beginning of each selected line. + + This is bound to the <> virtual event when the extensions + are loaded. """ + return f'{self.ztext}{line}' + + @format_selection + def z_out_event(self, line): + """Remove specific text from the beginning of each selected line. + + This is bound to the <> virtual event when the extensions + are loaded. """ - text = self.text - text.undo_block_start() - for line in range(1, text.index('end')): - text.insert('%d.0', ztext) - text.undo_block_stop() - return "break" + zlength = 0 if not line.startswith(self.ztext) else len(self.ztext) + return line[zlength:] - def z_out_event(self, event): pass ZzDummy.reload() -##if __name__ == "__main__": -## import unittest -## unittest.main('idlelib.idle_test.test_zzdummy', -## verbosity=2, exit=False) + +if __name__ == "__main__": + import unittest + unittest.main('idlelib.idle_test.test_zzdummy', verbosity=2, exit=False) diff --git a/Misc/NEWS.d/next/IDLE/2019-06-30-20-31-09.bpo-32631.e7_4BG.rst b/Misc/NEWS.d/next/IDLE/2019-06-30-20-31-09.bpo-32631.e7_4BG.rst new file mode 100644 index 00000000000000..c422f43b6d6dd8 --- /dev/null +++ b/Misc/NEWS.d/next/IDLE/2019-06-30-20-31-09.bpo-32631.e7_4BG.rst @@ -0,0 +1,2 @@ +Finish zzdummy example extension module: make menu entries work; +add docstrings and tests with 100% coverage. From 9b3a53a8264d4c469a3f3d8c037e74c010be3e5c Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Tue, 5 Jan 2021 14:23:19 +0200 Subject: [PATCH 0879/1314] [3.9] bpo-42681: Fix test_curses failures related to color pairs (GH-24089) (GH-24113) On ncurses 6.1 pair numbers are limited by SHORT_MAX-1. Improve error reporting and tests for color functions. (cherry picked from commit 59f9b4e4509be67494f3d45489fa55523175ff69) --- Lib/test/test_curses.py | 33 ++++++++++++++++++++++++++------- Modules/_cursesmodule.c | 26 ++++++++++++++++++-------- 2 files changed, 44 insertions(+), 15 deletions(-) diff --git a/Lib/test/test_curses.py b/Lib/test/test_curses.py index e310d191f97e90..de9f301737d8ca 100644 --- a/Lib/test/test_curses.py +++ b/Lib/test/test_curses.py @@ -323,11 +323,20 @@ def bad_colors(self): def bad_pairs(self): return (-2**31 - 1, 2**31, -2**63 - 1, 2**63, 2**64) + def test_start_color(self): + if not curses.has_colors(): + self.skipTest('requires colors support') + curses.start_color() + if verbose: + print(f'COLORS = {curses.COLORS}', file=sys.stderr) + print(f'COLOR_PAIRS = {curses.COLOR_PAIRS}', file=sys.stderr) + @requires_colors def test_color_content(self): self.assertEqual(curses.color_content(curses.COLOR_BLACK), (0, 0, 0)) curses.color_content(0) - curses.color_content(min(curses.COLORS - 1, SHORT_MAX)) + maxcolor = min(curses.COLORS - 1, SHORT_MAX) + curses.color_content(maxcolor) for color in self.bad_colors(): self.assertRaises(OverflowError, curses.color_content, color) @@ -368,13 +377,18 @@ def test_init_color(self): self.assertRaises(curses.error, curses.init_color, 0, 0, comp, 0) self.assertRaises(curses.error, curses.init_color, 0, 0, 0, comp) + def get_pair_limit(self): + return min(curses.COLOR_PAIRS, SHORT_MAX) + @requires_colors def test_pair_content(self): if not hasattr(curses, 'use_default_colors'): self.assertEqual(curses.pair_content(0), (curses.COLOR_WHITE, curses.COLOR_BLACK)) curses.pair_content(0) - curses.pair_content(min(curses.COLOR_PAIRS - 1, SHORT_MAX)) + maxpair = self.get_pair_limit() - 1 + if maxpair > 0: + curses.pair_content(maxpair) for pair in self.bad_pairs(): self.assertRaises(OverflowError, curses.pair_content, pair) @@ -389,11 +403,14 @@ def test_init_pair(self): curses.init_pair(1, 0, 0) self.assertEqual(curses.pair_content(1), (0, 0)) maxcolor = min(curses.COLORS - 1, SHORT_MAX) - curses.init_pair(1, maxcolor, maxcolor) - self.assertEqual(curses.pair_content(1), (maxcolor, maxcolor)) - maxpair = min(curses.COLOR_PAIRS - 1, SHORT_MAX) - curses.init_pair(maxpair, 2, 3) - self.assertEqual(curses.pair_content(maxpair), (2, 3)) + curses.init_pair(1, maxcolor, 0) + self.assertEqual(curses.pair_content(1), (maxcolor, 0)) + curses.init_pair(1, 0, maxcolor) + self.assertEqual(curses.pair_content(1), (0, maxcolor)) + maxpair = self.get_pair_limit() - 1 + if maxpair > 1: + curses.init_pair(maxpair, 0, 0) + self.assertEqual(curses.pair_content(maxpair), (0, 0)) for pair in self.bad_pairs(): self.assertRaises(OverflowError, curses.init_pair, pair, 0, 0) @@ -591,6 +608,8 @@ def test_update_lines_cols(self): @requires_curses_func('ncurses_version') def test_ncurses_version(self): v = curses.ncurses_version + if verbose: + print(f'ncurses_version = {curses.ncurses_version}', flush=True) self.assertIsInstance(v[:], tuple) self.assertEqual(len(v), 3) self.assertIsInstance(v[0], int) diff --git a/Modules/_cursesmodule.c b/Modules/_cursesmodule.c index 0914e20466fab0..d129248e363472 100644 --- a/Modules/_cursesmodule.c +++ b/Modules/_cursesmodule.c @@ -2592,13 +2592,18 @@ _curses_color_content_impl(PyObject *module, short color_number) PyCursesInitialised; PyCursesInitialisedColor; - if (color_content(color_number, &r, &g, &b) != ERR) - return Py_BuildValue("(iii)", r, g, b); - else { - PyErr_SetString(PyCursesError, - "Argument 1 was out of range. Check value of COLORS."); + if (color_content(color_number, &r, &g, &b) == ERR) { + if (color_number >= COLORS) { + PyErr_SetString(PyCursesError, + "Argument 1 was out of range. Check value of COLORS."); + } + else { + PyErr_SetString(PyCursesError, "color_content() returned ERR"); + } return NULL; } + + return Py_BuildValue("(iii)", r, g, b); } /*[clinic input] @@ -3701,9 +3706,14 @@ _curses_pair_content_impl(PyObject *module, short pair_number) PyCursesInitialised; PyCursesInitialisedColor; - if (pair_content(pair_number, &f, &b)==ERR) { - PyErr_SetString(PyCursesError, - "Argument 1 was out of range. (0..COLOR_PAIRS-1)"); + if (pair_content(pair_number, &f, &b) == ERR) { + if (pair_number >= COLOR_PAIRS) { + PyErr_SetString(PyCursesError, + "Argument 1 was out of range. (0..COLOR_PAIRS-1)"); + } + else { + PyErr_SetString(PyCursesError, "pair_content() returned ERR"); + } return NULL; } From 6e72ab909de58e89b5a7cd6899587e203cf129a3 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 5 Jan 2021 07:46:58 -0800 Subject: [PATCH 0880/1314] [3.9] bpo-40052: Fix alignment issue in PyVectorcall_Function() (GH-23999) (GH-24005) ``` In file included from /usr/include/python3.8/Python.h:147: In file included from /usr/include/python3.8/abstract.h:837: /usr/include/python3.8/cpython/abstract.h:91:11: error: cast from 'char *' to 'vectorcallfunc *' (aka 'struct _object *(**)(struct _object *, struct _object *const *, unsigned long, struct _object *)') increases required alignment from 1 to 8 [-Werror,-Wcast-align] ptr = (vectorcallfunc*)(((char *)callable) + offset); ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 1 error generated. ``` Co-authored-by: Petr Viktorin Co-Authored-By: Andreas Schneider Co-Authored-By: Antoine Pitrou (cherry picked from commit 056c08211b402b4dbc1530a9de9d00ad5309909f) --- Include/cpython/abstract.h | 6 +++--- .../next/C API/2020-03-24-09-27-10.bpo-40052.27P2KG.rst | 2 ++ Objects/call.c | 3 ++- 3 files changed, 7 insertions(+), 4 deletions(-) create mode 100644 Misc/NEWS.d/next/C API/2020-03-24-09-27-10.bpo-40052.27P2KG.rst diff --git a/Include/cpython/abstract.h b/Include/cpython/abstract.h index 7bc80833a746ef..0f1304d26af335 100644 --- a/Include/cpython/abstract.h +++ b/Include/cpython/abstract.h @@ -67,7 +67,7 @@ PyVectorcall_Function(PyObject *callable) { PyTypeObject *tp; Py_ssize_t offset; - vectorcallfunc *ptr; + vectorcallfunc ptr; assert(callable != NULL); tp = Py_TYPE(callable); @@ -77,8 +77,8 @@ PyVectorcall_Function(PyObject *callable) assert(PyCallable_Check(callable)); offset = tp->tp_vectorcall_offset; assert(offset > 0); - ptr = (vectorcallfunc *)(((char *)callable) + offset); - return *ptr; + memcpy(&ptr, (char *) callable + offset, sizeof(ptr)); + return ptr; } /* Call the callable object 'callable' with the "vectorcall" calling diff --git a/Misc/NEWS.d/next/C API/2020-03-24-09-27-10.bpo-40052.27P2KG.rst b/Misc/NEWS.d/next/C API/2020-03-24-09-27-10.bpo-40052.27P2KG.rst new file mode 100644 index 00000000000000..538488e2fbaccd --- /dev/null +++ b/Misc/NEWS.d/next/C API/2020-03-24-09-27-10.bpo-40052.27P2KG.rst @@ -0,0 +1,2 @@ +Fix an alignment build warning/error in function ``PyVectorcall_Function()``. +Patch by Andreas Schneider, Antoine Pitrou and Petr Viktorin. diff --git a/Objects/call.c b/Objects/call.c index 61426c7e09e4e7..87dc0dbbdb504a 100644 --- a/Objects/call.c +++ b/Objects/call.c @@ -205,6 +205,7 @@ PyObject * PyVectorcall_Call(PyObject *callable, PyObject *tuple, PyObject *kwargs) { PyThreadState *tstate = _PyThreadState_GET(); + vectorcallfunc func; /* get vectorcallfunc as in PyVectorcall_Function, but without * the Py_TPFLAGS_HAVE_VECTORCALL check */ @@ -215,7 +216,7 @@ PyVectorcall_Call(PyObject *callable, PyObject *tuple, PyObject *kwargs) Py_TYPE(callable)->tp_name); return NULL; } - vectorcallfunc func = *(vectorcallfunc *)(((char *)callable) + offset); + memcpy(&func, (char *) callable + offset, sizeof(func)); if (func == NULL) { _PyErr_Format(tstate, PyExc_TypeError, "'%.200s' object does not support vectorcall", From e9a71dab094c0467f07d13cce4324c8a93727863 Mon Sep 17 00:00:00 2001 From: Erlend Egeberg Aasland Date: Tue, 5 Jan 2021 23:52:55 +0100 Subject: [PATCH 0881/1314] [3.9] bpo-42584: Update macOS installer to use SQLite 3.34.0 (GH-23674) (GH-24130) (cherry picked from commit c94ee13ad596d26d1859078bc09806aa59bb0000) Co-authored-by: Erlend Egeberg Aasland Automerge-Triggered-By: GH:ned-deily --- Mac/BuildScript/build-installer.py | 8 ++++---- .../next/macOS/2020-12-07-11-37-35.bpo-42584.LygmqQ.rst | 1 + 2 files changed, 5 insertions(+), 4 deletions(-) create mode 100644 Misc/NEWS.d/next/macOS/2020-12-07-11-37-35.bpo-42584.LygmqQ.rst diff --git a/Mac/BuildScript/build-installer.py b/Mac/BuildScript/build-installer.py index b51859823a4a0b..ef64502ab780c7 100755 --- a/Mac/BuildScript/build-installer.py +++ b/Mac/BuildScript/build-installer.py @@ -354,9 +354,9 @@ def library_recipes(): ), ), dict( - name="SQLite 3.33.0", - url="https://sqlite.org/2020/sqlite-autoconf-3330000.tar.gz", - checksum='842a8a100d7b01b09e543deb2b7951dd', + name="SQLite 3.34.0", + url="https://sqlite.org/2020/sqlite-autoconf-3340000.tar.gz", + checksum='7f33c9db7b713957fcb9271fe9049fef', extra_cflags=('-Os ' '-DSQLITE_ENABLE_FTS5 ' '-DSQLITE_ENABLE_FTS4 ' @@ -1611,7 +1611,7 @@ def buildDMG(): if os.path.exists(outdir): shutil.rmtree(outdir) - # We used to use the deployment target as the last characters of the + # We used to use the deployment target as the last characters of the # installer file name. With the introduction of weaklinked installer # variants, we may have two variants with the same file name, i.e. # both ending in '10.9'. To avoid this, we now use the major/minor diff --git a/Misc/NEWS.d/next/macOS/2020-12-07-11-37-35.bpo-42584.LygmqQ.rst b/Misc/NEWS.d/next/macOS/2020-12-07-11-37-35.bpo-42584.LygmqQ.rst new file mode 100644 index 00000000000000..2a625f98e90781 --- /dev/null +++ b/Misc/NEWS.d/next/macOS/2020-12-07-11-37-35.bpo-42584.LygmqQ.rst @@ -0,0 +1 @@ +Update macOS installer to use SQLite 3.34.0. From c8333931434389ae72da9eb0471054f4393249db Mon Sep 17 00:00:00 2001 From: Steve Dower Date: Tue, 5 Jan 2021 23:37:29 +0000 Subject: [PATCH 0882/1314] bpo-41837: Updated Windows installer to include OpenSSL 1.1.1i (GH-24125) --- .../next/Windows/2021-01-05-20-36-40.bpo-41837.bmS7vB.rst | 1 + PCbuild/get_externals.bat | 4 ++-- PCbuild/python.props | 4 ++-- PCbuild/readme.txt | 2 +- 4 files changed, 6 insertions(+), 5 deletions(-) create mode 100644 Misc/NEWS.d/next/Windows/2021-01-05-20-36-40.bpo-41837.bmS7vB.rst diff --git a/Misc/NEWS.d/next/Windows/2021-01-05-20-36-40.bpo-41837.bmS7vB.rst b/Misc/NEWS.d/next/Windows/2021-01-05-20-36-40.bpo-41837.bmS7vB.rst new file mode 100644 index 00000000000000..8d4bb34ff909c2 --- /dev/null +++ b/Misc/NEWS.d/next/Windows/2021-01-05-20-36-40.bpo-41837.bmS7vB.rst @@ -0,0 +1 @@ +Updated Windows installer to include OpenSSL 1.1.1i diff --git a/PCbuild/get_externals.bat b/PCbuild/get_externals.bat index 3bb281904f6a61..3e9cb0299fca6e 100644 --- a/PCbuild/get_externals.bat +++ b/PCbuild/get_externals.bat @@ -53,7 +53,7 @@ echo.Fetching external libraries... set libraries= set libraries=%libraries% bzip2-1.0.6 if NOT "%IncludeLibffiSrc%"=="false" set libraries=%libraries% libffi -if NOT "%IncludeSSLSrc%"=="false" set libraries=%libraries% openssl-1.1.1g +if NOT "%IncludeSSLSrc%"=="false" set libraries=%libraries% openssl-1.1.1i set libraries=%libraries% sqlite-3.33.0.0 if NOT "%IncludeTkinterSrc%"=="false" set libraries=%libraries% tcl-core-8.6.9.0 if NOT "%IncludeTkinterSrc%"=="false" set libraries=%libraries% tk-8.6.9.0 @@ -77,7 +77,7 @@ echo.Fetching external binaries... set binaries= if NOT "%IncludeLibffi%"=="false" set binaries=%binaries% libffi -if NOT "%IncludeSSL%"=="false" set binaries=%binaries% openssl-bin-1.1.1g +if NOT "%IncludeSSL%"=="false" set binaries=%binaries% openssl-bin-1.1.1i if NOT "%IncludeTkinter%"=="false" set binaries=%binaries% tcltk-8.6.9.0 if NOT "%IncludeSSLSrc%"=="false" set binaries=%binaries% nasm-2.11.06 diff --git a/PCbuild/python.props b/PCbuild/python.props index acc41a2c017684..769dabc5641ca9 100644 --- a/PCbuild/python.props +++ b/PCbuild/python.props @@ -62,8 +62,8 @@ $(ExternalsDir)libffi\ $(ExternalsDir)libffi\$(ArchName)\ $(libffiOutDir)include - $(ExternalsDir)openssl-1.1.1g\ - $(ExternalsDir)openssl-bin-1.1.1g\$(ArchName)\ + $(ExternalsDir)openssl-1.1.1i\ + $(ExternalsDir)openssl-bin-1.1.1i\$(ArchName)\ $(opensslOutDir)include $(ExternalsDir)\nasm-2.11.06\ $(ExternalsDir)\zlib-1.2.11\ diff --git a/PCbuild/readme.txt b/PCbuild/readme.txt index bafd91248a5871..c00ee8e3292774 100644 --- a/PCbuild/readme.txt +++ b/PCbuild/readme.txt @@ -166,7 +166,7 @@ _lzma Homepage: http://tukaani.org/xz/ _ssl - Python wrapper for version 1.1.1c of the OpenSSL secure sockets + Python wrapper for version 1.1.1i of the OpenSSL secure sockets library, which is downloaded from our binaries repository at https://github.com/python/cpython-bin-deps. From 77d54710506b67e48b50bb1758fb31fc33a33c83 Mon Sep 17 00:00:00 2001 From: Steve Dower Date: Wed, 6 Jan 2021 00:09:08 +0000 Subject: [PATCH 0883/1314] bpo-42584: Update Windows installer to use SQLite 3.34.0 (GH-23675) Co-authored-by: Erlend Egeberg Aasland --- .../next/Windows/2020-12-07-11-40-52.bpo-42584.AsYnVX.rst | 1 + PCbuild/get_externals.bat | 2 +- PCbuild/python.props | 2 +- PCbuild/readme.txt | 2 +- 4 files changed, 4 insertions(+), 3 deletions(-) create mode 100644 Misc/NEWS.d/next/Windows/2020-12-07-11-40-52.bpo-42584.AsYnVX.rst diff --git a/Misc/NEWS.d/next/Windows/2020-12-07-11-40-52.bpo-42584.AsYnVX.rst b/Misc/NEWS.d/next/Windows/2020-12-07-11-40-52.bpo-42584.AsYnVX.rst new file mode 100644 index 00000000000000..afb6530c8f66d7 --- /dev/null +++ b/Misc/NEWS.d/next/Windows/2020-12-07-11-40-52.bpo-42584.AsYnVX.rst @@ -0,0 +1 @@ +Upgrade Windows installer to use SQLite 3.34.0. diff --git a/PCbuild/get_externals.bat b/PCbuild/get_externals.bat index 3e9cb0299fca6e..1e783846a2b908 100644 --- a/PCbuild/get_externals.bat +++ b/PCbuild/get_externals.bat @@ -54,7 +54,7 @@ set libraries= set libraries=%libraries% bzip2-1.0.6 if NOT "%IncludeLibffiSrc%"=="false" set libraries=%libraries% libffi if NOT "%IncludeSSLSrc%"=="false" set libraries=%libraries% openssl-1.1.1i -set libraries=%libraries% sqlite-3.33.0.0 +set libraries=%libraries% sqlite-3.34.0.0 if NOT "%IncludeTkinterSrc%"=="false" set libraries=%libraries% tcl-core-8.6.9.0 if NOT "%IncludeTkinterSrc%"=="false" set libraries=%libraries% tk-8.6.9.0 if NOT "%IncludeTkinterSrc%"=="false" set libraries=%libraries% tix-8.4.3.6 diff --git a/PCbuild/python.props b/PCbuild/python.props index 769dabc5641ca9..3fa774816a7530 100644 --- a/PCbuild/python.props +++ b/PCbuild/python.props @@ -56,7 +56,7 @@ $(EXTERNALS_DIR) $([System.IO.Path]::GetFullPath(`$(PySourcePath)externals`)) $(ExternalsDir)\ - $(ExternalsDir)sqlite-3.33.0.0\ + $(ExternalsDir)sqlite-3.34.0.0\ $(ExternalsDir)bzip2-1.0.6\ $(ExternalsDir)xz-5.2.2\ $(ExternalsDir)libffi\ diff --git a/PCbuild/readme.txt b/PCbuild/readme.txt index c00ee8e3292774..5a21c30af9487a 100644 --- a/PCbuild/readme.txt +++ b/PCbuild/readme.txt @@ -185,7 +185,7 @@ _ssl again when building. _sqlite3 - Wraps SQLite 3.33.0, which is itself built by sqlite3.vcxproj + Wraps SQLite 3.34.0, which is itself built by sqlite3.vcxproj Homepage: http://www.sqlite.org/ _tkinter From a3ca6747f50efa2fe59caf516a26b0fd1912b8e8 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 5 Jan 2021 18:27:30 -0800 Subject: [PATCH 0884/1314] bpo-14014: Clarify StreamWriter.reset() documentation (GH-13716) (cherry picked from commit 1a9f51ed12feb4d95ad6d0faf610a030c05b9f5e) Co-authored-by: Berker Peksag --- Doc/library/codecs.rst | 4 ++-- Lib/codecs.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Doc/library/codecs.rst b/Doc/library/codecs.rst index f071057293eece..6eb907afce3c6c 100644 --- a/Doc/library/codecs.rst +++ b/Doc/library/codecs.rst @@ -694,7 +694,7 @@ compatible with the Python codec registry. .. method:: reset() - Flushes and resets the codec buffers used for keeping state. + Resets the codec buffers used for keeping internal state. Calling this method should ensure that the data on the output is put into a clean state that allows appending of new fresh data without having to @@ -789,7 +789,7 @@ compatible with the Python codec registry. .. method:: reset() - Resets the codec buffers used for keeping state. + Resets the codec buffers used for keeping internal state. Note that no stream repositioning should take place. This method is primarily intended to be able to recover from decoding errors. diff --git a/Lib/codecs.py b/Lib/codecs.py index 7f23e9775df804..d2edd148a290aa 100644 --- a/Lib/codecs.py +++ b/Lib/codecs.py @@ -386,7 +386,7 @@ def writelines(self, list): def reset(self): - """ Flushes and resets the codec buffers used for keeping state. + """ Resets the codec buffers used for keeping internal state. Calling this method should ensure that the data on the output is put into a clean state, that allows appending @@ -620,7 +620,7 @@ def readlines(self, sizehint=None, keepends=True): def reset(self): - """ Resets the codec buffers used for keeping state. + """ Resets the codec buffers used for keeping internal state. Note that no stream repositioning should take place. This method is primarily intended to be able to recover From faf49573963921033c608b4d2f398309d9f0d2b5 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 6 Jan 2021 04:54:18 -0800 Subject: [PATCH 0885/1314] bpo-42528: Improve the docs of most Py*_Check{,Exact} API calls (GH-23602) (GH-24139) I think that none of these API calls can fail, but only few of them are documented as such. Add the sentence "This function always succeeds" (which is the same already used e.g. by PyNumber_Check) to all of them. (cherry picked from commit 315fc52db17b19fe30aa9193f26adf69e18d8844) Co-authored-by: Antonio Cuni Co-authored-by: Antonio Cuni --- Doc/c-api/bool.rst | 3 ++- Doc/c-api/bytearray.rst | 4 ++-- Doc/c-api/bytes.rst | 4 ++-- Doc/c-api/capsule.rst | 3 ++- Doc/c-api/cell.rst | 3 ++- Doc/c-api/code.rst | 2 +- Doc/c-api/complex.rst | 4 ++-- Doc/c-api/coro.rst | 1 + Doc/c-api/datetime.rst | 25 +++++++++++++++---------- Doc/c-api/dict.rst | 4 ++-- Doc/c-api/float.rst | 4 ++-- Doc/c-api/function.rst | 2 +- Doc/c-api/gen.rst | 6 ++++-- Doc/c-api/iter.rst | 3 ++- Doc/c-api/iterator.rst | 6 ++++-- Doc/c-api/list.rst | 4 ++-- Doc/c-api/long.rst | 4 ++-- Doc/c-api/memoryview.rst | 3 ++- Doc/c-api/method.rst | 3 ++- Doc/c-api/module.rst | 3 ++- Doc/c-api/set.rst | 9 +++++---- Doc/c-api/slice.rst | 3 ++- Doc/c-api/tuple.rst | 6 +++--- Doc/c-api/type.rst | 6 ++++-- Doc/c-api/unicode.rst | 4 ++-- Doc/c-api/weakref.rst | 7 ++++--- 26 files changed, 74 insertions(+), 52 deletions(-) diff --git a/Doc/c-api/bool.rst b/Doc/c-api/bool.rst index ce8de6e22f44ca..c197d447e9618c 100644 --- a/Doc/c-api/bool.rst +++ b/Doc/c-api/bool.rst @@ -13,7 +13,8 @@ are available, however. .. c:function:: int PyBool_Check(PyObject *o) - Return true if *o* is of type :c:data:`PyBool_Type`. + Return true if *o* is of type :c:data:`PyBool_Type`. This function always + succeeds. .. c:var:: PyObject* Py_False diff --git a/Doc/c-api/bytearray.rst b/Doc/c-api/bytearray.rst index b2f409c15abb7a..30bcfc7cf9f500 100644 --- a/Doc/c-api/bytearray.rst +++ b/Doc/c-api/bytearray.rst @@ -25,13 +25,13 @@ Type check macros .. c:function:: int PyByteArray_Check(PyObject *o) Return true if the object *o* is a bytearray object or an instance of a - subtype of the bytearray type. + subtype of the bytearray type. This function always succeeds. .. c:function:: int PyByteArray_CheckExact(PyObject *o) Return true if the object *o* is a bytearray object, but not an instance of a - subtype of the bytearray type. + subtype of the bytearray type. This function always succeeds. Direct API functions diff --git a/Doc/c-api/bytes.rst b/Doc/c-api/bytes.rst index 0e33ed2c7c9403..de65701037a7c1 100644 --- a/Doc/c-api/bytes.rst +++ b/Doc/c-api/bytes.rst @@ -25,13 +25,13 @@ called with a non-bytes parameter. .. c:function:: int PyBytes_Check(PyObject *o) Return true if the object *o* is a bytes object or an instance of a subtype - of the bytes type. + of the bytes type. This function always succeeds. .. c:function:: int PyBytes_CheckExact(PyObject *o) Return true if the object *o* is a bytes object, but not an instance of a - subtype of the bytes type. + subtype of the bytes type. This function always succeeds. .. c:function:: PyObject* PyBytes_FromString(const char *v) diff --git a/Doc/c-api/capsule.rst b/Doc/c-api/capsule.rst index 5eb313c89bfd59..908e92653dd483 100644 --- a/Doc/c-api/capsule.rst +++ b/Doc/c-api/capsule.rst @@ -34,7 +34,8 @@ Refer to :ref:`using-capsules` for more information on using these objects. .. c:function:: int PyCapsule_CheckExact(PyObject *p) - Return true if its argument is a :c:type:`PyCapsule`. + Return true if its argument is a :c:type:`PyCapsule`. This function always + succeeds. .. c:function:: PyObject* PyCapsule_New(void *pointer, const char *name, PyCapsule_Destructor destructor) diff --git a/Doc/c-api/cell.rst b/Doc/c-api/cell.rst index 8408f7e398db7b..ac4ef5adc5cc20 100644 --- a/Doc/c-api/cell.rst +++ b/Doc/c-api/cell.rst @@ -27,7 +27,8 @@ Cell objects are not likely to be useful elsewhere. .. c:function:: int PyCell_Check(ob) - Return true if *ob* is a cell object; *ob* must not be ``NULL``. + Return true if *ob* is a cell object; *ob* must not be ``NULL``. This + function always succeeds. .. c:function:: PyObject* PyCell_New(PyObject *ob) diff --git a/Doc/c-api/code.rst b/Doc/c-api/code.rst index 6f8c41ccbf6e85..b3a17f1898e8e1 100644 --- a/Doc/c-api/code.rst +++ b/Doc/c-api/code.rst @@ -27,7 +27,7 @@ bound into a function. .. c:function:: int PyCode_Check(PyObject *co) - Return true if *co* is a :class:`code` object. + Return true if *co* is a :class:`code` object. This function always succeeds. .. c:function:: int PyCode_GetNumFree(PyCodeObject *co) diff --git a/Doc/c-api/complex.rst b/Doc/c-api/complex.rst index 06dbb2572725ee..e2ea766b3a32a7 100644 --- a/Doc/c-api/complex.rst +++ b/Doc/c-api/complex.rst @@ -94,13 +94,13 @@ Complex Numbers as Python Objects .. c:function:: int PyComplex_Check(PyObject *p) Return true if its argument is a :c:type:`PyComplexObject` or a subtype of - :c:type:`PyComplexObject`. + :c:type:`PyComplexObject`. This function always succeeds. .. c:function:: int PyComplex_CheckExact(PyObject *p) Return true if its argument is a :c:type:`PyComplexObject`, but not a subtype of - :c:type:`PyComplexObject`. + :c:type:`PyComplexObject`. This function always succeeds. .. c:function:: PyObject* PyComplex_FromCComplex(Py_complex v) diff --git a/Doc/c-api/coro.rst b/Doc/c-api/coro.rst index 2260944a9a93a9..caa855a10d20ca 100644 --- a/Doc/c-api/coro.rst +++ b/Doc/c-api/coro.rst @@ -24,6 +24,7 @@ return. .. c:function:: int PyCoro_CheckExact(PyObject *ob) Return true if *ob*'s type is :c:type:`PyCoro_Type`; *ob* must not be ``NULL``. + This function always succeeds. .. c:function:: PyObject* PyCoro_New(PyFrameObject *frame, PyObject *name, PyObject *qualname) diff --git a/Doc/c-api/datetime.rst b/Doc/c-api/datetime.rst index bd4f1ff446bcf4..66f148df286807 100644 --- a/Doc/c-api/datetime.rst +++ b/Doc/c-api/datetime.rst @@ -28,61 +28,66 @@ Type-check macros: .. c:function:: int PyDate_Check(PyObject *ob) Return true if *ob* is of type :c:data:`PyDateTime_DateType` or a subtype of - :c:data:`PyDateTime_DateType`. *ob* must not be ``NULL``. + :c:data:`PyDateTime_DateType`. *ob* must not be ``NULL``. This function always + succeeds. .. c:function:: int PyDate_CheckExact(PyObject *ob) Return true if *ob* is of type :c:data:`PyDateTime_DateType`. *ob* must not be - ``NULL``. + ``NULL``. This function always succeeds. .. c:function:: int PyDateTime_Check(PyObject *ob) Return true if *ob* is of type :c:data:`PyDateTime_DateTimeType` or a subtype of - :c:data:`PyDateTime_DateTimeType`. *ob* must not be ``NULL``. + :c:data:`PyDateTime_DateTimeType`. *ob* must not be ``NULL``. This function always + succeeds. .. c:function:: int PyDateTime_CheckExact(PyObject *ob) Return true if *ob* is of type :c:data:`PyDateTime_DateTimeType`. *ob* must not - be ``NULL``. + be ``NULL``. This function always succeeds. .. c:function:: int PyTime_Check(PyObject *ob) Return true if *ob* is of type :c:data:`PyDateTime_TimeType` or a subtype of - :c:data:`PyDateTime_TimeType`. *ob* must not be ``NULL``. + :c:data:`PyDateTime_TimeType`. *ob* must not be ``NULL``. This function always + succeeds. .. c:function:: int PyTime_CheckExact(PyObject *ob) Return true if *ob* is of type :c:data:`PyDateTime_TimeType`. *ob* must not be - ``NULL``. + ``NULL``. This function always succeeds. .. c:function:: int PyDelta_Check(PyObject *ob) Return true if *ob* is of type :c:data:`PyDateTime_DeltaType` or a subtype of - :c:data:`PyDateTime_DeltaType`. *ob* must not be ``NULL``. + :c:data:`PyDateTime_DeltaType`. *ob* must not be ``NULL``. This function always + succeeds. .. c:function:: int PyDelta_CheckExact(PyObject *ob) Return true if *ob* is of type :c:data:`PyDateTime_DeltaType`. *ob* must not be - ``NULL``. + ``NULL``. This function always succeeds. .. c:function:: int PyTZInfo_Check(PyObject *ob) Return true if *ob* is of type :c:data:`PyDateTime_TZInfoType` or a subtype of - :c:data:`PyDateTime_TZInfoType`. *ob* must not be ``NULL``. + :c:data:`PyDateTime_TZInfoType`. *ob* must not be ``NULL``. This function always + succeeds. .. c:function:: int PyTZInfo_CheckExact(PyObject *ob) Return true if *ob* is of type :c:data:`PyDateTime_TZInfoType`. *ob* must not be - ``NULL``. + ``NULL``. This function always succeeds. Macros to create objects: diff --git a/Doc/c-api/dict.rst b/Doc/c-api/dict.rst index 8c626c7d4a9403..5803ac2ad97adb 100644 --- a/Doc/c-api/dict.rst +++ b/Doc/c-api/dict.rst @@ -22,13 +22,13 @@ Dictionary Objects .. c:function:: int PyDict_Check(PyObject *p) Return true if *p* is a dict object or an instance of a subtype of the dict - type. + type. This function always succeeds. .. c:function:: int PyDict_CheckExact(PyObject *p) Return true if *p* is a dict object, but not an instance of a subtype of - the dict type. + the dict type. This function always succeeds. .. c:function:: PyObject* PyDict_New() diff --git a/Doc/c-api/float.rst b/Doc/c-api/float.rst index b29937dbecdcfd..c107243a88dfc6 100644 --- a/Doc/c-api/float.rst +++ b/Doc/c-api/float.rst @@ -22,13 +22,13 @@ Floating Point Objects .. c:function:: int PyFloat_Check(PyObject *p) Return true if its argument is a :c:type:`PyFloatObject` or a subtype of - :c:type:`PyFloatObject`. + :c:type:`PyFloatObject`. This function always succeeds. .. c:function:: int PyFloat_CheckExact(PyObject *p) Return true if its argument is a :c:type:`PyFloatObject`, but not a subtype of - :c:type:`PyFloatObject`. + :c:type:`PyFloatObject`. This function always succeeds. .. c:function:: PyObject* PyFloat_FromString(PyObject *str) diff --git a/Doc/c-api/function.rst b/Doc/c-api/function.rst index bb416f4bb63aa2..20968828e0bb36 100644 --- a/Doc/c-api/function.rst +++ b/Doc/c-api/function.rst @@ -26,7 +26,7 @@ There are a few functions specific to Python functions. .. c:function:: int PyFunction_Check(PyObject *o) Return true if *o* is a function object (has type :c:data:`PyFunction_Type`). - The parameter must not be ``NULL``. + The parameter must not be ``NULL``. This function always succeeds. .. c:function:: PyObject* PyFunction_New(PyObject *code, PyObject *globals) diff --git a/Doc/c-api/gen.rst b/Doc/c-api/gen.rst index 74410927bfde10..0eb5922f6da75f 100644 --- a/Doc/c-api/gen.rst +++ b/Doc/c-api/gen.rst @@ -22,12 +22,14 @@ than explicitly calling :c:func:`PyGen_New` or :c:func:`PyGen_NewWithQualName`. .. c:function:: int PyGen_Check(PyObject *ob) - Return true if *ob* is a generator object; *ob* must not be ``NULL``. + Return true if *ob* is a generator object; *ob* must not be ``NULL``. This + function always succeeds. .. c:function:: int PyGen_CheckExact(PyObject *ob) - Return true if *ob*'s type is :c:type:`PyGen_Type`; *ob* must not be ``NULL``. + Return true if *ob*'s type is :c:type:`PyGen_Type`; *ob* must not be + ``NULL``. This function always succeeds. .. c:function:: PyObject* PyGen_New(PyFrameObject *frame) diff --git a/Doc/c-api/iter.rst b/Doc/c-api/iter.rst index a2992b3452f91c..189f80b9b81932 100644 --- a/Doc/c-api/iter.rst +++ b/Doc/c-api/iter.rst @@ -9,7 +9,8 @@ There are two functions specifically for working with iterators. .. c:function:: int PyIter_Check(PyObject *o) - Return true if the object *o* supports the iterator protocol. + Return true if the object *o* supports the iterator protocol. This + function always succeeds. .. c:function:: PyObject* PyIter_Next(PyObject *o) diff --git a/Doc/c-api/iterator.rst b/Doc/c-api/iterator.rst index 4d91e4a224fe82..3fcf099134d4dd 100644 --- a/Doc/c-api/iterator.rst +++ b/Doc/c-api/iterator.rst @@ -21,7 +21,8 @@ sentinel value is returned. .. c:function:: int PySeqIter_Check(op) - Return true if the type of *op* is :c:data:`PySeqIter_Type`. + Return true if the type of *op* is :c:data:`PySeqIter_Type`. This function + always succeeds. .. c:function:: PyObject* PySeqIter_New(PyObject *seq) @@ -39,7 +40,8 @@ sentinel value is returned. .. c:function:: int PyCallIter_Check(op) - Return true if the type of *op* is :c:data:`PyCallIter_Type`. + Return true if the type of *op* is :c:data:`PyCallIter_Type`. This + function always succeeds. .. c:function:: PyObject* PyCallIter_New(PyObject *callable, PyObject *sentinel) diff --git a/Doc/c-api/list.rst b/Doc/c-api/list.rst index 0bc0785f200d4c..f338e2ae066895 100644 --- a/Doc/c-api/list.rst +++ b/Doc/c-api/list.rst @@ -22,13 +22,13 @@ List Objects .. c:function:: int PyList_Check(PyObject *p) Return true if *p* is a list object or an instance of a subtype of the list - type. + type. This function always succeeds. .. c:function:: int PyList_CheckExact(PyObject *p) Return true if *p* is a list object, but not an instance of a subtype of - the list type. + the list type. This function always succeeds. .. c:function:: PyObject* PyList_New(Py_ssize_t len) diff --git a/Doc/c-api/long.rst b/Doc/c-api/long.rst index 22e59ce1e5357f..60e1791df9a451 100644 --- a/Doc/c-api/long.rst +++ b/Doc/c-api/long.rst @@ -27,13 +27,13 @@ distinguished from a number. Use :c:func:`PyErr_Occurred` to disambiguate. .. c:function:: int PyLong_Check(PyObject *p) Return true if its argument is a :c:type:`PyLongObject` or a subtype of - :c:type:`PyLongObject`. + :c:type:`PyLongObject`. This function always succeeds. .. c:function:: int PyLong_CheckExact(PyObject *p) Return true if its argument is a :c:type:`PyLongObject`, but not a subtype of - :c:type:`PyLongObject`. + :c:type:`PyLongObject`. This function always succeeds. .. c:function:: PyObject* PyLong_FromLong(long v) diff --git a/Doc/c-api/memoryview.rst b/Doc/c-api/memoryview.rst index de429e5c11dc76..24f8c935302e8e 100644 --- a/Doc/c-api/memoryview.rst +++ b/Doc/c-api/memoryview.rst @@ -45,7 +45,8 @@ any other object. .. c:function:: int PyMemoryView_Check(PyObject *obj) Return true if the object *obj* is a memoryview object. It is not - currently allowed to create subclasses of :class:`memoryview`. + currently allowed to create subclasses of :class:`memoryview`. This + function always succeeds. .. c:function:: Py_buffer *PyMemoryView_GET_BUFFER(PyObject *mview) diff --git a/Doc/c-api/method.rst b/Doc/c-api/method.rst index 0a5341cbbdf152..23852251dfe020 100644 --- a/Doc/c-api/method.rst +++ b/Doc/c-api/method.rst @@ -22,6 +22,7 @@ to bind a :c:data:`PyCFunction` to a class object. It replaces the former call Return true if *o* is an instance method object (has type :c:data:`PyInstanceMethod_Type`). The parameter must not be ``NULL``. + This function always succeeds. .. c:function:: PyObject* PyInstanceMethod_New(PyObject *func) @@ -64,7 +65,7 @@ no longer available. .. c:function:: int PyMethod_Check(PyObject *o) Return true if *o* is a method object (has type :c:data:`PyMethod_Type`). The - parameter must not be ``NULL``. + parameter must not be ``NULL``. This function always succeeds. .. c:function:: PyObject* PyMethod_New(PyObject *func, PyObject *self) diff --git a/Doc/c-api/module.rst b/Doc/c-api/module.rst index 6e9474bfa40eba..90766dca78bfa7 100644 --- a/Doc/c-api/module.rst +++ b/Doc/c-api/module.rst @@ -19,12 +19,13 @@ Module Objects .. c:function:: int PyModule_Check(PyObject *p) Return true if *p* is a module object, or a subtype of a module object. + This function always succeeds. .. c:function:: int PyModule_CheckExact(PyObject *p) Return true if *p* is a module object, but not a subtype of - :c:data:`PyModule_Type`. + :c:data:`PyModule_Type`. This function always succeeds. .. c:function:: PyObject* PyModule_NewObject(PyObject *name) diff --git a/Doc/c-api/set.rst b/Doc/c-api/set.rst index 879f394d966cd0..84f34e7dae80be 100644 --- a/Doc/c-api/set.rst +++ b/Doc/c-api/set.rst @@ -53,28 +53,29 @@ the constructor functions work with any iterable Python object. .. c:function:: int PySet_Check(PyObject *p) Return true if *p* is a :class:`set` object or an instance of a subtype. + This function always succeeds. .. c:function:: int PyFrozenSet_Check(PyObject *p) Return true if *p* is a :class:`frozenset` object or an instance of a - subtype. + subtype. This function always succeeds. .. c:function:: int PyAnySet_Check(PyObject *p) Return true if *p* is a :class:`set` object, a :class:`frozenset` object, or an - instance of a subtype. + instance of a subtype. This function always succeeds. .. c:function:: int PyAnySet_CheckExact(PyObject *p) Return true if *p* is a :class:`set` object or a :class:`frozenset` object but - not an instance of a subtype. + not an instance of a subtype. This function always succeeds. .. c:function:: int PyFrozenSet_CheckExact(PyObject *p) Return true if *p* is a :class:`frozenset` object but not an instance of a - subtype. + subtype. This function always succeeds. .. c:function:: PyObject* PySet_New(PyObject *iterable) diff --git a/Doc/c-api/slice.rst b/Doc/c-api/slice.rst index 48a58c6c6f7e36..8271d9acfb645e 100644 --- a/Doc/c-api/slice.rst +++ b/Doc/c-api/slice.rst @@ -14,7 +14,8 @@ Slice Objects .. c:function:: int PySlice_Check(PyObject *ob) - Return true if *ob* is a slice object; *ob* must not be ``NULL``. + Return true if *ob* is a slice object; *ob* must not be ``NULL``. This + function always succeeds. .. c:function:: PyObject* PySlice_New(PyObject *start, PyObject *stop, PyObject *step) diff --git a/Doc/c-api/tuple.rst b/Doc/c-api/tuple.rst index bf751e44acde09..1dbf7dbb67ccd4 100644 --- a/Doc/c-api/tuple.rst +++ b/Doc/c-api/tuple.rst @@ -21,14 +21,14 @@ Tuple Objects .. c:function:: int PyTuple_Check(PyObject *p) - Return true if *p* is a tuple object or an instance of a subtype of the tuple - type. + Return true if *p* is a tuple object or an instance of a subtype of the + tuple type. This function always succeeds. .. c:function:: int PyTuple_CheckExact(PyObject *p) Return true if *p* is a tuple object, but not an instance of a subtype of the - tuple type. + tuple type. This function always succeeds. .. c:function:: PyObject* PyTuple_New(Py_ssize_t len) diff --git a/Doc/c-api/type.rst b/Doc/c-api/type.rst index 822360e06170d9..ee76f52289387f 100644 --- a/Doc/c-api/type.rst +++ b/Doc/c-api/type.rst @@ -23,12 +23,14 @@ Type Objects Return non-zero if the object *o* is a type object, including instances of types derived from the standard type object. Return 0 in all other cases. + This function always succeeds. .. c:function:: int PyType_CheckExact(PyObject *o) - Return non-zero if the object *o* is a type object, but not a subtype of the - standard type object. Return 0 in all other cases. + Return non-zero if the object *o* is a type object, but not a subtype of + the standard type object. Return 0 in all other cases. This function + always succeeds. .. c:function:: unsigned int PyType_ClearCache() diff --git a/Doc/c-api/unicode.rst b/Doc/c-api/unicode.rst index 8a312ae90ed641..62295b4c52934d 100644 --- a/Doc/c-api/unicode.rst +++ b/Doc/c-api/unicode.rst @@ -91,13 +91,13 @@ access internal read-only data of Unicode objects: .. c:function:: int PyUnicode_Check(PyObject *o) Return true if the object *o* is a Unicode object or an instance of a Unicode - subtype. + subtype. This function always succeeds. .. c:function:: int PyUnicode_CheckExact(PyObject *o) Return true if the object *o* is a Unicode object, but not an instance of a - subtype. + subtype. This function always succeeds. .. c:function:: int PyUnicode_READY(PyObject *o) diff --git a/Doc/c-api/weakref.rst b/Doc/c-api/weakref.rst index e3a9bda54d671a..67698de77fef1d 100644 --- a/Doc/c-api/weakref.rst +++ b/Doc/c-api/weakref.rst @@ -13,17 +13,18 @@ as much as it can. .. c:function:: int PyWeakref_Check(ob) - Return true if *ob* is either a reference or proxy object. + Return true if *ob* is either a reference or proxy object. This function + always succeeds. .. c:function:: int PyWeakref_CheckRef(ob) - Return true if *ob* is a reference object. + Return true if *ob* is a reference object. This function always succeeds. .. c:function:: int PyWeakref_CheckProxy(ob) - Return true if *ob* is a proxy object. + Return true if *ob* is a proxy object. This function always succeeds. .. c:function:: PyObject* PyWeakref_NewRef(PyObject *ob, PyObject *callback) From 49c150f1f16398a4e77e051244f27adc5ac7b47b Mon Sep 17 00:00:00 2001 From: Vladimir Date: Wed, 6 Jan 2021 12:57:24 -0800 Subject: [PATCH 0886/1314] bpo-38413: Remove outdated section about multithreading in sqlite3 (GH-23159) (cherry picked from commit f9949f82e17c88609adb53eff3a7d5cd63a645bd) --- Doc/library/sqlite3.rst | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/Doc/library/sqlite3.rst b/Doc/library/sqlite3.rst index fc9ad2e113e112..7dc2cc48c47538 100644 --- a/Doc/library/sqlite3.rst +++ b/Doc/library/sqlite3.rst @@ -1093,19 +1093,6 @@ committed: .. literalinclude:: ../includes/sqlite3/ctx_manager.py -Common issues -------------- - -Multithreading -^^^^^^^^^^^^^^ - -Older SQLite versions had issues with sharing connections between threads. -That's why the Python module disallows sharing connections and cursors between -threads. If you still try to do so, you will get an exception at runtime. - -The only exception is calling the :meth:`~Connection.interrupt` method, which -only makes sense to call from a different thread. - .. rubric:: Footnotes .. [#f1] The sqlite3 module is not built with loadable extension support by From 8c3914aef47e6e5a31b48a0b1f165ec3f4dc4c98 Mon Sep 17 00:00:00 2001 From: Yair Frid Date: Thu, 7 Jan 2021 20:06:13 +0200 Subject: [PATCH 0887/1314] [3.9] bpo-42811: Update importlib.utils.resolve_name() docs to use __spec__.parent (GH-24100) (GH-24149) This is a backport of https://github.com/python/cpython/pull/24100 Automerge-Triggered-By: GH:brettcannon --- Doc/library/importlib.rst | 2 +- .../next/Documentation/2021-01-07-12-08-59.bpo-42811.ePF7EC.rst | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Documentation/2021-01-07-12-08-59.bpo-42811.ePF7EC.rst diff --git a/Doc/library/importlib.rst b/Doc/library/importlib.rst index 305bb54d5271d5..cb2a5686a95a50 100644 --- a/Doc/library/importlib.rst +++ b/Doc/library/importlib.rst @@ -1473,7 +1473,7 @@ an :term:`importer`. If **name** has no leading dots, then **name** is simply returned. This allows for usage such as - ``importlib.util.resolve_name('sys', __package__)`` without doing a + ``importlib.util.resolve_name('sys', __spec__.parent)`` without doing a check to see if the **package** argument is needed. :exc:`ImportError` is raised if **name** is a relative module name but diff --git a/Misc/NEWS.d/next/Documentation/2021-01-07-12-08-59.bpo-42811.ePF7EC.rst b/Misc/NEWS.d/next/Documentation/2021-01-07-12-08-59.bpo-42811.ePF7EC.rst new file mode 100644 index 00000000000000..179c0655c70680 --- /dev/null +++ b/Misc/NEWS.d/next/Documentation/2021-01-07-12-08-59.bpo-42811.ePF7EC.rst @@ -0,0 +1,2 @@ +Updated importlib.utils.resolve_name() doc to use __spec__.parent instead of +__package__. (Thanks Yair Frid.) From 9ab4dd452287169f08a8cf4d4c68c2139f8de714 Mon Sep 17 00:00:00 2001 From: Ethan Furman Date: Thu, 7 Jan 2021 13:55:59 -0800 Subject: [PATCH 0888/1314] [3.9] bpo-42851: [Enum] remove brittle __init_subclass__ support (GH-24154) (GH-24155) Solution to support calls to `__init_subclass__` with members defined is too brittle and breaks with certain mixins.. (cherry picked from commit a581a868d97f649aedf868a1d27865a10925c73a) --- Lib/enum.py | 31 +------------ Lib/test/test_enum.py | 46 ------------------- .../2021-01-07-11-44-22.bpo-42851.uyQFyd.rst | 1 + 3 files changed, 2 insertions(+), 76 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2021-01-07-11-44-22.bpo-42851.uyQFyd.rst diff --git a/Lib/enum.py b/Lib/enum.py index 1c22380f03b38c..1fddb1c75e8be4 100644 --- a/Lib/enum.py +++ b/Lib/enum.py @@ -9,14 +9,6 @@ ] -class _NoInitSubclass: - """ - temporary base class to suppress calling __init_subclass__ - """ - @classmethod - def __init_subclass__(cls, **kwds): - pass - def _is_descriptor(obj): """ Returns True if obj is a descriptor, False otherwise. @@ -219,22 +211,7 @@ def __new__(metacls, cls, bases, classdict, **kwds): if '__doc__' not in classdict: classdict['__doc__'] = 'An enumeration.' - # postpone calling __init_subclass__ - if '__init_subclass__' in classdict and classdict['__init_subclass__'] is None: - raise TypeError('%s.__init_subclass__ cannot be None') - # remove current __init_subclass__ so previous one can be found with getattr - new_init_subclass = classdict.pop('__init_subclass__', None) - # create our new Enum type - if bases: - bases = (_NoInitSubclass, ) + bases - enum_class = super().__new__(metacls, cls, bases, classdict, **kwds) - enum_class.__bases__ = enum_class.__bases__[1:] #or (object, ) - else: - enum_class = super().__new__(metacls, cls, bases, classdict, **kwds) - old_init_subclass = getattr(enum_class, '__init_subclass__', None) - # and restore the new one (if there was one) - if new_init_subclass is not None: - enum_class.__init_subclass__ = classmethod(new_init_subclass) + enum_class = super().__new__(metacls, cls, bases, classdict, **kwds) enum_class._member_names_ = [] # names in definition order enum_class._member_map_ = {} # name->value map enum_class._member_type_ = member_type @@ -346,9 +323,6 @@ def __new__(metacls, cls, bases, classdict, **kwds): if _order_ != enum_class._member_names_: raise TypeError('member order does not match _order_') - # finally, call parents' __init_subclass__ - if Enum is not None and old_init_subclass is not None: - old_init_subclass(**kwds) return enum_class def __bool__(self): @@ -726,9 +700,6 @@ def _generate_next_value_(name, start, count, last_values): else: return start - def __init_subclass__(cls, **kwds): - super().__init_subclass__(**kwds) - @classmethod def _missing_(cls, value): return None diff --git a/Lib/test/test_enum.py b/Lib/test/test_enum.py index f6db73167dc959..4e229863255211 100644 --- a/Lib/test/test_enum.py +++ b/Lib/test/test_enum.py @@ -2065,52 +2065,6 @@ class Private(Enum): except ValueError: pass - def test_init_subclass_calling(self): - class MyEnum(Enum): - def __init_subclass__(cls, **kwds): - super(MyEnum, cls).__init_subclass__(**kwds) - self.assertFalse(cls.__dict__.get('_test', False)) - cls._test1 = 'MyEnum' - # - class TheirEnum(MyEnum): - def __init_subclass__(cls, **kwds): - super().__init_subclass__(**kwds) - cls._test2 = 'TheirEnum' - class WhoseEnum(TheirEnum): - def __init_subclass__(cls, **kwds): - pass - class NoEnum(WhoseEnum): - ONE = 1 - self.assertEqual(TheirEnum.__dict__['_test1'], 'MyEnum') - self.assertEqual(WhoseEnum.__dict__['_test1'], 'MyEnum') - self.assertEqual(WhoseEnum.__dict__['_test2'], 'TheirEnum') - self.assertFalse(NoEnum.__dict__.get('_test1', False)) - self.assertFalse(NoEnum.__dict__.get('_test2', False)) - # - class OurEnum(MyEnum): - def __init_subclass__(cls, **kwds): - cls._test2 = 'OurEnum' - class WhereEnum(OurEnum): - def __init_subclass__(cls, **kwds): - pass - class NeverEnum(WhereEnum): - ONE = 'one' - self.assertEqual(OurEnum.__dict__['_test1'], 'MyEnum') - self.assertFalse(WhereEnum.__dict__.get('_test1', False)) - self.assertEqual(WhereEnum.__dict__['_test2'], 'OurEnum') - self.assertFalse(NeverEnum.__dict__.get('_test1', False)) - self.assertFalse(NeverEnum.__dict__.get('_test2', False)) - - def test_init_subclass_parameter(self): - class multiEnum(Enum): - def __init_subclass__(cls, multi): - for member in cls: - member._as_parameter_ = multi * member.value - class E(multiEnum, multi=3): - A = 1 - B = 2 - self.assertEqual(E.A._as_parameter_, 3) - self.assertEqual(E.B._as_parameter_, 6) class TestOrder(unittest.TestCase): diff --git a/Misc/NEWS.d/next/Library/2021-01-07-11-44-22.bpo-42851.uyQFyd.rst b/Misc/NEWS.d/next/Library/2021-01-07-11-44-22.bpo-42851.uyQFyd.rst new file mode 100644 index 00000000000000..927283521e80e3 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2021-01-07-11-44-22.bpo-42851.uyQFyd.rst @@ -0,0 +1 @@ +remove __init_subclass__ support for Enum members From 799f8489d418b7f9207d333eac38214931bd7dcc Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 9 Jan 2021 23:30:43 -0800 Subject: [PATCH 0889/1314] bpo-33065: Fix problem debugging user classes with __repr__ method (GH-24183) If __repr__ uses instance attributes, as normal, and one steps through the __init__ method, debugger may try to get repr before the instance attributes exist. reprlib.repr handles the error. (cherry picked from commit 81f87bbf9f65702062021a78abd9b8f82c98a414) Co-authored-by: Terry Jan Reedy --- Lib/idlelib/NEWS.txt | 2 ++ Lib/idlelib/debugger_r.py | 6 +++--- Lib/idlelib/idle_test/test_debugger_r.py | 14 ++++++++++++++ .../IDLE/2021-01-10-01-25-43.bpo-33065.zmyHYJ.rst | 1 + 4 files changed, 20 insertions(+), 3 deletions(-) create mode 100644 Misc/NEWS.d/next/IDLE/2021-01-10-01-25-43.bpo-33065.zmyHYJ.rst diff --git a/Lib/idlelib/NEWS.txt b/Lib/idlelib/NEWS.txt index c466fe9cc77766..0033e66f9b8a26 100644 --- a/Lib/idlelib/NEWS.txt +++ b/Lib/idlelib/NEWS.txt @@ -3,6 +3,8 @@ Released on 2020-12-07? ====================================== +bpo-33065: Fix problem debugging user classes with __repr__ method. + bpo-32631: Finish zzdummy example extension module: make menu entries work; add docstrings and tests with 100% coverage. diff --git a/Lib/idlelib/debugger_r.py b/Lib/idlelib/debugger_r.py index 9dcfc56414c050..26204438858d8a 100644 --- a/Lib/idlelib/debugger_r.py +++ b/Lib/idlelib/debugger_r.py @@ -19,7 +19,7 @@ barrier, in particular frame and traceback objects. """ - +import reprlib import types from idlelib import debugger @@ -170,7 +170,7 @@ def dict_keys_list(self, did): def dict_item(self, did, key): dict = dicttable[did] value = dict[key] - value = repr(value) ### can't pickle module 'builtins' + value = reprlib.repr(value) ### can't pickle module 'builtins' return value #----------end class IdbAdapter---------- @@ -390,4 +390,4 @@ def restart_subprocess_debugger(rpcclt): if __name__ == "__main__": from unittest import main - main('idlelib.idle_test.test_debugger', verbosity=2, exit=False) + main('idlelib.idle_test.test_debugger_r', verbosity=2, exit=False) diff --git a/Lib/idlelib/idle_test/test_debugger_r.py b/Lib/idlelib/idle_test/test_debugger_r.py index 199f63447ce6ca..638ebd36a7405d 100644 --- a/Lib/idlelib/idle_test/test_debugger_r.py +++ b/Lib/idlelib/idle_test/test_debugger_r.py @@ -25,5 +25,19 @@ def test_init(self): # Classes GUIProxy, IdbAdapter, FrameProxy, CodeProxy, DictProxy, # GUIAdapter, IdbProxy plus 7 module functions. +class IdbAdapterTest(unittest.TestCase): + + def test_dict_item_noattr(self): # Issue 33065. + + class BinData: + def __repr__(self): + return self.length + + debugger_r.dicttable[0] = {'BinData': BinData()} + idb = debugger_r.IdbAdapter(None) + self.assertTrue(idb.dict_item(0, 'BinData')) + debugger_r.dicttable.clear() + + if __name__ == '__main__': unittest.main(verbosity=2) diff --git a/Misc/NEWS.d/next/IDLE/2021-01-10-01-25-43.bpo-33065.zmyHYJ.rst b/Misc/NEWS.d/next/IDLE/2021-01-10-01-25-43.bpo-33065.zmyHYJ.rst new file mode 100644 index 00000000000000..87948f3cd1baa1 --- /dev/null +++ b/Misc/NEWS.d/next/IDLE/2021-01-10-01-25-43.bpo-33065.zmyHYJ.rst @@ -0,0 +1 @@ +Fix problem debugging user classes with __repr__ method. From ddc0fa3a1c1da32359f2019d14cbcfc8eb73498b Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 14 Jan 2021 08:17:44 -0800 Subject: [PATCH 0890/1314] Docs: Remove stray semicolon in init.rst (GH-23974) Removed stray semicolon which was causing the docs to render weirdly (it's the function right under the one [here](https://docs.python.org/3/c-api/init.htmlGH-c._PyInterpreterState_GetEvalFrameFunc)). (cherry picked from commit 971235827754eee6c0d9f7d39b52fecdfd4cb7b4) Co-authored-by: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> --- Doc/c-api/init.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/c-api/init.rst b/Doc/c-api/init.rst index 7f06648bcb4572..eb0bd14587145b 100644 --- a/Doc/c-api/init.rst +++ b/Doc/c-api/init.rst @@ -1155,7 +1155,7 @@ All of the following functions must be called after :c:func:`Py_Initialize`. .. versionadded:: 3.9 -.. c:function:: void _PyInterpreterState_SetEvalFrameFunc(PyInterpreterState *interp, _PyFrameEvalFunction eval_frame); +.. c:function:: void _PyInterpreterState_SetEvalFrameFunc(PyInterpreterState *interp, _PyFrameEvalFunction eval_frame) Set the frame evaluation function. From 17c1f0c8cb96637c36548edf6e4570ac7564004b Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 15 Jan 2021 10:21:52 -0800 Subject: [PATCH 0891/1314] bpo-42931: randbytes missing from random.__all__ (GH-24219) (GH-24225) --- Lib/random.py | 1 + .../NEWS.d/next/Library/2021-01-15-00-23-50.bpo-42931.QD6U2B.rst | 1 + 2 files changed, 2 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2021-01-15-00-23-50.bpo-42931.QD6U2B.rst diff --git a/Lib/random.py b/Lib/random.py index a6454f520df0a3..190df6a8c3a56c 100644 --- a/Lib/random.py +++ b/Lib/random.py @@ -77,6 +77,7 @@ "lognormvariate", "normalvariate", "paretovariate", + "randbytes", "randint", "random", "randrange", diff --git a/Misc/NEWS.d/next/Library/2021-01-15-00-23-50.bpo-42931.QD6U2B.rst b/Misc/NEWS.d/next/Library/2021-01-15-00-23-50.bpo-42931.QD6U2B.rst new file mode 100644 index 00000000000000..01f8094944f70c --- /dev/null +++ b/Misc/NEWS.d/next/Library/2021-01-15-00-23-50.bpo-42931.QD6U2B.rst @@ -0,0 +1 @@ +Add :func:`randbytes` to ``random.__all__``. From 799722cb0ddb90752cde7798cab543f30623ebf2 Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Sat, 16 Jan 2021 14:45:30 -0500 Subject: [PATCH 0892/1314] [3.9] bpo-42163, bpo-42189, bpo-42659: Support uname_tuple._replace (for all but processor) (GH-23010) (#24232) * Add test capturing missed expectation with uname_result._replace. * bpo-42163: Override uname_result._make to allow uname_result._replace to work (for everything but 'processor'. * Replace hard-coded length with one derived from the definition. * Add test capturing missed expectation with copy/deepcopy on namedtuple (bpo-42189). * bpo-42189: Exclude processor parameter when constructing uname_result. * In _make, rely on __new__ to strip processor. * Add blurb. * iter is not necessary here. * Rely on num_fields in __new__ * Add test for slices on uname * Add test for copy and pickle. Co-authored-by: Serhiy Storchaka * import pickle * Fix equality test after pickling. * Simply rely on __reduce__ for pickling. Co-authored-by: Serhiy Storchaka (cherry picked from commit a6fd0f414c0cb4cd5cc20eb2df3340b31c6f7743) Co-authored-by: Jason R. Coombs --- Lib/platform.py | 17 ++++++++-- Lib/test/test_platform.py | 34 +++++++++++++++++++ .../2020-10-29-09-22-56.bpo-42163.O4VcCY.rst | 1 + 3 files changed, 50 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2020-10-29-09-22-56.bpo-42163.O4VcCY.rst diff --git a/Lib/platform.py b/Lib/platform.py index e9f50ab622d316..6258827d0e41f8 100755 --- a/Lib/platform.py +++ b/Lib/platform.py @@ -782,7 +782,7 @@ class uname_result( ): """ A uname_result that's largely compatible with a - simple namedtuple except that 'platform' is + simple namedtuple except that 'processor' is resolved late and cached to avoid calling "uname" except when needed. """ @@ -797,12 +797,25 @@ def __iter__(self): (self.processor,) ) + @classmethod + def _make(cls, iterable): + # override factory to affect length check + num_fields = len(cls._fields) + result = cls.__new__(cls, *iterable) + if len(result) != num_fields + 1: + msg = f'Expected {num_fields} arguments, got {len(result)}' + raise TypeError(msg) + return result + def __getitem__(self, key): - return tuple(iter(self))[key] + return tuple(self)[key] def __len__(self): return len(tuple(iter(self))) + def __reduce__(self): + return uname_result, tuple(self)[:len(self._fields)] + _uname_cache = None diff --git a/Lib/test/test_platform.py b/Lib/test/test_platform.py index a3b06feb6552ec..9f04c79e09ba46 100644 --- a/Lib/test/test_platform.py +++ b/Lib/test/test_platform.py @@ -1,4 +1,6 @@ import os +import copy +import pickle import platform import subprocess import sys @@ -175,6 +177,38 @@ def test_uname_cast_to_tuple(self): ) self.assertEqual(tuple(res), expected) + def test_uname_replace(self): + res = platform.uname() + new = res._replace( + system='system', node='node', release='release', + version='version', machine='machine') + self.assertEqual(new.system, 'system') + self.assertEqual(new.node, 'node') + self.assertEqual(new.release, 'release') + self.assertEqual(new.version, 'version') + self.assertEqual(new.machine, 'machine') + # processor cannot be replaced + self.assertEqual(new.processor, res.processor) + + def test_uname_copy(self): + uname = platform.uname() + self.assertEqual(copy.copy(uname), uname) + self.assertEqual(copy.deepcopy(uname), uname) + + def test_uname_pickle(self): + orig = platform.uname() + for proto in range(pickle.HIGHEST_PROTOCOL + 1): + with self.subTest(protocol=proto): + pickled = pickle.dumps(orig, proto) + restored = pickle.loads(pickled) + self.assertEqual(restored, orig) + + def test_uname_slices(self): + res = platform.uname() + expected = tuple(res) + self.assertEqual(res[:], expected) + self.assertEqual(res[:5], expected[:5]) + @unittest.skipIf(sys.platform in ['win32', 'OpenVMS'], "uname -p not used") def test_uname_processor(self): """ diff --git a/Misc/NEWS.d/next/Library/2020-10-29-09-22-56.bpo-42163.O4VcCY.rst b/Misc/NEWS.d/next/Library/2020-10-29-09-22-56.bpo-42163.O4VcCY.rst new file mode 100644 index 00000000000000..0c357eb4ac1daf --- /dev/null +++ b/Misc/NEWS.d/next/Library/2020-10-29-09-22-56.bpo-42163.O4VcCY.rst @@ -0,0 +1 @@ +Restore compatibility for ``uname_result`` around deepcopy and _replace. From a90539f5723a4c34430761be8cba97daa8474abf Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 18 Jan 2021 10:36:07 -0800 Subject: [PATCH 0893/1314] bpo-42944 Fix Random.sample when counts is not None (GH-24235) (GH-24243) --- Lib/random.py | 2 +- Lib/test/test_random.py | 54 +++++++++---------- .../2021-01-18-10-41-44.bpo-42944.RrONvy.rst | 1 + 3 files changed, 29 insertions(+), 28 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2021-01-18-10-41-44.bpo-42944.RrONvy.rst diff --git a/Lib/random.py b/Lib/random.py index 190df6a8c3a56c..36e16a9063b534 100644 --- a/Lib/random.py +++ b/Lib/random.py @@ -442,7 +442,7 @@ def sample(self, population, k, *, counts=None): raise TypeError('Counts must be integers') if total <= 0: raise ValueError('Total of counts must be greater than zero') - selections = sample(range(total), k=k) + selections = self.sample(range(total), k=k) bisect = _bisect return [population[bisect(cum_counts, s)] for s in selections] randbelow = self._randbelow diff --git a/Lib/test/test_random.py b/Lib/test/test_random.py index a80e71e67e4c6c..15a68418bdd86a 100644 --- a/Lib/test/test_random.py +++ b/Lib/test/test_random.py @@ -207,33 +207,6 @@ def test_sample_with_counts(self): with self.assertRaises(ValueError): sample(['red', 'green', 'blue'], counts=[1, 2, 3, 4], k=2) # too many counts - def test_sample_counts_equivalence(self): - # Test the documented strong equivalence to a sample with repeated elements. - # We run this test on random.Random() which makes deterministic selections - # for a given seed value. - sample = random.sample - seed = random.seed - - colors = ['red', 'green', 'blue', 'orange', 'black', 'amber'] - counts = [500, 200, 20, 10, 5, 1 ] - k = 700 - seed(8675309) - s1 = sample(colors, counts=counts, k=k) - seed(8675309) - expanded = [color for (color, count) in zip(colors, counts) for i in range(count)] - self.assertEqual(len(expanded), sum(counts)) - s2 = sample(expanded, k=k) - self.assertEqual(s1, s2) - - pop = 'abcdefghi' - counts = [10, 9, 8, 7, 6, 5, 4, 3, 2] - seed(8675309) - s1 = ''.join(sample(pop, counts=counts, k=30)) - expanded = ''.join([letter for (letter, count) in zip(pop, counts) for i in range(count)]) - seed(8675309) - s2 = ''.join(sample(expanded, k=30)) - self.assertEqual(s1, s2) - def test_choices(self): choices = self.gen.choices data = ['red', 'green', 'blue', 'yellow'] @@ -888,6 +861,33 @@ def test_randbytes_getrandbits(self): self.assertEqual(self.gen.randbytes(n), gen2.getrandbits(n * 8).to_bytes(n, 'little')) + def test_sample_counts_equivalence(self): + # Test the documented strong equivalence to a sample with repeated elements. + # We run this test on random.Random() which makes deterministic selections + # for a given seed value. + sample = self.gen.sample + seed = self.gen.seed + + colors = ['red', 'green', 'blue', 'orange', 'black', 'amber'] + counts = [500, 200, 20, 10, 5, 1 ] + k = 700 + seed(8675309) + s1 = sample(colors, counts=counts, k=k) + seed(8675309) + expanded = [color for (color, count) in zip(colors, counts) for i in range(count)] + self.assertEqual(len(expanded), sum(counts)) + s2 = sample(expanded, k=k) + self.assertEqual(s1, s2) + + pop = 'abcdefghi' + counts = [10, 9, 8, 7, 6, 5, 4, 3, 2] + seed(8675309) + s1 = ''.join(sample(pop, counts=counts, k=30)) + expanded = ''.join([letter for (letter, count) in zip(pop, counts) for i in range(count)]) + seed(8675309) + s2 = ''.join(sample(expanded, k=30)) + self.assertEqual(s1, s2) + def gamma(z, sqrt2pi=(2.0*pi)**0.5): # Reflection to right half of complex plane diff --git a/Misc/NEWS.d/next/Library/2021-01-18-10-41-44.bpo-42944.RrONvy.rst b/Misc/NEWS.d/next/Library/2021-01-18-10-41-44.bpo-42944.RrONvy.rst new file mode 100644 index 00000000000000..b78d10aa255454 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2021-01-18-10-41-44.bpo-42944.RrONvy.rst @@ -0,0 +1 @@ +Fix ``random.Random.sample`` when ``counts`` argument is not ``None``. From c347cbe694743cee120457aa6626712f7799a932 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 18 Jan 2021 13:29:31 -0800 Subject: [PATCH 0894/1314] closes bpo-42938: Replace snprintf with Python unicode formatting in ctypes param reprs. (GH-24247) (cherry picked from commit 916610ef90a0d0761f08747f7b0905541f0977c7) Co-authored-by: Benjamin Peterson Co-authored-by: Benjamin Peterson --- Lib/ctypes/test/test_parameters.py | 43 ++++++++++++++++ .../2021-01-18-09-27-31.bpo-42938.4Zn4Mp.rst | 2 + Modules/_ctypes/callproc.c | 51 +++++++------------ 3 files changed, 64 insertions(+), 32 deletions(-) create mode 100644 Misc/NEWS.d/next/Security/2021-01-18-09-27-31.bpo-42938.4Zn4Mp.rst diff --git a/Lib/ctypes/test/test_parameters.py b/Lib/ctypes/test/test_parameters.py index e4c25fd880cefb..531894fdec8382 100644 --- a/Lib/ctypes/test/test_parameters.py +++ b/Lib/ctypes/test/test_parameters.py @@ -201,6 +201,49 @@ def __dict__(self): with self.assertRaises(ZeroDivisionError): WorseStruct().__setstate__({}, b'foo') + def test_parameter_repr(self): + from ctypes import ( + c_bool, + c_char, + c_wchar, + c_byte, + c_ubyte, + c_short, + c_ushort, + c_int, + c_uint, + c_long, + c_ulong, + c_longlong, + c_ulonglong, + c_float, + c_double, + c_longdouble, + c_char_p, + c_wchar_p, + c_void_p, + ) + self.assertRegex(repr(c_bool.from_param(True)), r"^$") + self.assertEqual(repr(c_char.from_param(97)), "") + self.assertRegex(repr(c_wchar.from_param('a')), r"^$") + self.assertEqual(repr(c_byte.from_param(98)), "") + self.assertEqual(repr(c_ubyte.from_param(98)), "") + self.assertEqual(repr(c_short.from_param(511)), "") + self.assertEqual(repr(c_ushort.from_param(511)), "") + self.assertRegex(repr(c_int.from_param(20000)), r"^$") + self.assertRegex(repr(c_uint.from_param(20000)), r"^$") + self.assertRegex(repr(c_long.from_param(20000)), r"^$") + self.assertRegex(repr(c_ulong.from_param(20000)), r"^$") + self.assertRegex(repr(c_longlong.from_param(20000)), r"^$") + self.assertRegex(repr(c_ulonglong.from_param(20000)), r"^$") + self.assertEqual(repr(c_float.from_param(1.5)), "") + self.assertEqual(repr(c_double.from_param(1.5)), "") + self.assertEqual(repr(c_double.from_param(1e300)), "") + self.assertRegex(repr(c_longdouble.from_param(1.5)), r"^$") + self.assertRegex(repr(c_char_p.from_param(b'hihi')), "^$") + self.assertRegex(repr(c_wchar_p.from_param('hihi')), "^$") + self.assertRegex(repr(c_void_p.from_param(0x12)), r"^$") + ################################################################ if __name__ == '__main__': diff --git a/Misc/NEWS.d/next/Security/2021-01-18-09-27-31.bpo-42938.4Zn4Mp.rst b/Misc/NEWS.d/next/Security/2021-01-18-09-27-31.bpo-42938.4Zn4Mp.rst new file mode 100644 index 00000000000000..7df65a156feabd --- /dev/null +++ b/Misc/NEWS.d/next/Security/2021-01-18-09-27-31.bpo-42938.4Zn4Mp.rst @@ -0,0 +1,2 @@ +Avoid static buffers when computing the repr of :class:`ctypes.c_double` and +:class:`ctypes.c_longdouble` values. diff --git a/Modules/_ctypes/callproc.c b/Modules/_ctypes/callproc.c index b0a36a30248f74..f2506de54498e7 100644 --- a/Modules/_ctypes/callproc.c +++ b/Modules/_ctypes/callproc.c @@ -489,58 +489,47 @@ is_literal_char(unsigned char c) static PyObject * PyCArg_repr(PyCArgObject *self) { - char buffer[256]; switch(self->tag) { case 'b': case 'B': - sprintf(buffer, "", + return PyUnicode_FromFormat("", self->tag, self->value.b); - break; case 'h': case 'H': - sprintf(buffer, "", + return PyUnicode_FromFormat("", self->tag, self->value.h); - break; case 'i': case 'I': - sprintf(buffer, "", + return PyUnicode_FromFormat("", self->tag, self->value.i); - break; case 'l': case 'L': - sprintf(buffer, "", + return PyUnicode_FromFormat("", self->tag, self->value.l); - break; case 'q': case 'Q': - sprintf(buffer, -#ifdef MS_WIN32 - "", -#else - "", -#endif + return PyUnicode_FromFormat("", self->tag, self->value.q); - break; case 'd': - sprintf(buffer, "", - self->tag, self->value.d); - break; - case 'f': - sprintf(buffer, "", - self->tag, self->value.f); - break; - + case 'f': { + PyObject *f = PyFloat_FromDouble((self->tag == 'f') ? self->value.f : self->value.d); + if (f == NULL) { + return NULL; + } + PyObject *result = PyUnicode_FromFormat("", self->tag, f); + Py_DECREF(f); + return result; + } case 'c': if (is_literal_char((unsigned char)self->value.c)) { - sprintf(buffer, "", + return PyUnicode_FromFormat("", self->tag, self->value.c); } else { - sprintf(buffer, "", + return PyUnicode_FromFormat("", self->tag, (unsigned char)self->value.c); } - break; /* Hm, are these 'z' and 'Z' codes useful at all? Shouldn't they be replaced by the functionality of c_string @@ -549,22 +538,20 @@ PyCArg_repr(PyCArgObject *self) case 'z': case 'Z': case 'P': - sprintf(buffer, "", + return PyUnicode_FromFormat("", self->tag, self->value.p); break; default: if (is_literal_char((unsigned char)self->tag)) { - sprintf(buffer, "", + return PyUnicode_FromFormat("", (unsigned char)self->tag, (void *)self); } else { - sprintf(buffer, "", + return PyUnicode_FromFormat("", (unsigned char)self->tag, (void *)self); } - break; } - return PyUnicode_FromString(buffer); } static PyMemberDef PyCArgType_members[] = { From 50938b63fbb0d4bed24dceccf188b8d0fe58463c Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 20 Jan 2021 01:03:28 -0800 Subject: [PATCH 0895/1314] bpo-41995: Handle allocation failure in _tracemalloc and _zoneinfo (GH-22635) (cherry picked from commit f1ff800db1f9fa5ff8f2fa2863796a46bfa9ee46) Co-authored-by: Yunlongs --- Modules/_zoneinfo.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/Modules/_zoneinfo.c b/Modules/_zoneinfo.c index fafb6b01df3712..d87a20100a2218 100644 --- a/Modules/_zoneinfo.c +++ b/Modules/_zoneinfo.c @@ -909,7 +909,13 @@ load_data(PyZoneInfo_ZoneInfo *self, PyObject *file_obj) // Load the transition indices and list self->trans_list_utc = PyMem_Malloc(self->num_transitions * sizeof(int64_t)); + if (self->trans_list_utc == NULL) { + goto error; + } trans_idx = PyMem_Malloc(self->num_transitions * sizeof(Py_ssize_t)); + if (trans_idx == NULL) { + goto error; + } for (size_t i = 0; i < self->num_transitions; ++i) { PyObject *num = PyTuple_GetItem(trans_utc, i); @@ -991,6 +997,9 @@ load_data(PyZoneInfo_ZoneInfo *self, PyObject *file_obj) // Build _ttinfo objects from utcoff, dstoff and abbr self->_ttinfos = PyMem_Malloc(self->num_ttinfos * sizeof(_ttinfo)); + if (self->_ttinfos == NULL) { + goto error; + } for (size_t i = 0; i < self->num_ttinfos; ++i) { PyObject *tzname = PyTuple_GetItem(abbr, i); if (tzname == NULL) { @@ -1006,6 +1015,9 @@ load_data(PyZoneInfo_ZoneInfo *self, PyObject *file_obj) // Build our mapping from transition to the ttinfo that applies self->trans_ttinfos = PyMem_Calloc(self->num_transitions, sizeof(_ttinfo *)); + if (self->trans_ttinfos == NULL) { + goto error; + } for (size_t i = 0; i < self->num_transitions; ++i) { size_t ttinfo_idx = trans_idx[i]; assert(ttinfo_idx < self->num_ttinfos); From 0654c4c4cc54a325e878154f8b117159d0105cf7 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 20 Jan 2021 01:19:08 -0800 Subject: [PATCH 0896/1314] bpo-42005: profile and cProfile catch BrokenPipeError (GH-22643) (cherry picked from commit 3554fa4abecfb77ac5fcaa5ce8310eeca5683960) Co-authored-by: Zhiming Wang --- Lib/cProfile.py | 7 ++++++- Lib/profile.py | 7 ++++++- .../next/Library/2020-10-11-13-48-03.bpo-42005.Jq6Az-.rst | 2 ++ 3 files changed, 14 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2020-10-11-13-48-03.bpo-42005.Jq6Az-.rst diff --git a/Lib/cProfile.py b/Lib/cProfile.py index 59b4699feb5062..22a7d0aade855f 100755 --- a/Lib/cProfile.py +++ b/Lib/cProfile.py @@ -175,7 +175,12 @@ def main(): '__package__': None, '__cached__': None, } - runctx(code, globs, None, options.outfile, options.sort) + try: + runctx(code, globs, None, options.outfile, options.sort) + except BrokenPipeError as exc: + # Prevent "Exception ignored" during interpreter shutdown. + sys.stdout = None + sys.exit(exc.errno) else: parser.print_usage() return parser diff --git a/Lib/profile.py b/Lib/profile.py index 5cb017ed830099..d8599fb4eebd66 100755 --- a/Lib/profile.py +++ b/Lib/profile.py @@ -595,7 +595,12 @@ def main(): '__package__': None, '__cached__': None, } - runctx(code, globs, None, options.outfile, options.sort) + try: + runctx(code, globs, None, options.outfile, options.sort) + except BrokenPipeError as exc: + # Prevent "Exception ignored" during interpreter shutdown. + sys.stdout = None + sys.exit(exc.errno) else: parser.print_usage() return parser diff --git a/Misc/NEWS.d/next/Library/2020-10-11-13-48-03.bpo-42005.Jq6Az-.rst b/Misc/NEWS.d/next/Library/2020-10-11-13-48-03.bpo-42005.Jq6Az-.rst new file mode 100644 index 00000000000000..be4ed7f55ffded --- /dev/null +++ b/Misc/NEWS.d/next/Library/2020-10-11-13-48-03.bpo-42005.Jq6Az-.rst @@ -0,0 +1,2 @@ +Fix CLI of :mod:`cProfile` and :mod:`profile` to catch +:exc:`BrokenPipeError`. From 6893523bed4ad701838715380659c245eec71d48 Mon Sep 17 00:00:00 2001 From: cptpcrd <31829097+cptpcrd@users.noreply.github.com> Date: Thu, 21 Jan 2021 05:46:35 -0500 Subject: [PATCH 0897/1314] bpo-42780: Fix set_inheritable() for O_PATH file descriptors on Linux (GH-24172) (GH-24278) (cherry picked from commit 7dc71c425cf6aa6a4070a418dce5d95ca435c79f) --- Lib/test/test_os.py | 27 +++++++++++++++++++ .../2021-01-08-15-49-20.bpo-42780.rtqi6B.rst | 1 + Python/fileutils.c | 7 +++++ 3 files changed, 35 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2021-01-08-15-49-20.bpo-42780.rtqi6B.rst diff --git a/Lib/test/test_os.py b/Lib/test/test_os.py index bf1cb5f5112557..35933e9c8c3a97 100644 --- a/Lib/test/test_os.py +++ b/Lib/test/test_os.py @@ -3659,6 +3659,33 @@ def test_set_inheritable_cloexec(self): self.assertEqual(fcntl.fcntl(fd, fcntl.F_GETFD) & fcntl.FD_CLOEXEC, 0) + @unittest.skipUnless(hasattr(os, 'O_PATH'), "need os.O_PATH") + def test_get_set_inheritable_o_path(self): + fd = os.open(__file__, os.O_PATH) + self.addCleanup(os.close, fd) + self.assertEqual(os.get_inheritable(fd), False) + + os.set_inheritable(fd, True) + self.assertEqual(os.get_inheritable(fd), True) + + os.set_inheritable(fd, False) + self.assertEqual(os.get_inheritable(fd), False) + + def test_get_set_inheritable_badf(self): + fd = support.make_bad_fd() + + with self.assertRaises(OSError) as ctx: + os.get_inheritable(fd) + self.assertEqual(ctx.exception.errno, errno.EBADF) + + with self.assertRaises(OSError) as ctx: + os.set_inheritable(fd, True) + self.assertEqual(ctx.exception.errno, errno.EBADF) + + with self.assertRaises(OSError) as ctx: + os.set_inheritable(fd, False) + self.assertEqual(ctx.exception.errno, errno.EBADF) + def test_open(self): fd = os.open(__file__, os.O_RDONLY) self.addCleanup(os.close, fd) diff --git a/Misc/NEWS.d/next/Library/2021-01-08-15-49-20.bpo-42780.rtqi6B.rst b/Misc/NEWS.d/next/Library/2021-01-08-15-49-20.bpo-42780.rtqi6B.rst new file mode 100644 index 00000000000000..a491690507129e --- /dev/null +++ b/Misc/NEWS.d/next/Library/2021-01-08-15-49-20.bpo-42780.rtqi6B.rst @@ -0,0 +1 @@ +Fix os.set_inheritable() for O_PATH file descriptors on Linux. diff --git a/Python/fileutils.c b/Python/fileutils.c index 397ac34e8073df..ddc090988f1589 100644 --- a/Python/fileutils.c +++ b/Python/fileutils.c @@ -1165,6 +1165,13 @@ set_inheritable(int fd, int inheritable, int raise, int *atomic_flag_works) return 0; } +#ifdef __linux__ + if (errno == EBADF) { + // On Linux, ioctl(FIOCLEX) will fail with EBADF for O_PATH file descriptors + // Fall through to the fcntl() path + } + else +#endif if (errno != ENOTTY && errno != EACCES) { if (raise) PyErr_SetFromErrno(PyExc_OSError); From 98e1f5c778b9719f6338a3247da95402192bad18 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 21 Jan 2021 22:09:50 -0800 Subject: [PATCH 0898/1314] bpo-40304: Correct type(name, bases, dict) doc (GH-19553) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Éric Araujo Co-authored-by: Terry Jan Reedy Co-authored-by: Tal Einat <532281+taleinat@users.noreply.github.com> (cherry picked from commit 644d52818a6391535e5838fd57d58ffcb1163056) Co-authored-by: Ð‘Ð¾Ñ€Ð¸Ñ Ð’ÐµÑ€Ñ…Ð¾Ð²Ñкий --- Doc/library/functions.rst | 17 +++++++++-------- .../2021-01-20-23-03-49.bpo-40304.-LK7Ps.rst | 2 ++ 2 files changed, 11 insertions(+), 8 deletions(-) create mode 100644 Misc/NEWS.d/next/Documentation/2021-01-20-23-03-49.bpo-40304.-LK7Ps.rst diff --git a/Doc/library/functions.rst b/Doc/library/functions.rst index 9c12b6c48d8ff0..9d13967c04fffa 100644 --- a/Doc/library/functions.rst +++ b/Doc/library/functions.rst @@ -1687,18 +1687,19 @@ are always available. They are listed here in alphabetical order. With three arguments, return a new type object. This is essentially a - dynamic form of the :keyword:`class` statement. The *name* string is the - class name and becomes the :attr:`~definition.__name__` attribute; the *bases* - tuple itemizes the base classes and becomes the :attr:`~class.__bases__` - attribute; and the *dict* dictionary is the namespace containing definitions - for class body and is copied to a standard dictionary to become the - :attr:`~object.__dict__` attribute. For example, the following two - statements create identical :class:`type` objects: + dynamic form of the :keyword:`class` statement. The *name* string is + the class name and becomes the :attr:`~definition.__name__` attribute. + The *bases* tuple contains the base classes and becomes the + :attr:`~class.__bases__` attribute; if empty, :class:`object`, the + ultimate base of all classes, is added. The *dict* dictionary contains + attribute and method definitions for the class body; it may be copied + or wrapped before becoming the :attr:`~object.__dict__` attribute. + The following two statements create identical :class:`type` objects: >>> class X: ... a = 1 ... - >>> X = type('X', (object,), dict(a=1)) + >>> X = type('X', (), dict(a=1)) See also :ref:`bltin-type-objects`. diff --git a/Misc/NEWS.d/next/Documentation/2021-01-20-23-03-49.bpo-40304.-LK7Ps.rst b/Misc/NEWS.d/next/Documentation/2021-01-20-23-03-49.bpo-40304.-LK7Ps.rst new file mode 100644 index 00000000000000..3f2f14c2d7b893 --- /dev/null +++ b/Misc/NEWS.d/next/Documentation/2021-01-20-23-03-49.bpo-40304.-LK7Ps.rst @@ -0,0 +1,2 @@ +Fix doc for type(name, bases, dict). Patch by Boris Verkhovskiy and +Éric Araujo. From 00e24cdca422f792b80016287562b6b3bccab239 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 23 Jan 2021 08:56:08 -0800 Subject: [PATCH 0899/1314] closes bpo-43011: Fix DeprecationWarnings in test_ctypes (GH-24305) (cherry picked from commit f7fa64f0e87edc61d990ed51b4da722906a10928) Co-authored-by: Zackery Spytz --- Lib/ctypes/test/test_parameters.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/ctypes/test/test_parameters.py b/Lib/ctypes/test/test_parameters.py index 531894fdec8382..38af7ac13d756c 100644 --- a/Lib/ctypes/test/test_parameters.py +++ b/Lib/ctypes/test/test_parameters.py @@ -240,8 +240,8 @@ def test_parameter_repr(self): self.assertEqual(repr(c_double.from_param(1.5)), "") self.assertEqual(repr(c_double.from_param(1e300)), "") self.assertRegex(repr(c_longdouble.from_param(1.5)), r"^$") - self.assertRegex(repr(c_char_p.from_param(b'hihi')), "^$") - self.assertRegex(repr(c_wchar_p.from_param('hihi')), "^$") + self.assertRegex(repr(c_char_p.from_param(b'hihi')), r"^$") + self.assertRegex(repr(c_wchar_p.from_param('hihi')), r"^$") self.assertRegex(repr(c_void_p.from_param(0x12)), r"^$") ################################################################ From ff06957710aa849f3402b082a7ddd34b0325d6de Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 24 Jan 2021 15:36:02 -0800 Subject: [PATCH 0900/1314] bpo-43013: Update idlelib code to 3.x (GH-24315) Remove 9 remaining '(object)' occurrences in class headers in idlelib and 25 '()' occurrences in idlelib.idle_test class headers. (cherry picked from commit 8dfe15625e6ea4357a13fec7989a0e6ba2bf1359) Co-authored-by: Terry Jan Reedy --- Lib/idlelib/editor.py | 4 +-- Lib/idlelib/idle_test/test_autocomplete.py | 2 +- Lib/idlelib/idle_test/test_calltip.py | 4 +-- Lib/idlelib/idle_test/test_codecontext.py | 38 +++++++++++----------- Lib/idlelib/idle_test/test_format.py | 2 +- Lib/idlelib/idle_test/test_help_about.py | 2 +- Lib/idlelib/idle_test/test_pyparse.py | 30 +++++++++-------- Lib/idlelib/rpc.py | 10 +++--- Lib/idlelib/run.py | 2 +- Lib/idlelib/tooltip.py | 2 +- 10 files changed, 49 insertions(+), 47 deletions(-) diff --git a/Lib/idlelib/editor.py b/Lib/idlelib/editor.py index a178eaf93c013a..a4d0c95362fa9b 100644 --- a/Lib/idlelib/editor.py +++ b/Lib/idlelib/editor.py @@ -46,7 +46,7 @@ def _sphinx_version(): return release -class EditorWindow(object): +class EditorWindow: from idlelib.percolator import Percolator from idlelib.colorizer import ColorDelegator, color_config from idlelib.undo import UndoDelegator @@ -1546,7 +1546,7 @@ def get_line_indent(line, tabwidth): return m.end(), len(m.group().expandtabs(tabwidth)) -class IndentSearcher(object): +class IndentSearcher: # .run() chews over the Text widget, looking for a block opener # and the stmt following it. Returns a pair, diff --git a/Lib/idlelib/idle_test/test_autocomplete.py b/Lib/idlelib/idle_test/test_autocomplete.py index 9c113bd893f137..642bb5db64dc34 100644 --- a/Lib/idlelib/idle_test/test_autocomplete.py +++ b/Lib/idlelib/idle_test/test_autocomplete.py @@ -195,7 +195,7 @@ def test_open_completions_none(self): self.assertFalse(acp.open_completions(ac.TAB)) self.text.delete('1.0', 'end') - class dummy_acw(): + class dummy_acw: __init__ = Func() show_window = Func(result=False) hide_window = Func() diff --git a/Lib/idlelib/idle_test/test_calltip.py b/Lib/idlelib/idle_test/test_calltip.py index a76829f3656c80..b23915c5ab7849 100644 --- a/Lib/idlelib/idle_test/test_calltip.py +++ b/Lib/idlelib/idle_test/test_calltip.py @@ -10,7 +10,7 @@ # Test Class TC is used in multiple get_argspec test methods -class TC(): +class TC: 'doc' tip = "(ai=None, *b)" def __init__(self, ai=None, *b): 'doc' @@ -268,7 +268,7 @@ def test_good_entity(self): # open_calltip is about half the code; the others are fairly trivial. # The default mocks are what are needed for open_calltip. -class mock_Shell(): +class mock_Shell: "Return mock sufficient to pass to hyperparser." def __init__(self, text): text.tag_prevrange = Mock(return_value=None) diff --git a/Lib/idlelib/idle_test/test_codecontext.py b/Lib/idlelib/idle_test/test_codecontext.py index 9578cc731a6f93..6969ad73b01a81 100644 --- a/Lib/idlelib/idle_test/test_codecontext.py +++ b/Lib/idlelib/idle_test/test_codecontext.py @@ -20,7 +20,7 @@ } code_sample = """\ -class C1(): +class C1: # Class comment. def __init__(self, a, b): self.a = a @@ -178,29 +178,29 @@ def test_get_context(self): with self.assertRaises(AssertionError): gc(1, stopline=0) - eq(gc(3), ([(2, 0, 'class C1():', 'class')], 0)) + eq(gc(3), ([(2, 0, 'class C1:', 'class')], 0)) # Don't return comment. - eq(gc(4), ([(2, 0, 'class C1():', 'class')], 0)) + eq(gc(4), ([(2, 0, 'class C1:', 'class')], 0)) # Two indentation levels and no comment. - eq(gc(5), ([(2, 0, 'class C1():', 'class'), + eq(gc(5), ([(2, 0, 'class C1:', 'class'), (4, 4, ' def __init__(self, a, b):', 'def')], 0)) # Only one 'def' is returned, not both at the same indent level. - eq(gc(10), ([(2, 0, 'class C1():', 'class'), + eq(gc(10), ([(2, 0, 'class C1:', 'class'), (7, 4, ' def compare(self):', 'def'), (8, 8, ' if a > b:', 'if')], 0)) # With 'elif', also show the 'if' even though it's at the same level. - eq(gc(11), ([(2, 0, 'class C1():', 'class'), + eq(gc(11), ([(2, 0, 'class C1:', 'class'), (7, 4, ' def compare(self):', 'def'), (8, 8, ' if a > b:', 'if'), (10, 8, ' elif a < b:', 'elif')], 0)) # Set stop_line to not go back to first line in source code. # Return includes stop_line. - eq(gc(11, stopline=2), ([(2, 0, 'class C1():', 'class'), + eq(gc(11, stopline=2), ([(2, 0, 'class C1:', 'class'), (7, 4, ' def compare(self):', 'def'), (8, 8, ' if a > b:', 'if'), (10, 8, ' elif a < b:', 'elif')], 0)) @@ -240,37 +240,37 @@ def test_update_code_context(self): # Scroll down to line 2. cc.text.yview(2) cc.update_code_context() - eq(cc.info, [(0, -1, '', False), (2, 0, 'class C1():', 'class')]) + eq(cc.info, [(0, -1, '', False), (2, 0, 'class C1:', 'class')]) eq(cc.topvisible, 3) - eq(cc.context.get('1.0', 'end-1c'), 'class C1():') + eq(cc.context.get('1.0', 'end-1c'), 'class C1:') # Scroll down to line 3. Since it's a comment, nothing changes. cc.text.yview(3) cc.update_code_context() - eq(cc.info, [(0, -1, '', False), (2, 0, 'class C1():', 'class')]) + eq(cc.info, [(0, -1, '', False), (2, 0, 'class C1:', 'class')]) eq(cc.topvisible, 4) - eq(cc.context.get('1.0', 'end-1c'), 'class C1():') + eq(cc.context.get('1.0', 'end-1c'), 'class C1:') # Scroll down to line 4. cc.text.yview(4) cc.update_code_context() eq(cc.info, [(0, -1, '', False), - (2, 0, 'class C1():', 'class'), + (2, 0, 'class C1:', 'class'), (4, 4, ' def __init__(self, a, b):', 'def')]) eq(cc.topvisible, 5) - eq(cc.context.get('1.0', 'end-1c'), 'class C1():\n' + eq(cc.context.get('1.0', 'end-1c'), 'class C1:\n' ' def __init__(self, a, b):') # Scroll down to line 11. Last 'def' is removed. cc.text.yview(11) cc.update_code_context() eq(cc.info, [(0, -1, '', False), - (2, 0, 'class C1():', 'class'), + (2, 0, 'class C1:', 'class'), (7, 4, ' def compare(self):', 'def'), (8, 8, ' if a > b:', 'if'), (10, 8, ' elif a < b:', 'elif')]) eq(cc.topvisible, 12) - eq(cc.context.get('1.0', 'end-1c'), 'class C1():\n' + eq(cc.context.get('1.0', 'end-1c'), 'class C1:\n' ' def compare(self):\n' ' if a > b:\n' ' elif a < b:') @@ -279,12 +279,12 @@ def test_update_code_context(self): cc.update_code_context() cc.context_depth = 1 eq(cc.info, [(0, -1, '', False), - (2, 0, 'class C1():', 'class'), + (2, 0, 'class C1:', 'class'), (7, 4, ' def compare(self):', 'def'), (8, 8, ' if a > b:', 'if'), (10, 8, ' elif a < b:', 'elif')]) eq(cc.topvisible, 12) - eq(cc.context.get('1.0', 'end-1c'), 'class C1():\n' + eq(cc.context.get('1.0', 'end-1c'), 'class C1:\n' ' def compare(self):\n' ' if a > b:\n' ' elif a < b:') @@ -293,7 +293,7 @@ def test_update_code_context(self): cc.text.yview(5) cc.update_code_context() eq(cc.info, [(0, -1, '', False), - (2, 0, 'class C1():', 'class'), + (2, 0, 'class C1:', 'class'), (4, 4, ' def __init__(self, a, b):', 'def')]) eq(cc.topvisible, 6) # context_depth is 1. @@ -440,7 +440,7 @@ def test_get_line_info(self): # Line 1 is not a BLOCKOPENER. eq(gli(lines[0]), (codecontext.INFINITY, '', False)) # Line 2 is a BLOCKOPENER without an indent. - eq(gli(lines[1]), (0, 'class C1():', 'class')) + eq(gli(lines[1]), (0, 'class C1:', 'class')) # Line 3 is not a BLOCKOPENER and does not return the indent level. eq(gli(lines[2]), (codecontext.INFINITY, ' # Class comment.', False)) # Line 4 is a BLOCKOPENER and is indented. diff --git a/Lib/idlelib/idle_test/test_format.py b/Lib/idlelib/idle_test/test_format.py index a79bb515089e7b..e5e903688597aa 100644 --- a/Lib/idlelib/idle_test/test_format.py +++ b/Lib/idlelib/idle_test/test_format.py @@ -418,7 +418,7 @@ def tearDown(self): code_sample = """\ # WS line needed for test. -class C1(): +class C1: # Class comment. def __init__(self, a, b): self.a = a diff --git a/Lib/idlelib/idle_test/test_help_about.py b/Lib/idlelib/idle_test/test_help_about.py index 7c148d23a135b6..b915535acac0cc 100644 --- a/Lib/idlelib/idle_test/test_help_about.py +++ b/Lib/idlelib/idle_test/test_help_about.py @@ -134,7 +134,7 @@ def test_close(self): self.dialog.winfo_class() -class Dummy_about_dialog(): +class Dummy_about_dialog: # Dummy class for testing file display functions. idle_credits = About.show_idle_credits idle_readme = About.show_readme diff --git a/Lib/idlelib/idle_test/test_pyparse.py b/Lib/idlelib/idle_test/test_pyparse.py index f21baf7534420a..fb5726db1d821e 100644 --- a/Lib/idlelib/idle_test/test_pyparse.py +++ b/Lib/idlelib/idle_test/test_pyparse.py @@ -73,11 +73,12 @@ def char_in_string_false(index): return False # Split def across lines. setcode('"""This is a module docstring"""\n' - 'class C():\n' + 'class C:\n' ' def __init__(self, a,\n' ' b=True):\n' ' pass\n' ) + pos0, pos = 33, 42 # Start of 'class...', ' def' lines. # Passing no value or non-callable should fail (issue 32989). with self.assertRaises(TypeError): @@ -91,40 +92,41 @@ def char_in_string_false(index): return False # Make all text look like it's not in a string. This means that it # found a good start position. - eq(start(char_in_string_false), 44) + eq(start(char_in_string_false), pos) # If the beginning of the def line is not in a string, then it # returns that as the index. - eq(start(is_char_in_string=lambda index: index > 44), 44) + eq(start(is_char_in_string=lambda index: index > pos), pos) # If the beginning of the def line is in a string, then it # looks for a previous index. - eq(start(is_char_in_string=lambda index: index >= 44), 33) + eq(start(is_char_in_string=lambda index: index >= pos), pos0) # If everything before the 'def' is in a string, then returns None. # The non-continuation def line returns 44 (see below). - eq(start(is_char_in_string=lambda index: index < 44), None) + eq(start(is_char_in_string=lambda index: index < pos), None) # Code without extra line break in def line - mostly returns the same # values. setcode('"""This is a module docstring"""\n' - 'class C():\n' + 'class C:\n' ' def __init__(self, a, b=True):\n' ' pass\n' - ) - eq(start(char_in_string_false), 44) - eq(start(is_char_in_string=lambda index: index > 44), 44) - eq(start(is_char_in_string=lambda index: index >= 44), 33) + ) # Does not affect class, def positions. + eq(start(char_in_string_false), pos) + eq(start(is_char_in_string=lambda index: index > pos), pos) + eq(start(is_char_in_string=lambda index: index >= pos), pos0) # When the def line isn't split, this returns which doesn't match the # split line test. - eq(start(is_char_in_string=lambda index: index < 44), 44) + eq(start(is_char_in_string=lambda index: index < pos), pos) def test_set_lo(self): code = ( '"""This is a module docstring"""\n' - 'class C():\n' + 'class C:\n' ' def __init__(self, a,\n' ' b=True):\n' ' pass\n' ) + pos = 42 p = self.parser p.set_code(code) @@ -137,8 +139,8 @@ def test_set_lo(self): self.assertEqual(p.code, code) # An index that is preceded by a newline. - p.set_lo(44) - self.assertEqual(p.code, code[44:]) + p.set_lo(pos) + self.assertEqual(p.code, code[pos:]) def test_study1(self): eq = self.assertEqual diff --git a/Lib/idlelib/rpc.py b/Lib/idlelib/rpc.py index aa8cbd36c47926..8efcf048fa3aa2 100644 --- a/Lib/idlelib/rpc.py +++ b/Lib/idlelib/rpc.py @@ -125,7 +125,7 @@ def handle_error(self, request, client_address): response_queue = queue.Queue(0) -class SocketIO(object): +class SocketIO: nextseq = 0 @@ -486,7 +486,7 @@ def EOFhook(self): #----------------- end class SocketIO -------------------- -class RemoteObject(object): +class RemoteObject: # Token mix-in class pass @@ -497,7 +497,7 @@ def remoteref(obj): return RemoteProxy(oid) -class RemoteProxy(object): +class RemoteProxy: def __init__(self, oid): self.oid = oid @@ -547,7 +547,7 @@ def get_remote_proxy(self, oid): return RPCProxy(self, oid) -class RPCProxy(object): +class RPCProxy: __methods = None __attributes = None @@ -596,7 +596,7 @@ def _getattributes(obj, attributes): attributes[name] = 1 -class MethodProxy(object): +class MethodProxy: def __init__(self, sockio, oid, name): self.sockio = sockio diff --git a/Lib/idlelib/run.py b/Lib/idlelib/run.py index 1e84ecc6584ef1..ec575c3d483631 100644 --- a/Lib/idlelib/run.py +++ b/Lib/idlelib/run.py @@ -538,7 +538,7 @@ def decode_interrupthook(self): thread.interrupt_main() -class Executive(object): +class Executive: def __init__(self, rpchandler): self.rpchandler = rpchandler diff --git a/Lib/idlelib/tooltip.py b/Lib/idlelib/tooltip.py index 69658264dbd4a4..d714318dae8ef1 100644 --- a/Lib/idlelib/tooltip.py +++ b/Lib/idlelib/tooltip.py @@ -7,7 +7,7 @@ from tkinter import * -class TooltipBase(object): +class TooltipBase: """abstract base class for tooltips""" def __init__(self, anchor_widget): From 3d5434d5cbc945c58be663e3dbd5ef4875677b7a Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Mon, 25 Jan 2021 11:45:30 +0200 Subject: [PATCH 0901/1314] [3.9] bpo-33289: Return RGB triplet of ints instead of floats from tkinter.colorchooser (GH-6578). (GH-24318) (cherry picked from commit 6713e869c4989c04318158b406c30a147ea52904) Co-authored-by: Cheryl Sabella --- Lib/tkinter/__init__.py | 3 +- Lib/tkinter/colorchooser.py | 60 +++++++++++-------- .../test/test_tkinter/test_colorchooser.py | 43 +++++++++++++ Lib/tkinter/test/test_tkinter/test_misc.py | 20 +++++++ .../2018-04-23-13-44-10.bpo-33289.anBnUr.rst | 2 + 5 files changed, 102 insertions(+), 26 deletions(-) create mode 100644 Lib/tkinter/test/test_tkinter/test_colorchooser.py create mode 100644 Misc/NEWS.d/next/Library/2018-04-23-13-44-10.bpo-33289.anBnUr.rst diff --git a/Lib/tkinter/__init__.py b/Lib/tkinter/__init__.py index 98e95ad44866fe..f15f6c5e57a501 100644 --- a/Lib/tkinter/__init__.py +++ b/Lib/tkinter/__init__.py @@ -1160,8 +1160,7 @@ def winfo_reqwidth(self): self.tk.call('winfo', 'reqwidth', self._w)) def winfo_rgb(self, color): - """Return tuple of decimal values for red, green, blue for - COLOR in this widget.""" + """Return a tuple of integer RGB values in range(65536) for color in this widget.""" return self._getints( self.tk.call('winfo', 'rgb', self._w, color)) diff --git a/Lib/tkinter/colorchooser.py b/Lib/tkinter/colorchooser.py index 3cfc06f6f1fae6..e2fb69dba92763 100644 --- a/Lib/tkinter/colorchooser.py +++ b/Lib/tkinter/colorchooser.py @@ -8,57 +8,69 @@ # fixed initialcolor handling in August 1998 # -# -# options (all have default values): -# -# - initialcolor: color to mark as selected when dialog is displayed -# (given as an RGB triplet or a Tk color string) -# -# - parent: which window to place the dialog on top of -# -# - title: dialog title -# from tkinter.commondialog import Dialog __all__ = ["Chooser", "askcolor"] -# -# color chooser class - class Chooser(Dialog): - "Ask for a color" + """Create a dialog for the tk_chooseColor command. + + Args: + master: The master widget for this dialog. If not provided, + defaults to options['parent'] (if defined). + options: Dictionary of options for the tk_chooseColor call. + initialcolor: Specifies the selected color when the + dialog is first displayed. This can be a tk color + string or a 3-tuple of ints in the range (0, 255) + for an RGB triplet. + parent: The parent window of the color dialog. The + color dialog is displayed on top of this. + title: A string for the title of the dialog box. + """ command = "tk_chooseColor" def _fixoptions(self): + """Ensure initialcolor is a tk color string. + + Convert initialcolor from a RGB triplet to a color string. + """ try: - # make sure initialcolor is a tk color string color = self.options["initialcolor"] if isinstance(color, tuple): - # assume an RGB triplet + # Assume an RGB triplet. self.options["initialcolor"] = "#%02x%02x%02x" % color except KeyError: pass def _fixresult(self, widget, result): - # result can be somethings: an empty tuple, an empty string or - # a Tcl_Obj, so this somewhat weird check handles that + """Adjust result returned from call to tk_chooseColor. + + Return both an RGB tuple of ints in the range (0, 255) and the + tk color string in the form #rrggbb. + """ + # Result can be many things: an empty tuple, an empty string, or + # a _tkinter.Tcl_Obj, so this somewhat weird check handles that. if not result or not str(result): - return None, None # canceled + return None, None # canceled - # to simplify application code, the color chooser returns - # an RGB tuple together with the Tk color string + # To simplify application code, the color chooser returns + # an RGB tuple together with the Tk color string. r, g, b = widget.winfo_rgb(result) - return (r/256, g/256, b/256), str(result) + return (r//256, g//256, b//256), str(result) # # convenience stuff -def askcolor(color = None, **options): - "Ask for a color" +def askcolor(color=None, **options): + """Display dialog window for selection of a color. + + Convenience wrapper for the Chooser class. Displays the color + chooser dialog with color as the initial value. + """ if color: options = options.copy() diff --git a/Lib/tkinter/test/test_tkinter/test_colorchooser.py b/Lib/tkinter/test/test_tkinter/test_colorchooser.py new file mode 100644 index 00000000000000..4798bc9c26fc05 --- /dev/null +++ b/Lib/tkinter/test/test_tkinter/test_colorchooser.py @@ -0,0 +1,43 @@ +import unittest +import tkinter +from test.support import requires, run_unittest, swap_attr +from tkinter.test.support import AbstractTkTest +from tkinter import colorchooser + +requires('gui') + + +class ChooserTest(AbstractTkTest, unittest.TestCase): + + @classmethod + def setUpClass(cls): + AbstractTkTest.setUpClass.__func__(cls) + cls.cc = colorchooser.Chooser(initialcolor='dark blue slate') + + def test_fixoptions(self): + cc = self.cc + cc._fixoptions() + self.assertEqual(cc.options['initialcolor'], 'dark blue slate') + + cc.options['initialcolor'] = '#D2D269691E1E' + cc._fixoptions() + self.assertEqual(cc.options['initialcolor'], '#D2D269691E1E') + + cc.options['initialcolor'] = (210, 105, 30) + cc._fixoptions() + self.assertEqual(cc.options['initialcolor'], '#d2691e') + + def test_fixresult(self): + cc = self.cc + self.assertEqual(cc._fixresult(self.root, ()), (None, None)) + self.assertEqual(cc._fixresult(self.root, ''), (None, None)) + self.assertEqual(cc._fixresult(self.root, 'chocolate'), + ((210, 105, 30), 'chocolate')) + self.assertEqual(cc._fixresult(self.root, '#4a3c8c'), + ((74, 60, 140), '#4a3c8c')) + + +tests_gui = (ChooserTest,) + +if __name__ == "__main__": + run_unittest(*tests_gui) diff --git a/Lib/tkinter/test/test_tkinter/test_misc.py b/Lib/tkinter/test/test_tkinter/test_misc.py index 585d81ddf9f2d6..f6e5b4db1ae1fb 100644 --- a/Lib/tkinter/test/test_tkinter/test_misc.py +++ b/Lib/tkinter/test/test_tkinter/test_misc.py @@ -192,6 +192,26 @@ def test_clipboard_astral(self): with self.assertRaises(tkinter.TclError): root.clipboard_get() + def test_winfo_rgb(self): + root = self.root + rgb = root.winfo_rgb + + # Color name. + self.assertEqual(rgb('red'), (65535, 0, 0)) + self.assertEqual(rgb('dark slate blue'), (18504, 15677, 35723)) + # #RGB - extends each 4-bit hex value to be 16-bit. + self.assertEqual(rgb('#F0F'), (0xFFFF, 0x0000, 0xFFFF)) + # #RRGGBB - extends each 8-bit hex value to be 16-bit. + self.assertEqual(rgb('#4a3c8c'), (0x4a4a, 0x3c3c, 0x8c8c)) + # #RRRRGGGGBBBB + self.assertEqual(rgb('#dede14143939'), (0xdede, 0x1414, 0x3939)) + # Invalid string. + with self.assertRaises(tkinter.TclError): + rgb('#123456789a') + # RGB triplet is invalid input. + with self.assertRaises(tkinter.TclError): + rgb((111, 78, 55)) + def test_event_repr_defaults(self): e = tkinter.Event() e.serial = 12345 diff --git a/Misc/NEWS.d/next/Library/2018-04-23-13-44-10.bpo-33289.anBnUr.rst b/Misc/NEWS.d/next/Library/2018-04-23-13-44-10.bpo-33289.anBnUr.rst new file mode 100644 index 00000000000000..52d9ac9dd902cd --- /dev/null +++ b/Misc/NEWS.d/next/Library/2018-04-23-13-44-10.bpo-33289.anBnUr.rst @@ -0,0 +1,2 @@ +Correct call to :mod:`tkinter.colorchooser` to return RGB triplet of ints +instead of floats. Patch by Cheryl Sabella. From 26af2fae189629d22a87aaf01b92d6f4de92b958 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 25 Jan 2021 05:25:39 -0800 Subject: [PATCH 0902/1314] bpo-43013: Fix old tkinter module names in idlelib (GH-24326) Lowercase 'tkColorChooser', 'tkFileDialog', 'tkSimpleDialog', and 'tkMessageBox' and remove 'tk'. Just lowercase 'tkFont' as 'font' is already used. Adjust import. (cherry picked from commit 879986d8a932c4524cb6ff822afc9537de16e28d) Co-authored-by: Terry Jan Reedy --- Lib/idlelib/configdialog.py | 10 ++++---- Lib/idlelib/editor.py | 16 ++++++------ Lib/idlelib/filelist.py | 6 ++--- Lib/idlelib/idle_test/mock_tk.py | 9 +++---- Lib/idlelib/idle_test/test_configdialog.py | 8 +++--- Lib/idlelib/idle_test/test_replace.py | 6 ++--- Lib/idlelib/idle_test/test_searchengine.py | 6 ++--- Lib/idlelib/idle_test/test_squeezer.py | 4 +-- Lib/idlelib/iomenu.py | 30 +++++++++++----------- Lib/idlelib/pyshell.py | 20 +++++++-------- Lib/idlelib/runscript.py | 8 +++--- Lib/idlelib/searchengine.py | 4 +-- Lib/idlelib/squeezer.py | 6 ++--- 13 files changed, 66 insertions(+), 67 deletions(-) diff --git a/Lib/idlelib/configdialog.py b/Lib/idlelib/configdialog.py index 73e64852c69dfd..c52a04b503adb4 100644 --- a/Lib/idlelib/configdialog.py +++ b/Lib/idlelib/configdialog.py @@ -18,8 +18,8 @@ HORIZONTAL, VERTICAL, ANCHOR, ACTIVE, END) from tkinter.ttk import (Frame, LabelFrame, Button, Checkbutton, Entry, Label, OptionMenu, Notebook, Radiobutton, Scrollbar, Style) -import tkinter.colorchooser as tkColorChooser -import tkinter.font as tkFont +from tkinter import colorchooser +import tkinter.font as tkfont from tkinter import messagebox from idlelib.config import idleConf, ConfigChanges @@ -609,7 +609,7 @@ def load_font_cfg(self): font_bold = configured_font[2]=='bold' # Set sorted no-duplicate editor font selection list and font_name. - fonts = sorted(set(tkFont.families(self))) + fonts = sorted(set(tkfont.families(self))) for font in fonts: self.fontlist.insert(END, font) self.font_name.set(font_name) @@ -663,7 +663,7 @@ def set_samples(self, event=None): Updates font_sample and highlight page highlight_sample. """ font_name = self.font_name.get() - font_weight = tkFont.BOLD if self.font_bold.get() else tkFont.NORMAL + font_weight = tkfont.BOLD if self.font_bold.get() else tkfont.NORMAL new_font = (font_name, self.font_size.get(), font_weight) self.font_sample['font'] = new_font self.highlight_sample['font'] = new_font @@ -1100,7 +1100,7 @@ def get_color(self): target = self.highlight_target.get() prev_color = self.style.lookup(self.frame_color_set['style'], 'background') - rgbTuplet, color_string = tkColorChooser.askcolor( + rgbTuplet, color_string = colorchooser.askcolor( parent=self, title='Pick new color for : '+target, initialcolor=prev_color) if color_string and (color_string != prev_color): diff --git a/Lib/idlelib/editor.py b/Lib/idlelib/editor.py index a4d0c95362fa9b..66e9da5a9dccf9 100644 --- a/Lib/idlelib/editor.py +++ b/Lib/idlelib/editor.py @@ -12,8 +12,8 @@ from tkinter import * from tkinter.font import Font from tkinter.ttk import Scrollbar -import tkinter.simpledialog as tkSimpleDialog -import tkinter.messagebox as tkMessageBox +from tkinter import simpledialog +from tkinter import messagebox from idlelib.config import idleConf from idlelib import configdialog @@ -295,9 +295,9 @@ def __init__(self, flist=None, filename=None, key=None, root=None): window.register_callback(self.postwindowsmenu) # Some abstractions so IDLE extensions are cross-IDE - self.askyesno = tkMessageBox.askyesno - self.askinteger = tkSimpleDialog.askinteger - self.showerror = tkMessageBox.showerror + self.askinteger = simpledialog.askinteger + self.askyesno = messagebox.askyesno + self.showerror = messagebox.showerror # Add pseudoevents for former extension fixed keys. # (This probably needs to be done once in the process.) @@ -596,7 +596,7 @@ def python_docs(self, event=None): try: os.startfile(self.help_url) except OSError as why: - tkMessageBox.showerror(title='Document Start Failure', + messagebox.showerror(title='Document Start Failure', message=str(why), parent=self.text) else: webbrowser.open(self.help_url) @@ -927,7 +927,7 @@ def display_extra_help(helpfile=helpfile): try: os.startfile(helpfile) except OSError as why: - tkMessageBox.showerror(title='Document Start Failure', + messagebox.showerror(title='Document Start Failure', message=str(why), parent=self.text) else: webbrowser.open(helpfile) @@ -963,7 +963,7 @@ def update_recent_files_list(self, new_file=None): except OSError as err: if not getattr(self.root, "recentfiles_message", False): self.root.recentfiles_message = True - tkMessageBox.showwarning(title='IDLE Warning', + messagebox.showwarning(title='IDLE Warning', message="Cannot save Recent Files list to disk.\n" f" {err}\n" "Select OK to continue.", diff --git a/Lib/idlelib/filelist.py b/Lib/idlelib/filelist.py index 0d200854ef0007..254f5caf6b81b0 100644 --- a/Lib/idlelib/filelist.py +++ b/Lib/idlelib/filelist.py @@ -1,7 +1,7 @@ "idlelib.filelist" import os -from tkinter import messagebox as tkMessageBox +from tkinter import messagebox class FileList: @@ -20,7 +20,7 @@ def open(self, filename, action=None): filename = self.canonize(filename) if os.path.isdir(filename): # This can happen when bad filename is passed on command line: - tkMessageBox.showerror( + messagebox.showerror( "File Error", "%r is a directory." % (filename,), master=self.root) @@ -88,7 +88,7 @@ def filename_changed_edit(self, edit): if newkey in self.dict: conflict = self.dict[newkey] self.inversedict[conflict] = None - tkMessageBox.showerror( + messagebox.showerror( "Name Conflict", "You now have multiple edit windows open for %r" % (filename,), master=self.root) diff --git a/Lib/idlelib/idle_test/mock_tk.py b/Lib/idlelib/idle_test/mock_tk.py index b736bd001da87f..db583553838fb3 100644 --- a/Lib/idlelib/idle_test/mock_tk.py +++ b/Lib/idlelib/idle_test/mock_tk.py @@ -59,27 +59,26 @@ def __call__(self, title, message, *args, **kwds): class Mbox: """Mock for tkinter.messagebox with an Mbox_func for each function. - This module was 'tkMessageBox' in 2.x; hence the 'import as' in 3.x. Example usage in test_module.py for testing functions in module.py: --- from idlelib.idle_test.mock_tk import Mbox import module -orig_mbox = module.tkMessageBox +orig_mbox = module.messagebox showerror = Mbox.showerror # example, for attribute access in test methods class Test(unittest.TestCase): @classmethod def setUpClass(cls): - module.tkMessageBox = Mbox + module.messagebox = Mbox @classmethod def tearDownClass(cls): - module.tkMessageBox = orig_mbox + module.messagebox = orig_mbox --- For 'ask' functions, set func.result return value before calling the method - that uses the message function. When tkMessageBox functions are the + that uses the message function. When messagebox functions are the only gui alls in a method, this replacement makes the method gui-free, """ askokcancel = Mbox_func() # True or False diff --git a/Lib/idlelib/idle_test/test_configdialog.py b/Lib/idlelib/idle_test/test_configdialog.py index 1fea6d41df811c..98ddc67afdcc08 100644 --- a/Lib/idlelib/idle_test/test_configdialog.py +++ b/Lib/idlelib/idle_test/test_configdialog.py @@ -423,7 +423,7 @@ def test_custom_name(self): def test_color(self): d = self.page d.on_new_color_set = Func() - # self.color is only set in get_color through ColorChooser. + # self.color is only set in get_color through colorchooser. d.color.set('green') self.assertEqual(d.on_new_color_set.called, 1) del d.on_new_color_set @@ -540,8 +540,8 @@ def test_set_theme_type(self): def test_get_color(self): eq = self.assertEqual d = self.page - orig_chooser = configdialog.tkColorChooser.askcolor - chooser = configdialog.tkColorChooser.askcolor = Func() + orig_chooser = configdialog.colorchooser.askcolor + chooser = configdialog.colorchooser.askcolor = Func() gntn = d.get_new_theme_name = Func() d.highlight_target.set('Editor Breakpoint') @@ -582,7 +582,7 @@ def test_get_color(self): eq(d.color.get(), '#de0000') del d.get_new_theme_name - configdialog.tkColorChooser.askcolor = orig_chooser + configdialog.colorchooser.askcolor = orig_chooser def test_on_new_color_set(self): d = self.page diff --git a/Lib/idlelib/idle_test/test_replace.py b/Lib/idlelib/idle_test/test_replace.py index c3c5d2eeb94998..6c07389b29ad45 100644 --- a/Lib/idlelib/idle_test/test_replace.py +++ b/Lib/idlelib/idle_test/test_replace.py @@ -10,7 +10,7 @@ from idlelib.idle_test.mock_tk import Mbox import idlelib.searchengine as se -orig_mbox = se.tkMessageBox +orig_mbox = se.messagebox showerror = Mbox.showerror @@ -20,7 +20,7 @@ class ReplaceDialogTest(unittest.TestCase): def setUpClass(cls): cls.root = Tk() cls.root.withdraw() - se.tkMessageBox = Mbox + se.messagebox = Mbox cls.engine = se.SearchEngine(cls.root) cls.dialog = ReplaceDialog(cls.root, cls.engine) cls.dialog.bell = lambda: None @@ -32,7 +32,7 @@ def setUpClass(cls): @classmethod def tearDownClass(cls): - se.tkMessageBox = orig_mbox + se.messagebox = orig_mbox del cls.text, cls.dialog, cls.engine cls.root.destroy() del cls.root diff --git a/Lib/idlelib/idle_test/test_searchengine.py b/Lib/idlelib/idle_test/test_searchengine.py index f8401ce9380f25..9d979839419586 100644 --- a/Lib/idlelib/idle_test/test_searchengine.py +++ b/Lib/idlelib/idle_test/test_searchengine.py @@ -4,7 +4,7 @@ import unittest # from test.support import requires from tkinter import BooleanVar, StringVar, TclError # ,Tk, Text -import tkinter.messagebox as tkMessageBox +from tkinter import messagebox from idlelib.idle_test.mock_tk import Var, Mbox from idlelib.idle_test.mock_tk import Text as mockText import re @@ -19,13 +19,13 @@ def setUpModule(): # Replace s-e module tkinter imports other than non-gui TclError. se.BooleanVar = Var se.StringVar = Var - se.tkMessageBox = Mbox + se.messagebox = Mbox def tearDownModule(): # Restore 'just in case', though other tests should also replace. se.BooleanVar = BooleanVar se.StringVar = StringVar - se.tkMessageBox = tkMessageBox + se.messagebox = messagebox class Mock: diff --git a/Lib/idlelib/idle_test/test_squeezer.py b/Lib/idlelib/idle_test/test_squeezer.py index e3912f4bbbec89..ee1bbd76b50562 100644 --- a/Lib/idlelib/idle_test/test_squeezer.py +++ b/Lib/idlelib/idle_test/test_squeezer.py @@ -396,7 +396,7 @@ def test_expand_dangerous_oupput(self): expandingbutton.base_text = expandingbutton.text # Patch the message box module to always return False. - with patch('idlelib.squeezer.tkMessageBox') as mock_msgbox: + with patch('idlelib.squeezer.messagebox') as mock_msgbox: mock_msgbox.askokcancel.return_value = False mock_msgbox.askyesno.return_value = False # Trigger the expand event. @@ -407,7 +407,7 @@ def test_expand_dangerous_oupput(self): self.assertEqual(expandingbutton.text.get('1.0', 'end-1c'), '') # Patch the message box module to always return True. - with patch('idlelib.squeezer.tkMessageBox') as mock_msgbox: + with patch('idlelib.squeezer.messagebox') as mock_msgbox: mock_msgbox.askokcancel.return_value = True mock_msgbox.askyesno.return_value = True # Trigger the expand event. diff --git a/Lib/idlelib/iomenu.py b/Lib/idlelib/iomenu.py index 8bb2fa6a6e7939..5ebf7089fb9abe 100644 --- a/Lib/idlelib/iomenu.py +++ b/Lib/idlelib/iomenu.py @@ -5,8 +5,8 @@ import tempfile import tokenize -import tkinter.filedialog as tkFileDialog -import tkinter.messagebox as tkMessageBox +from tkinter import filedialog +from tkinter import messagebox from tkinter.simpledialog import askstring import idlelib @@ -147,10 +147,10 @@ def loadfile(self, filename): eol_convention = f.newlines converted = True except OSError as err: - tkMessageBox.showerror("I/O Error", str(err), parent=self.text) + messagebox.showerror("I/O Error", str(err), parent=self.text) return False except UnicodeDecodeError: - tkMessageBox.showerror("Decoding Error", + messagebox.showerror("Decoding Error", "File %s\nFailed to Decode" % filename, parent=self.text) return False @@ -159,7 +159,7 @@ def loadfile(self, filename): # If the file does not contain line separators, it is None. # If the file contains mixed line separators, it is a tuple. if eol_convention is not None: - tkMessageBox.showwarning("Mixed Newlines", + messagebox.showwarning("Mixed Newlines", "Mixed newlines detected.\n" "The file will be changed on save.", parent=self.text) @@ -187,10 +187,10 @@ def maybesave(self): return "yes" message = "Do you want to save %s before closing?" % ( self.filename or "this untitled document") - confirm = tkMessageBox.askyesnocancel( + confirm = messagebox.askyesnocancel( title="Save On Close", message=message, - default=tkMessageBox.YES, + default=messagebox.YES, parent=self.text) if confirm: reply = "yes" @@ -249,7 +249,7 @@ def writefile(self, filename): os.fsync(f.fileno()) return True except OSError as msg: - tkMessageBox.showerror("I/O Error", str(msg), + messagebox.showerror("I/O Error", str(msg), parent=self.text) return False @@ -286,7 +286,7 @@ def encode(self, chars): failed = str(err) except UnicodeEncodeError: failed = "Invalid encoding '%s'" % enc - tkMessageBox.showerror( + messagebox.showerror( "I/O Error", "%s.\nSaving as UTF-8" % failed, parent=self.text) @@ -295,10 +295,10 @@ def encode(self, chars): return chars.encode('utf-8-sig') def print_window(self, event): - confirm = tkMessageBox.askokcancel( + confirm = messagebox.askokcancel( title="Print", message="Print to Default Printer", - default=tkMessageBox.OK, + default=messagebox.OK, parent=self.text) if not confirm: self.text.focus_set() @@ -336,10 +336,10 @@ def print_window(self, event): status + output if output: output = "Printing command: %s\n" % repr(command) + output - tkMessageBox.showerror("Print status", output, parent=self.text) + messagebox.showerror("Print status", output, parent=self.text) else: #no printing for this platform message = "Printing is not enabled for this platform: %s" % platform - tkMessageBox.showinfo("Print status", message, parent=self.text) + messagebox.showinfo("Print status", message, parent=self.text) if tempfilename: os.unlink(tempfilename) return "break" @@ -358,7 +358,7 @@ def print_window(self, event): def askopenfile(self): dir, base = self.defaultfilename("open") if not self.opendialog: - self.opendialog = tkFileDialog.Open(parent=self.text, + self.opendialog = filedialog.Open(parent=self.text, filetypes=self.filetypes) filename = self.opendialog.show(initialdir=dir, initialfile=base) return filename @@ -378,7 +378,7 @@ def defaultfilename(self, mode="open"): def asksavefile(self): dir, base = self.defaultfilename("save") if not self.savedialog: - self.savedialog = tkFileDialog.SaveAs( + self.savedialog = filedialog.SaveAs( parent=self.text, filetypes=self.filetypes, defaultextension=self.defaultextension) diff --git a/Lib/idlelib/pyshell.py b/Lib/idlelib/pyshell.py index 6fa138219a24da..d32106c9838744 100755 --- a/Lib/idlelib/pyshell.py +++ b/Lib/idlelib/pyshell.py @@ -21,13 +21,13 @@ except (ImportError, AttributeError, OSError): pass -import tkinter.messagebox as tkMessageBox +from tkinter import messagebox if TkVersion < 8.5: root = Tk() # otherwise create root in main root.withdraw() from idlelib.run import fix_scaling fix_scaling(root) - tkMessageBox.showerror("Idle Cannot Start", + messagebox.showerror("Idle Cannot Start", "Idle requires tcl/tk 8.5+, not %s." % TkVersion, parent=root) raise SystemExit(1) @@ -261,7 +261,7 @@ def store_file_breaks(self): except OSError as err: if not getattr(self.root, "breakpoint_error_displayed", False): self.root.breakpoint_error_displayed = True - tkMessageBox.showerror(title='IDLE Error', + messagebox.showerror(title='IDLE Error', message='Unable to update breakpoint list:\n%s' % str(err), parent=self.text) @@ -771,7 +771,7 @@ def runcode(self, code): exec(code, self.locals) except SystemExit: if not self.tkconsole.closing: - if tkMessageBox.askyesno( + if messagebox.askyesno( "Exit?", "Do you want to exit altogether?", default="yes", @@ -805,7 +805,7 @@ def write(self, s): return self.tkconsole.stderr.write(s) def display_port_binding_error(self): - tkMessageBox.showerror( + messagebox.showerror( "Port Binding Error", "IDLE can't bind to a TCP/IP port, which is necessary to " "communicate with its Python execution server. This might be " @@ -816,7 +816,7 @@ def display_port_binding_error(self): parent=self.tkconsole.text) def display_no_subprocess_error(self): - tkMessageBox.showerror( + messagebox.showerror( "Subprocess Connection Error", "IDLE's subprocess didn't make connection.\n" "See the 'Startup failure' section of the IDLE doc, online at\n" @@ -824,7 +824,7 @@ def display_no_subprocess_error(self): parent=self.tkconsole.text) def display_executing_dialog(self): - tkMessageBox.showerror( + messagebox.showerror( "Already executing", "The Python Shell window is already executing a command; " "please wait until it is finished.", @@ -945,7 +945,7 @@ def get_warning_stream(self): def toggle_debugger(self, event=None): if self.executing: - tkMessageBox.showerror("Don't debug now", + messagebox.showerror("Don't debug now", "You can only toggle the debugger when idle", parent=self.text) self.set_debugger_indicator() @@ -1003,7 +1003,7 @@ def endexecuting(self): def close(self): "Extend EditorWindow.close()" if self.executing: - response = tkMessageBox.askokcancel( + response = messagebox.askokcancel( "Kill?", "Your program is still running!\n Do you want to kill it?", default="ok", @@ -1254,7 +1254,7 @@ def open_stack_viewer(self, event=None): try: sys.last_traceback except: - tkMessageBox.showerror("No stack trace", + messagebox.showerror("No stack trace", "There is no stack trace yet.\n" "(sys.last_traceback is not defined)", parent=self.text) diff --git a/Lib/idlelib/runscript.py b/Lib/idlelib/runscript.py index 028b0dbd21dfe6..55712e904603f8 100644 --- a/Lib/idlelib/runscript.py +++ b/Lib/idlelib/runscript.py @@ -14,7 +14,7 @@ import time import tokenize -import tkinter.messagebox as tkMessageBox +from tkinter import messagebox from idlelib.config import idleConf from idlelib import macosx @@ -195,15 +195,15 @@ def getfilename(self): def ask_save_dialog(self): msg = "Source Must Be Saved\n" + 5*' ' + "OK to Save?" - confirm = tkMessageBox.askokcancel(title="Save Before Run or Check", + confirm = messagebox.askokcancel(title="Save Before Run or Check", message=msg, - default=tkMessageBox.OK, + default=messagebox.OK, parent=self.editwin.text) return confirm def errorbox(self, title, message): # XXX This should really be a function of EditorWindow... - tkMessageBox.showerror(title, message, parent=self.editwin.text) + messagebox.showerror(title, message, parent=self.editwin.text) self.editwin.text.focus_set() self.perf = time.perf_counter() diff --git a/Lib/idlelib/searchengine.py b/Lib/idlelib/searchengine.py index a50038e282ba6c..eddef581ab40a7 100644 --- a/Lib/idlelib/searchengine.py +++ b/Lib/idlelib/searchengine.py @@ -2,7 +2,7 @@ import re from tkinter import StringVar, BooleanVar, TclError -import tkinter.messagebox as tkMessageBox +from tkinter import messagebox def get(root): '''Return the singleton SearchEngine instance for the process. @@ -96,7 +96,7 @@ def report_error(self, pat, msg, col=None): msg = msg + "\nPattern: " + str(pat) if col is not None: msg = msg + "\nOffset: " + str(col) - tkMessageBox.showerror("Regular expression error", + messagebox.showerror("Regular expression error", msg, master=self.root) def search_text(self, text, prog=None, ok=0): diff --git a/Lib/idlelib/squeezer.py b/Lib/idlelib/squeezer.py index be1538a25fdedf..3046d803b74a4e 100644 --- a/Lib/idlelib/squeezer.py +++ b/Lib/idlelib/squeezer.py @@ -17,7 +17,7 @@ import re import tkinter as tk -import tkinter.messagebox as tkMessageBox +from tkinter import messagebox from idlelib.config import idleConf from idlelib.textview import view_text @@ -147,7 +147,7 @@ def expand(self, event=None): if self.is_dangerous is None: self.set_is_dangerous() if self.is_dangerous: - confirm = tkMessageBox.askokcancel( + confirm = messagebox.askokcancel( title="Expand huge output?", message="\n\n".join([ "The squeezed output is very long: %d lines, %d chars.", @@ -155,7 +155,7 @@ def expand(self, event=None): "It is recommended to view or copy the output instead.", "Really expand?" ]) % (self.numoflines, len(self.s)), - default=tkMessageBox.CANCEL, + default=messagebox.CANCEL, parent=self.text) if not confirm: return "break" From f2df7958fb82cd927e17152b3a1bd2823a76dd3e Mon Sep 17 00:00:00 2001 From: Andrey Bienkowski Date: Mon, 25 Jan 2021 21:08:41 +0000 Subject: [PATCH 0903/1314] [3.9] bpo-42384: pdb: correctly populate sys.path[0] (GH-23338) (#24321) --- Lib/pdb.py | 3 +- Lib/test/test_pdb.py | 42 +++++++++++++++++++ .../2020-11-17-14-32-39.bpo-42384.1ZnQSn.rst | 1 + 3 files changed, 45 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Library/2020-11-17-14-32-39.bpo-42384.1ZnQSn.rst diff --git a/Lib/pdb.py b/Lib/pdb.py index d7d957159458be..7a5192cbadc3ad 100755 --- a/Lib/pdb.py +++ b/Lib/pdb.py @@ -1686,8 +1686,9 @@ def main(): sys.argv[:] = args # Hide "pdb.py" and pdb options from argument list - # Replace pdb's dir with script's dir in front of module search path. if not run_as_module: + mainpyfile = os.path.realpath(mainpyfile) + # Replace pdb's dir with script's dir in front of module search path. sys.path[0] = os.path.dirname(mainpyfile) # Note on saving/restoring sys.argv: it's a good idea when sys.argv was diff --git a/Lib/test/test_pdb.py b/Lib/test/test_pdb.py index 8016f81e5ac51b..e1a13cbaf3ef84 100644 --- a/Lib/test/test_pdb.py +++ b/Lib/test/test_pdb.py @@ -1661,6 +1661,48 @@ def test_errors_in_command(self): '(Pdb) ', ]) + + def test_issue42384(self): + '''When running `python foo.py` sys.path[0] is an absolute path. `python -m pdb foo.py` should behave the same''' + script = textwrap.dedent(""" + import sys + print('sys.path[0] is', sys.path[0]) + """) + commands = 'c\nq' + + with support.temp_cwd() as cwd: + expected = f'(Pdb) sys.path[0] is {os.path.realpath(cwd)}' + + stdout, stderr = self.run_pdb_script(script, commands) + + self.assertEqual(stdout.split('\n')[2].rstrip('\r'), expected) + + @support.skip_unless_symlink + def test_issue42384_symlink(self): + '''When running `python foo.py` sys.path[0] resolves symlinks. `python -m pdb foo.py` should behave the same''' + script = textwrap.dedent(""" + import sys + print('sys.path[0] is', sys.path[0]) + """) + commands = 'c\nq' + + with support.temp_cwd() as cwd: + cwd = os.path.realpath(cwd) + dir_one = os.path.join(cwd, 'dir_one') + dir_two = os.path.join(cwd, 'dir_two') + expected = f'(Pdb) sys.path[0] is {dir_one}' + + os.mkdir(dir_one) + with open(os.path.join(dir_one, 'foo.py'), 'w') as f: + f.write(script) + os.mkdir(dir_two) + os.symlink(os.path.join(dir_one, 'foo.py'), os.path.join(dir_two, 'foo.py')) + + stdout, stderr = self._run_pdb([os.path.join('dir_two', 'foo.py')], commands) + + self.assertEqual(stdout.split('\n')[2].rstrip('\r'), expected) + + def load_tests(*args): from test import test_pdb suites = [ diff --git a/Misc/NEWS.d/next/Library/2020-11-17-14-32-39.bpo-42384.1ZnQSn.rst b/Misc/NEWS.d/next/Library/2020-11-17-14-32-39.bpo-42384.1ZnQSn.rst new file mode 100644 index 00000000000000..ae990162fbab75 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2020-11-17-14-32-39.bpo-42384.1ZnQSn.rst @@ -0,0 +1 @@ +Make pdb populate sys.path[0] exactly the same as regular python execution. From f8cfe54e5a7082edcec74a34b3d7e6afab051afd Mon Sep 17 00:00:00 2001 From: Andrey Bienkowski Date: Tue, 26 Jan 2021 15:57:58 +0000 Subject: [PATCH 0904/1314] [3.9] bpo-42383: pdb: do not fail to restart the target if the current directory changed (GH-23412) (#24322) --- Lib/test/test_pdb.py | 23 +++++++++++++++++++ .../2020-11-17-14-30-12.bpo-42383.ubl0Y_.rst | 2 ++ 2 files changed, 25 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2020-11-17-14-30-12.bpo-42383.ubl0Y_.rst diff --git a/Lib/test/test_pdb.py b/Lib/test/test_pdb.py index e1a13cbaf3ef84..6c4eaf318e4480 100644 --- a/Lib/test/test_pdb.py +++ b/Lib/test/test_pdb.py @@ -1702,6 +1702,29 @@ def test_issue42384_symlink(self): self.assertEqual(stdout.split('\n')[2].rstrip('\r'), expected) + def test_issue42383(self): + with support.temp_cwd() as cwd: + with open('foo.py', 'w') as f: + s = textwrap.dedent(""" + print('The correct file was executed') + + import os + os.chdir("subdir") + """) + f.write(s) + + subdir = os.path.join(cwd, 'subdir') + os.mkdir(subdir) + os.mkdir(os.path.join(subdir, 'subdir')) + wrong_file = os.path.join(subdir, 'foo.py') + + with open(wrong_file, 'w') as f: + f.write('print("The wrong file was executed")') + + stdout, stderr = self._run_pdb(['foo.py'], 'c\nc\nq') + expected = '(Pdb) The correct file was executed' + self.assertEqual(stdout.split('\n')[6].rstrip('\r'), expected) + def load_tests(*args): from test import test_pdb diff --git a/Misc/NEWS.d/next/Library/2020-11-17-14-30-12.bpo-42383.ubl0Y_.rst b/Misc/NEWS.d/next/Library/2020-11-17-14-30-12.bpo-42383.ubl0Y_.rst new file mode 100644 index 00000000000000..ccf2106f28a93d --- /dev/null +++ b/Misc/NEWS.d/next/Library/2020-11-17-14-30-12.bpo-42383.ubl0Y_.rst @@ -0,0 +1,2 @@ +Fix pdb: previously pdb would fail to restart the debugging target if it was +specified using a relative path and the current directory changed. From fd668bc62b7f6de95448344b6650e1c3c2a997fa Mon Sep 17 00:00:00 2001 From: Terry Jan Reedy Date: Tue, 26 Jan 2021 13:59:18 -0500 Subject: [PATCH 0905/1314] [3.9] bpo-41841: Prepare IDLE NEWS for 3.9.2 (#GH-4343) --- Lib/idlelib/NEWS.txt | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/Lib/idlelib/NEWS.txt b/Lib/idlelib/NEWS.txt index 0033e66f9b8a26..f9b09ed25df7a3 100644 --- a/Lib/idlelib/NEWS.txt +++ b/Lib/idlelib/NEWS.txt @@ -1,5 +1,5 @@ -What's New in IDLE 3.9.1 -Released on 2020-12-07? +What's New in IDLE 3.9.2 +Released on 2021-02-15? ====================================== @@ -8,6 +8,11 @@ bpo-33065: Fix problem debugging user classes with __repr__ method. bpo-32631: Finish zzdummy example extension module: make menu entries work; add docstrings and tests with 100% coverage. + +What's New in IDLE 3.9.1 +Released on 2020-12-07 +====================================== + bpo-42508: Keep IDLE running on macOS. Remove obsolete workaround that prevented running files with shortcuts when using new universal2 installers built on macOS 11. From 68102fb9987338a70d69a0162917866e5710458d Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 26 Jan 2021 16:24:14 -0800 Subject: [PATCH 0906/1314] bpo-43008: Make IDLE respect sys.excepthook (GH-24302) Co-authored-by: Terry Jan Reedy (cherry picked from commit 7a34380ad788886f5ad50d4175ceb2d5715b8cff) Co-authored-by: Ken --- Doc/library/idle.rst | 2 +- Lib/idlelib/NEWS.txt | 3 ++ Lib/idlelib/idle_test/test_run.py | 43 +++++++++++++++++-- Lib/idlelib/run.py | 27 ++++++++---- .../2021-01-26-18-12-17.bpo-43008.mbQUc7.rst | 1 + 5 files changed, 63 insertions(+), 13 deletions(-) create mode 100644 Misc/NEWS.d/next/IDLE/2021-01-26-18-12-17.bpo-43008.mbQUc7.rst diff --git a/Doc/library/idle.rst b/Doc/library/idle.rst index a59a5d3a465703..e7eaabd8bfa25a 100644 --- a/Doc/library/idle.rst +++ b/Doc/library/idle.rst @@ -250,7 +250,7 @@ View Last Restart Scroll the shell window to the last Shell restart. Restart Shell - Restart the shell to clean the environment. + Restart the shell to clean the environment and reset display and exception handling. Previous History Cycle through earlier commands in history which match the current entry. diff --git a/Lib/idlelib/NEWS.txt b/Lib/idlelib/NEWS.txt index f9b09ed25df7a3..2c52295e4184f4 100644 --- a/Lib/idlelib/NEWS.txt +++ b/Lib/idlelib/NEWS.txt @@ -3,6 +3,9 @@ Released on 2021-02-15? ====================================== +bpo-43008: Make IDLE invoke :func:`sys.excepthook` in normal, +2-process mode. + bpo-33065: Fix problem debugging user classes with __repr__ method. bpo-32631: Finish zzdummy example extension module: make menu entries diff --git a/Lib/idlelib/idle_test/test_run.py b/Lib/idlelib/idle_test/test_run.py index 37c0d4525e56cd..a31671ee0485fa 100644 --- a/Lib/idlelib/idle_test/test_run.py +++ b/Lib/idlelib/idle_test/test_run.py @@ -1,16 +1,18 @@ "Test run, coverage 49%." from idlelib import run +import io +import sys +from test.support import captured_output, captured_stderr import unittest from unittest import mock +import idlelib from idlelib.idle_test.mock_idle import Func -from test.support import captured_output, captured_stderr -import io -import sys +idlelib.testing = True # Use {} for executing test user code. -class RunTest(unittest.TestCase): +class PrintExceptionTest(unittest.TestCase): def test_print_exception_unhashable(self): class UnhashableException(Exception): @@ -351,5 +353,38 @@ def test_fatal_error(self): self.assertIn('IndexError', msg) eq(func.called, 2) + +class ExecRuncodeTest(unittest.TestCase): + + @classmethod + def setUpClass(cls): + cls.addClassCleanup(setattr,run,'print_exception',run.print_exception) + cls.prt = Func() # Need reference. + run.print_exception = cls.prt + mockrpc = mock.Mock() + mockrpc.console.getvar = Func(result=False) + cls.ex = run.Executive(mockrpc) + + @classmethod + def tearDownClass(cls): + assert sys.excepthook == sys.__excepthook__ + + def test_exceptions(self): + ex = self.ex + ex.runcode('1/0') + self.assertIs(ex.user_exc_info[0], ZeroDivisionError) + + self.addCleanup(setattr, sys, 'excepthook', sys.__excepthook__) + sys.excepthook = lambda t, e, tb: run.print_exception(t) + ex.runcode('1/0') + self.assertIs(self.prt.args[0], ZeroDivisionError) + + sys.excepthook = lambda: None + ex.runcode('1/0') + t, e, tb = ex.user_exc_info + self.assertIs(t, TypeError) + self.assertTrue(isinstance(e.__context__, ZeroDivisionError)) + + if __name__ == '__main__': unittest.main(verbosity=2) diff --git a/Lib/idlelib/run.py b/Lib/idlelib/run.py index ec575c3d483631..07e9a2bf9ceeae 100644 --- a/Lib/idlelib/run.py +++ b/Lib/idlelib/run.py @@ -16,6 +16,7 @@ import threading import warnings +import idlelib # testing from idlelib import autocomplete # AutoComplete, fetch_encodings from idlelib import calltip # Calltip from idlelib import debugger_r # start_debugger @@ -542,14 +543,17 @@ class Executive: def __init__(self, rpchandler): self.rpchandler = rpchandler - self.locals = __main__.__dict__ - self.calltip = calltip.Calltip() - self.autocomplete = autocomplete.AutoComplete() + if idlelib.testing is False: + self.locals = __main__.__dict__ + self.calltip = calltip.Calltip() + self.autocomplete = autocomplete.AutoComplete() + else: + self.locals = {} def runcode(self, code): global interruptable try: - self.usr_exc_info = None + self.user_exc_info = None interruptable = True try: exec(code, self.locals) @@ -562,10 +566,17 @@ def runcode(self, code): print('SystemExit: ' + str(ob), file=sys.stderr) # Return to the interactive prompt. except: - self.usr_exc_info = sys.exc_info() + self.user_exc_info = sys.exc_info() # For testing, hook, viewer. if quitting: exit() - print_exception() + if sys.excepthook is sys.__excepthook__: + print_exception() + else: + try: + sys.excepthook(*self.user_exc_info) + except: + self.user_exc_info = sys.exc_info() # For testing. + print_exception() jit = self.rpchandler.console.getvar("<>") if jit: self.rpchandler.interp.open_remote_stack_viewer() @@ -590,8 +601,8 @@ def get_the_completion_list(self, what, mode): return self.autocomplete.fetch_completions(what, mode) def stackviewer(self, flist_oid=None): - if self.usr_exc_info: - typ, val, tb = self.usr_exc_info + if self.user_exc_info: + typ, val, tb = self.user_exc_info else: return None flist = None diff --git a/Misc/NEWS.d/next/IDLE/2021-01-26-18-12-17.bpo-43008.mbQUc7.rst b/Misc/NEWS.d/next/IDLE/2021-01-26-18-12-17.bpo-43008.mbQUc7.rst new file mode 100644 index 00000000000000..3e0b80a909d728 --- /dev/null +++ b/Misc/NEWS.d/next/IDLE/2021-01-26-18-12-17.bpo-43008.mbQUc7.rst @@ -0,0 +1 @@ +Make IDLE invoke :func:`sys.excepthook` in normal, 2-process mode. From cb77c5e1ddd9328e4706f8fdf893aa6bf697942c Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 27 Jan 2021 01:40:31 -0800 Subject: [PATCH 0907/1314] bpo-43033: Fix the handling of PyObject_SetAttrString() in _zoneinfo.c (GH-24345) (GH-24349) (cherry picked from commit 5327f370344a627f1578d8183d197feb286371c6) Co-authored-by: Zackery Spytz --- Modules/_zoneinfo.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Modules/_zoneinfo.c b/Modules/_zoneinfo.c index d87a20100a2218..0913860a4d4970 100644 --- a/Modules/_zoneinfo.c +++ b/Modules/_zoneinfo.c @@ -2530,7 +2530,11 @@ zoneinfo_init_subclass(PyTypeObject *cls, PyObject *args, PyObject **kwargs) return NULL; } - PyObject_SetAttrString((PyObject *)cls, "_weak_cache", weak_cache); + if (PyObject_SetAttrString((PyObject *)cls, "_weak_cache", + weak_cache) < 0) { + Py_DECREF(weak_cache); + return NULL; + } Py_DECREF(weak_cache); Py_RETURN_NONE; } From 895591c1f0bdec5ad357fe6a5fd0875990061357 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 27 Jan 2021 03:08:45 -0800 Subject: [PATCH 0908/1314] bpo-42979: _zoneinfo exec function checks for PyDateTime_IMPORT failure (GH-24333) (GH-24351) Importing datetime can fail. (cherry picked from commit eeb701adc0fc29ba803fddf133d917ff45639a00) Co-authored-by: Hai Shi Co-authored-by: Hai Shi --- Modules/_zoneinfo.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Modules/_zoneinfo.c b/Modules/_zoneinfo.c index 0913860a4d4970..0a4b38a6dc5ad7 100644 --- a/Modules/_zoneinfo.c +++ b/Modules/_zoneinfo.c @@ -2634,6 +2634,9 @@ static int zoneinfomodule_exec(PyObject *m) { PyDateTime_IMPORT; + if (PyDateTimeAPI == NULL) { + goto error; + } PyZoneInfo_ZoneInfoType.tp_base = PyDateTimeAPI->TZInfoType; if (PyType_Ready(&PyZoneInfo_ZoneInfoType) < 0) { goto error; From e9c6c26aff08e4c7bc6f1e8015cdd8edcc92dbef Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 28 Jan 2021 06:54:03 -0800 Subject: [PATCH 0909/1314] bpo-29076: Add fish support to macOS installer (GH-23302) (GH-23937) (cherry picked from commit 7f162e867c674f57c308a87fffcdcca3540c8933) Co-authored-by: Erlend Egeberg Aasland --- .../scripts/postflight.patch-profile | 18 +++++++++++++++++- .../2020-02-28-14-33-15.bpo-29076.Gtixi5.rst | 1 + 2 files changed, 18 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Build/2020-02-28-14-33-15.bpo-29076.Gtixi5.rst diff --git a/Mac/BuildScript/scripts/postflight.patch-profile b/Mac/BuildScript/scripts/postflight.patch-profile index 0a62e327f51b38..68b8e4bb044e10 100755 --- a/Mac/BuildScript/scripts/postflight.patch-profile +++ b/Mac/BuildScript/scripts/postflight.patch-profile @@ -20,7 +20,7 @@ fi # Make sure the directory ${PYTHON_ROOT}/bin is on the users PATH. BSH="`basename "${theShell}"`" case "${BSH}" in -bash|ksh|sh|*csh|zsh) +bash|ksh|sh|*csh|zsh|fish) if [ `id -ur` = 0 ]; then P=`su - ${USER} -c 'echo A-X-4-X@@$PATH@@X-4-X-A' | grep 'A-X-4-X@@.*@@X-4-X-A' | sed -e 's/^A-X-4-X@@//g' -e 's/@@X-4-X-A$//g'` else @@ -76,6 +76,22 @@ bash) PR="${HOME}/.bash_profile" fi ;; +fish) + CONFIG_DIR="${HOME}/.config/fish" + RC="${CONFIG_DIR}/config.fish" + mkdir -p "$CONFIG_DIR" + if [ -f "${RC}" ]; then + cp -fp "${RC}" "${RC}.pysave" + fi + echo "" >> "${RC}" + echo "# Setting PATH for Python ${PYVER}" >> "${RC}" + echo "# The original version is saved in ${RC}.pysave" >> "${RC}" + echo "set -x PATH \"${PYTHON_ROOT}/bin\" \"\$PATH\"" >> "${RC}" + if [ `id -ur` = 0 ]; then + chown "${USER}" "${RC}" + fi + exit 0 + ;; zsh) PR="${HOME}/.zprofile" ;; diff --git a/Misc/NEWS.d/next/Build/2020-02-28-14-33-15.bpo-29076.Gtixi5.rst b/Misc/NEWS.d/next/Build/2020-02-28-14-33-15.bpo-29076.Gtixi5.rst new file mode 100644 index 00000000000000..b38beb0586951c --- /dev/null +++ b/Misc/NEWS.d/next/Build/2020-02-28-14-33-15.bpo-29076.Gtixi5.rst @@ -0,0 +1 @@ +Add fish shell support to macOS installer. From 6d87dec5818667168cc7e4ad972dde8aeec6d900 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 28 Jan 2021 15:38:19 -0800 Subject: [PATCH 0910/1314] bpo-23544: Disable IDLE Stack Viewer when running user code (GH-17163) Starting stack viewer when user code is running, including when Debugger is active, hangs or crashes IDLE. Co-authored-by: Terry Jan Reedy (cherry picked from commit 23a567c11ca36eedde0e119443c85cc16075deaf) Co-authored-by: Zackery Spytz --- Lib/idlelib/NEWS.txt | 3 +++ Lib/idlelib/codecontext.py | 2 +- Lib/idlelib/editor.py | 10 +++++---- Lib/idlelib/idle_test/test_mainmenu.py | 21 +++++++++++++++++++ Lib/idlelib/pyshell.py | 4 ++++ .../2019-11-14-23-41-07.bpo-23544.3etemb.rst | 2 ++ 6 files changed, 37 insertions(+), 5 deletions(-) create mode 100644 Misc/NEWS.d/next/IDLE/2019-11-14-23-41-07.bpo-23544.3etemb.rst diff --git a/Lib/idlelib/NEWS.txt b/Lib/idlelib/NEWS.txt index 2c52295e4184f4..e7d2f16e7a5a6d 100644 --- a/Lib/idlelib/NEWS.txt +++ b/Lib/idlelib/NEWS.txt @@ -3,6 +3,9 @@ Released on 2021-02-15? ====================================== +bpo-23544: Disable Debug=>Stack Viewer when user code is running or +Debugger is active, to prevent hang or crash. Patch by Zackery Spytz. + bpo-43008: Make IDLE invoke :func:`sys.excepthook` in normal, 2-process mode. diff --git a/Lib/idlelib/codecontext.py b/Lib/idlelib/codecontext.py index eb19773f56e34b..f2f44f5f8d4e61 100644 --- a/Lib/idlelib/codecontext.py +++ b/Lib/idlelib/codecontext.py @@ -142,7 +142,7 @@ def toggle_code_context_event(self, event=None): self.text.after_cancel(self.t1) self._reset() menu_status = 'Show' - self.editwin.update_menu_label(menu='options', index='* Code Context', + self.editwin.update_menu_label(menu='options', index='*ode*ontext', label=f'{menu_status} Code Context') return "break" diff --git a/Lib/idlelib/editor.py b/Lib/idlelib/editor.py index 66e9da5a9dccf9..b9cb50264ff06f 100644 --- a/Lib/idlelib/editor.py +++ b/Lib/idlelib/editor.py @@ -339,7 +339,7 @@ def __init__(self, flist=None, filename=None, key=None, root=None): text.bind("<>", self.code_context.toggle_code_context_event) else: - self.update_menu_state('options', '*Code Context', 'disabled') + self.update_menu_state('options', '*ode*ontext', 'disabled') if self.allow_line_numbers: self.line_numbers = self.LineNumbers(self) if idleConf.GetOption('main', 'EditorWindow', @@ -347,7 +347,7 @@ def __init__(self, flist=None, filename=None, key=None, root=None): self.toggle_line_numbers_event() text.bind("<>", self.toggle_line_numbers_event) else: - self.update_menu_state('options', '*Line Numbers', 'disabled') + self.update_menu_state('options', '*ine*umbers', 'disabled') def handle_winconfig(self, event=None): self.set_width() @@ -450,7 +450,9 @@ def createmenubar(self): self.menudict = menudict = {} for name, label in self.menu_specs: underline, label = prepstr(label) - menudict[name] = menu = Menu(mbar, name=name, tearoff=0) + postcommand = getattr(self, f'{name}_menu_postcommand', None) + menudict[name] = menu = Menu(mbar, name=name, tearoff=0, + postcommand=postcommand) mbar.add_cascade(label=label, menu=menu, underline=underline) if macosx.isCarbonTk(): # Insert the application menu @@ -1527,7 +1529,7 @@ def toggle_line_numbers_event(self, event=None): else: self.line_numbers.show_sidebar() menu_label = "Hide" - self.update_menu_label(menu='options', index='*Line Numbers', + self.update_menu_label(menu='options', index='*ine*umbers', label=f'{menu_label} Line Numbers') # "line.col" -> line, as an int diff --git a/Lib/idlelib/idle_test/test_mainmenu.py b/Lib/idlelib/idle_test/test_mainmenu.py index 7ec0368371c7df..51d2accfe48a1c 100644 --- a/Lib/idlelib/idle_test/test_mainmenu.py +++ b/Lib/idlelib/idle_test/test_mainmenu.py @@ -2,6 +2,7 @@ # Reported as 88%; mocking turtledemo absence would have no point. from idlelib import mainmenu +import re import unittest @@ -16,6 +17,26 @@ def test_menudefs(self): def test_default_keydefs(self): self.assertGreaterEqual(len(mainmenu.default_keydefs), 50) + def test_tcl_indexes(self): + # Test tcl patterns used to find menuitem to alter. + # On failure, change pattern here and in function(s). + # Patterns here have '.*' for re instead of '*' for tcl. + for menu, pattern in ( + ('debug', '.*tack.*iewer'), # PyShell.debug_menu_postcommand + ('options', '.*ode.*ontext'), # EW.__init__, CodeContext.toggle... + ('options', '.*ine.*umbers'), # EW.__init__, EW.toggle...event. + ): + with self.subTest(menu=menu, pattern=pattern): + for menutup in mainmenu.menudefs: + if menutup[0] == menu: + break + else: + self.assertTrue(0, f"{menu} not in menudefs") + self.assertTrue(any(re.search(pattern, menuitem[0]) + for menuitem in menutup[1] + if menuitem is not None), # Separator. + f"{pattern} not in {menu}") + if __name__ == '__main__': unittest.main(verbosity=2) diff --git a/Lib/idlelib/pyshell.py b/Lib/idlelib/pyshell.py index d32106c9838744..fea3762461e99e 100755 --- a/Lib/idlelib/pyshell.py +++ b/Lib/idlelib/pyshell.py @@ -989,6 +989,10 @@ def open_debugger(self): self.showprompt() self.set_debugger_indicator() + def debug_menu_postcommand(self): + state = 'disabled' if self.executing else 'normal' + self.update_menu_state('debug', '*tack*iewer', state) + def beginexecuting(self): "Helper for ModifiedInterpreter" self.resetoutput() diff --git a/Misc/NEWS.d/next/IDLE/2019-11-14-23-41-07.bpo-23544.3etemb.rst b/Misc/NEWS.d/next/IDLE/2019-11-14-23-41-07.bpo-23544.3etemb.rst new file mode 100644 index 00000000000000..eb4a56bf100b59 --- /dev/null +++ b/Misc/NEWS.d/next/IDLE/2019-11-14-23-41-07.bpo-23544.3etemb.rst @@ -0,0 +1,2 @@ +Disable Debug=>Stack Viewer when user code is running or Debugger +is active, to prevent hang or crash. Patch by Zackery Spytz. From bf782b2636880dd634281f905ae43b8555450ee2 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 29 Jan 2021 10:51:46 -0800 Subject: [PATCH 0911/1314] bpo-43008: Add 'Patch by Ken Hilton' (GH-24370) (#24374) (cherry picked from commit 11d75ec807f05eff1148c049e38b808d11c23b8a) Co-authored-by: Terry Jan Reedy --- Lib/idlelib/NEWS.txt | 2 +- Misc/NEWS.d/next/IDLE/2021-01-26-18-12-17.bpo-43008.mbQUc7.rst | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/Lib/idlelib/NEWS.txt b/Lib/idlelib/NEWS.txt index e7d2f16e7a5a6d..4bc4aefd1ac352 100644 --- a/Lib/idlelib/NEWS.txt +++ b/Lib/idlelib/NEWS.txt @@ -7,7 +7,7 @@ bpo-23544: Disable Debug=>Stack Viewer when user code is running or Debugger is active, to prevent hang or crash. Patch by Zackery Spytz. bpo-43008: Make IDLE invoke :func:`sys.excepthook` in normal, -2-process mode. +2-process mode. Patch by Ken Hilton. bpo-33065: Fix problem debugging user classes with __repr__ method. diff --git a/Misc/NEWS.d/next/IDLE/2021-01-26-18-12-17.bpo-43008.mbQUc7.rst b/Misc/NEWS.d/next/IDLE/2021-01-26-18-12-17.bpo-43008.mbQUc7.rst index 3e0b80a909d728..55ab67ca94959a 100644 --- a/Misc/NEWS.d/next/IDLE/2021-01-26-18-12-17.bpo-43008.mbQUc7.rst +++ b/Misc/NEWS.d/next/IDLE/2021-01-26-18-12-17.bpo-43008.mbQUc7.rst @@ -1 +1,2 @@ Make IDLE invoke :func:`sys.excepthook` in normal, 2-process mode. +Patch by Ken Hilton. From 44cd24452a03fd7c851293aaaff9b7ee47060ea0 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 29 Jan 2021 13:38:16 -0800 Subject: [PATCH 0912/1314] Fixed typo in turtle.rst (GH-24371) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Found it while translating it to french 🤷 Automerge-Triggered-By: GH:JulienPalard (cherry picked from commit 6372a4ceba126aa0a9f00eee0f8023308f13e77b) Co-authored-by: Jules Lasne --- Doc/library/turtle.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/turtle.rst b/Doc/library/turtle.rst index 2084d75b3a57a0..7bd7e966109124 100644 --- a/Doc/library/turtle.rst +++ b/Doc/library/turtle.rst @@ -662,7 +662,7 @@ Tell Turtle's state Return the angle between the line from turtle position to position specified by (x,y), the vector or the other turtle. This depends on the turtle's start - orientation which depends on the mode - "standard"/"world" or "logo"). + orientation which depends on the mode - "standard"/"world" or "logo". .. doctest:: :skipif: _tkinter is None From d34be1ed57bf99298f1b7f9d7259d25019a29cb2 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 29 Jan 2021 14:03:18 -0800 Subject: [PATCH 0913/1314] Fixing typos in turtle.rst (GH-24376) Automerge-Triggered-By: GH:JulienPalard (cherry picked from commit 6baaae589d596ed3bb668448f2a22c5f62fc5fdf) Co-authored-by: Jules Lasne --- Doc/library/turtle.rst | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Doc/library/turtle.rst b/Doc/library/turtle.rst index 7bd7e966109124..6a9d61916ad1a5 100644 --- a/Doc/library/turtle.rst +++ b/Doc/library/turtle.rst @@ -1105,7 +1105,7 @@ More drawing control :param font: a triple (fontname, fontsize, fonttype) Write text - the string representation of *arg* - at the current turtle - position according to *align* ("left", "center" or right") and with the given + position according to *align* ("left", "center" or "right") and with the given font. If *move* is true, the pen is moved to the bottom-right corner of the text. By default, *move* is ``False``. @@ -1192,7 +1192,7 @@ Appearance :func:`shapesize`. - "noresize": no adaption of the turtle's appearance takes place. - resizemode("user") is called by :func:`shapesize` when used with arguments. + ``resizemode("user")`` is called by :func:`shapesize` when used with arguments. .. doctest:: :skipif: _tkinter is None @@ -1330,7 +1330,7 @@ Appearance matrix as a tuple of 4 elements. Otherwise set the given elements and transform the turtleshape according to the matrix consisting of first row t11, t12 and - second row t21, 22. The determinant t11 * t22 - t12 * t21 must not be + second row t21, t22. The determinant t11 * t22 - t12 * t21 must not be zero, otherwise an error is raised. Modify stretchfactor, shearfactor and tiltangle according to the given matrix. @@ -1513,7 +1513,7 @@ Special Turtle methods :param size: an integer or ``None`` - Set or disable undobuffer. If *size* is an integer an empty undobuffer of + Set or disable undobuffer. If *size* is an integer, an empty undobuffer of given size is installed. *size* gives the maximum number of turtle actions that can be undone by the :func:`undo` method/function. If *size* is ``None``, the undobuffer is disabled. @@ -1821,7 +1821,7 @@ Using screen events existing bindings are removed. Example for a TurtleScreen instance named ``screen`` and a Turtle instance - named turtle: + named ``turtle``: .. doctest:: :skipif: _tkinter is None @@ -2048,7 +2048,7 @@ Methods specific to Screen, not inherited from TurtleScreen .. function:: exitonclick() - Bind bye() method to mouse clicks on the Screen. + Bind ``bye()`` method to mouse clicks on the Screen. If the value "using_IDLE" in the configuration dictionary is ``False`` From 08867a0bfc756b40b1d889b4edccc8137a291e81 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 30 Jan 2021 02:38:44 -0800 Subject: [PATCH 0914/1314] [doc] Document VIRTUAL_ENV environment variable (GH-21970) (cherry picked from commit 3584d4b64a5373440f78237eac734831cfd83f79) Co-authored-by: Andre Delfino --- Doc/using/venv-create.inc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Doc/using/venv-create.inc b/Doc/using/venv-create.inc index 5e724cd5794ce4..ddb36f94667d9f 100644 --- a/Doc/using/venv-create.inc +++ b/Doc/using/venv-create.inc @@ -126,6 +126,10 @@ directory containing the virtual environment): | | PowerShell | PS C:\\> \\Scripts\\Activate.ps1 | +-------------+-----------------+-----------------------------------------+ +When a virtual environment is active, the :envvar:`VIRTUAL_ENV` environment +variable is set to the path of the virtual environment. This can be used to +check if one is running inside a virtual environment. + You don't specifically *need* to activate an environment; activation just prepends the virtual environment's binary directory to your path, so that "python" invokes the virtual environment's Python interpreter and you can run From 926ca51be4b9b80c41a647bbc2fb9c40ff108ff0 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 30 Jan 2021 21:21:28 -0800 Subject: [PATCH 0915/1314] bpo-43059: Remove reference to legacy external sqlite3 repository (GH-24364) (cherry picked from commit e60344364245a23a7a1b25d5ebce6833652a656c) Co-authored-by: L <3177243+LukeLR@users.noreply.github.com> --- Doc/library/sqlite3.rst | 4 ---- 1 file changed, 4 deletions(-) diff --git a/Doc/library/sqlite3.rst b/Doc/library/sqlite3.rst index 7dc2cc48c47538..2e2e5e9cdae377 100644 --- a/Doc/library/sqlite3.rst +++ b/Doc/library/sqlite3.rst @@ -99,10 +99,6 @@ This example uses the iterator form:: .. seealso:: - https://github.com/ghaering/pysqlite - The pysqlite web page -- sqlite3 is developed externally under the name - "pysqlite". - https://www.sqlite.org The SQLite web page; the documentation describes the syntax and the available data types for the supported SQL dialect. From 995a6c015024f050b99ba8f9837dfc6b82d83f7d Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 31 Jan 2021 06:20:14 -0800 Subject: [PATCH 0916/1314] bpo-43030: Fixed a compiler warning in Py_UNICODE_ISSPACE with signed wchar_t (GH-24350) (cherry picked from commit 42b1806af90b86ec393ca7da14e99ce95ec6c53b) Co-authored-by: Serhiy Storchaka --- Include/cpython/unicodeobject.h | 2 +- Misc/NEWS.d/next/C API/2021-01-27-10-27-47.bpo-43030.loDcD_.rst | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/C API/2021-01-27-10-27-47.bpo-43030.loDcD_.rst diff --git a/Include/cpython/unicodeobject.h b/Include/cpython/unicodeobject.h index 1fc732abeb5553..503b079db275a5 100644 --- a/Include/cpython/unicodeobject.h +++ b/Include/cpython/unicodeobject.h @@ -22,7 +22,7 @@ extern "C" { */ #define Py_UNICODE_ISSPACE(ch) \ - ((ch) < 128U ? _Py_ascii_whitespace[(ch)] : _PyUnicode_IsWhitespace(ch)) + ((Py_UCS4)(ch) < 128U ? _Py_ascii_whitespace[(ch)] : _PyUnicode_IsWhitespace(ch)) #define Py_UNICODE_ISLOWER(ch) _PyUnicode_IsLowercase(ch) #define Py_UNICODE_ISUPPER(ch) _PyUnicode_IsUppercase(ch) diff --git a/Misc/NEWS.d/next/C API/2021-01-27-10-27-47.bpo-43030.loDcD_.rst b/Misc/NEWS.d/next/C API/2021-01-27-10-27-47.bpo-43030.loDcD_.rst new file mode 100644 index 00000000000000..7a432522db8a12 --- /dev/null +++ b/Misc/NEWS.d/next/C API/2021-01-27-10-27-47.bpo-43030.loDcD_.rst @@ -0,0 +1,2 @@ +Fixed a compiler warning in :c:func:`Py_UNICODE_ISSPACE()` on platforms with +signed ``wchar_t``. From 8a833a6f94d8c2baa6aa38abd9fc699881a5b0e1 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 31 Jan 2021 08:06:15 -0800 Subject: [PATCH 0917/1314] bpo-43083: Fix error handling in _sqlite3 (GH-24395) (cherry picked from commit 9073180db521dc83e6216ff0da1479d00167f643) Co-authored-by: Serhiy Storchaka --- Modules/_sqlite/connection.c | 6 +++++- Modules/_sqlite/cursor.c | 20 ++++++++++++++------ 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/Modules/_sqlite/connection.c b/Modules/_sqlite/connection.c index b80037347f13b5..d20339ca3f7dfd 100644 --- a/Modules/_sqlite/connection.c +++ b/Modules/_sqlite/connection.c @@ -1704,7 +1704,11 @@ pysqlite_connection_create_collation(pysqlite_Connection* self, PyObject* args) (callable != Py_None) ? callable : NULL, (callable != Py_None) ? pysqlite_collation_callback : NULL); if (rc != SQLITE_OK) { - PyDict_DelItem(self->collations, uppercase_name); + if (callable != Py_None) { + if (PyDict_DelItem(self->collations, uppercase_name) < 0) { + PyErr_Clear(); + } + } _pysqlite_seterror(self->db, NULL); goto finally; } diff --git a/Modules/_sqlite/cursor.c b/Modules/_sqlite/cursor.c index 5cfb4b97d61dfe..dd0ce7e1ea6a33 100644 --- a/Modules/_sqlite/cursor.c +++ b/Modules/_sqlite/cursor.c @@ -569,11 +569,13 @@ _pysqlite_query_execute(pysqlite_Cursor* self, int multiple, PyObject* args) } if (!multiple) { - Py_DECREF(self->lastrowid); Py_BEGIN_ALLOW_THREADS lastrowid = sqlite3_last_insert_rowid(self->connection->db); Py_END_ALLOW_THREADS - self->lastrowid = PyLong_FromLongLong(lastrowid); + Py_SETREF(self->lastrowid, PyLong_FromLongLong(lastrowid)); + if (self->lastrowid == NULL) { + goto error; + } } if (rc == SQLITE_ROW) { @@ -802,8 +804,11 @@ PyObject* pysqlite_cursor_fetchmany(pysqlite_Cursor* self, PyObject* args, PyObj } while ((row = pysqlite_cursor_iternext(self))) { - PyList_Append(list, row); - Py_XDECREF(row); + if (PyList_Append(list, row) < 0) { + Py_DECREF(row); + break; + } + Py_DECREF(row); if (++counter == maxrows) { break; @@ -829,8 +834,11 @@ PyObject* pysqlite_cursor_fetchall(pysqlite_Cursor* self, PyObject* args) } while ((row = pysqlite_cursor_iternext(self))) { - PyList_Append(list, row); - Py_XDECREF(row); + if (PyList_Append(list, row) < 0) { + Py_DECREF(row); + break; + } + Py_DECREF(row); } if (PyErr_Occurred()) { From e9d4960d15c5282904cf26e469ce7cee39f634f7 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sun, 31 Jan 2021 18:11:13 +0200 Subject: [PATCH 0918/1314] [3.9] bpo-43016: Rewrite tests for curses (GH-24312). (GH-24399) (cherry picked from commit d64fd4bb5bb4fd2e3277f39d3ad99b5a8d193e1b) --- Lib/test/test_curses.py | 997 +++++++++++++++++++++++++++++++--------- 1 file changed, 783 insertions(+), 214 deletions(-) diff --git a/Lib/test/test_curses.py b/Lib/test/test_curses.py index de9f301737d8ca..f5287e0143fcbf 100644 --- a/Lib/test/test_curses.py +++ b/Lib/test/test_curses.py @@ -1,18 +1,9 @@ -# -# Test script for the curses module -# -# This script doesn't actually display anything very coherent. but it -# does call (nearly) every method and function. -# -# Functions not tested: {def,reset}_{shell,prog}_mode, getch(), getstr() -# Only called, not tested: getmouse(), ungetmouse() -# - +import functools +import inspect import os import string import sys import tempfile -import functools import unittest from test.support import requires, import_module, verbose, SaveSignals @@ -20,7 +11,6 @@ # Optionally test curses module. This currently requires that the # 'curses' resource be given on the regrtest command line using the -u # option. If not available, nothing after this line will be executed. -import inspect requires('curses') # If either of these don't exist, skip the tests. @@ -36,6 +26,17 @@ def requires_curses_func(name): return unittest.skipUnless(hasattr(curses, name), 'requires curses.%s' % name) +def requires_curses_window_meth(name): + def deco(test): + @functools.wraps(test) + def wrapped(self, *args, **kwargs): + if not hasattr(self.stdscr, name): + raise unittest.SkipTest('requires curses.window.%s' % name) + test(self, *args, **kwargs) + return wrapped + return deco + + def requires_colors(test): @functools.wraps(test) def wrapped(self, *args, **kwargs): @@ -110,212 +111,732 @@ def setUp(self): curses.savetty() self.addCleanup(curses.endwin) self.addCleanup(curses.resetty) + self.stdscr.erase() + + @requires_curses_func('filter') + def test_filter(self): + # TODO: Should be called before initscr() or newterm() are called. + # TODO: nofilter() + curses.filter() + + @requires_curses_func('use_env') + def test_use_env(self): + # TODO: Should be called before initscr() or newterm() are called. + # TODO: use_tioctl() + curses.use_env(False) + curses.use_env(True) + + def test_create_windows(self): + win = curses.newwin(5, 10) + self.assertEqual(win.getbegyx(), (0, 0)) + self.assertEqual(win.getparyx(), (-1, -1)) + self.assertEqual(win.getmaxyx(), (5, 10)) + + win = curses.newwin(10, 15, 2, 5) + self.assertEqual(win.getbegyx(), (2, 5)) + self.assertEqual(win.getparyx(), (-1, -1)) + self.assertEqual(win.getmaxyx(), (10, 15)) + + win2 = win.subwin(3, 7) + self.assertEqual(win2.getbegyx(), (3, 7)) + self.assertEqual(win2.getparyx(), (1, 2)) + self.assertEqual(win2.getmaxyx(), (9, 13)) + + win2 = win.subwin(5, 10, 3, 7) + self.assertEqual(win2.getbegyx(), (3, 7)) + self.assertEqual(win2.getparyx(), (1, 2)) + self.assertEqual(win2.getmaxyx(), (5, 10)) + + win3 = win.derwin(2, 3) + self.assertEqual(win3.getbegyx(), (4, 8)) + self.assertEqual(win3.getparyx(), (2, 3)) + self.assertEqual(win3.getmaxyx(), (8, 12)) + + win3 = win.derwin(6, 11, 2, 3) + self.assertEqual(win3.getbegyx(), (4, 8)) + self.assertEqual(win3.getparyx(), (2, 3)) + self.assertEqual(win3.getmaxyx(), (6, 11)) + + win.mvwin(0, 1) + self.assertEqual(win.getbegyx(), (0, 1)) + self.assertEqual(win.getparyx(), (-1, -1)) + self.assertEqual(win.getmaxyx(), (10, 15)) + self.assertEqual(win2.getbegyx(), (3, 7)) + self.assertEqual(win2.getparyx(), (1, 2)) + self.assertEqual(win2.getmaxyx(), (5, 10)) + self.assertEqual(win3.getbegyx(), (4, 8)) + self.assertEqual(win3.getparyx(), (2, 3)) + self.assertEqual(win3.getmaxyx(), (6, 11)) + + win2.mvderwin(2, 1) + self.assertEqual(win2.getbegyx(), (3, 7)) + self.assertEqual(win2.getparyx(), (2, 1)) + self.assertEqual(win2.getmaxyx(), (5, 10)) + + win3.mvderwin(2, 1) + self.assertEqual(win3.getbegyx(), (4, 8)) + self.assertEqual(win3.getparyx(), (2, 1)) + self.assertEqual(win3.getmaxyx(), (6, 11)) + + def test_move_cursor(self): + stdscr = self.stdscr + win = stdscr.subwin(10, 15, 2, 5) + stdscr.move(1, 2) + win.move(2, 4) + self.assertEqual(stdscr.getyx(), (1, 2)) + self.assertEqual(win.getyx(), (2, 4)) + + win.cursyncup() + self.assertEqual(stdscr.getyx(), (4, 9)) - def test_window_funcs(self): - "Test the methods of windows" + def test_refresh_control(self): stdscr = self.stdscr - win = curses.newwin(10,10) - win = curses.newwin(5,5, 5,5) - win2 = curses.newwin(15,15, 5,5) - - for meth in [stdscr.addch, stdscr.addstr]: - for args in [('a',), ('a', curses.A_BOLD), - (4,4, 'a'), (5,5, 'a', curses.A_BOLD)]: - with self.subTest(meth=meth.__qualname__, args=args): - meth(*args) - - for meth in [stdscr.clear, stdscr.clrtobot, - stdscr.clrtoeol, stdscr.cursyncup, stdscr.delch, - stdscr.deleteln, stdscr.erase, stdscr.getbegyx, - stdscr.getbkgd, stdscr.getmaxyx, - stdscr.getparyx, stdscr.getyx, stdscr.inch, - stdscr.insertln, stdscr.instr, stdscr.is_wintouched, - win.noutrefresh, stdscr.redrawwin, stdscr.refresh, - stdscr.standout, stdscr.standend, stdscr.syncdown, - stdscr.syncup, stdscr.touchwin, stdscr.untouchwin]: - with self.subTest(meth=meth.__qualname__): - meth() - - stdscr.addnstr('1234', 3) - stdscr.addnstr('1234', 3, curses.A_BOLD) - stdscr.addnstr(4,4, '1234', 3) - stdscr.addnstr(5,5, '1234', 3, curses.A_BOLD) - - stdscr.attron(curses.A_BOLD) - stdscr.attroff(curses.A_BOLD) - stdscr.attrset(curses.A_BOLD) - stdscr.bkgd(' ') - stdscr.bkgd(' ', curses.A_REVERSE) - stdscr.bkgdset(' ') - stdscr.bkgdset(' ', curses.A_REVERSE) + # touchwin()/untouchwin()/is_wintouched() + stdscr.refresh() + self.assertIs(stdscr.is_wintouched(), False) + stdscr.touchwin() + self.assertIs(stdscr.is_wintouched(), True) + stdscr.refresh() + self.assertIs(stdscr.is_wintouched(), False) + stdscr.touchwin() + self.assertIs(stdscr.is_wintouched(), True) + stdscr.untouchwin() + self.assertIs(stdscr.is_wintouched(), False) + + # touchline()/untouchline()/is_linetouched() + stdscr.touchline(5, 2) + self.assertIs(stdscr.is_linetouched(5), True) + self.assertIs(stdscr.is_linetouched(6), True) + self.assertIs(stdscr.is_wintouched(), True) + stdscr.touchline(5, 1, False) + self.assertIs(stdscr.is_linetouched(5), False) + + # syncup() + win = stdscr.subwin(10, 15, 2, 5) + win2 = win.subwin(5, 10, 3, 7) + win2.touchwin() + stdscr.untouchwin() + win2.syncup() + self.assertIs(win.is_wintouched(), True) + self.assertIs(stdscr.is_wintouched(), True) + + # syncdown() + stdscr.touchwin() + win.untouchwin() + win2.untouchwin() + win2.syncdown() + self.assertIs(win2.is_wintouched(), True) + + # syncok() + if hasattr(stdscr, 'syncok') and not sys.platform.startswith("sunos"): + win.untouchwin() + stdscr.untouchwin() + for syncok in [False, True]: + win2.syncok(syncok) + win2.addch('a') + self.assertIs(win.is_wintouched(), syncok) + self.assertIs(stdscr.is_wintouched(), syncok) + + def test_output_character(self): + stdscr = self.stdscr + # addch() + stdscr.refresh() + stdscr.move(0, 0) + stdscr.addch('A') + stdscr.addch(b'A') + stdscr.addch(65) + stdscr.addch('\u20ac') + stdscr.addch('A', curses.A_BOLD) + stdscr.addch(1, 2, 'A') + stdscr.addch(2, 3, 'A', curses.A_BOLD) + self.assertIs(stdscr.is_wintouched(), True) + + # echochar() + stdscr.refresh() + stdscr.move(0, 0) + stdscr.echochar('A') + stdscr.echochar(b'A') + stdscr.echochar(65) + self.assertRaises(OverflowError, stdscr.echochar, '\u20ac') + stdscr.echochar('A', curses.A_BOLD) + self.assertIs(stdscr.is_wintouched(), False) + + def test_output_string(self): + stdscr = self.stdscr + # addstr()/insstr() + for func in [stdscr.addstr, stdscr.insstr]: + with self.subTest(func.__qualname__): + stdscr.move(0, 0) + func('abcd') + func(b'abcd') + func('àßçđ') + func('abcd', curses.A_BOLD) + func(1, 2, 'abcd') + func(2, 3, 'abcd', curses.A_BOLD) + + # addnstr()/insnstr() + for func in [stdscr.addnstr, stdscr.insnstr]: + with self.subTest(func.__qualname__): + stdscr.move(0, 0) + func('1234', 3) + func(b'1234', 3) + func('\u0661\u0662\u0663\u0664', 3) + func('1234', 5) + func('1234', 3, curses.A_BOLD) + func(1, 2, '1234', 3) + func(2, 3, '1234', 3, curses.A_BOLD) + + def test_output_string_embedded_null_chars(self): + # reject embedded null bytes and characters + stdscr = self.stdscr + for arg in ['a\0', b'a\0']: + with self.subTest(arg=arg): + self.assertRaises(ValueError, stdscr.addstr, arg) + self.assertRaises(ValueError, stdscr.addnstr, arg, 1) + self.assertRaises(ValueError, stdscr.insstr, arg) + self.assertRaises(ValueError, stdscr.insnstr, arg, 1) - win.border(65, 66, 67, 68, - 69, 70, 71, 72) + def test_read_from_window(self): + stdscr = self.stdscr + stdscr.addstr(0, 1, 'ABCD', curses.A_BOLD) + # inch() + stdscr.move(0, 1) + self.assertEqual(stdscr.inch(), 65 | curses.A_BOLD) + self.assertEqual(stdscr.inch(0, 3), 67 | curses.A_BOLD) + stdscr.move(0, 0) + # instr() + self.assertEqual(stdscr.instr()[:6], b' ABCD ') + self.assertEqual(stdscr.instr(3)[:6], b' AB') + self.assertEqual(stdscr.instr(0, 2)[:4], b'BCD ') + self.assertEqual(stdscr.instr(0, 2, 4), b'BCD ') + self.assertRaises(ValueError, stdscr.instr, -2) + self.assertRaises(ValueError, stdscr.instr, 0, 2, -2) + + def test_getch(self): + win = curses.newwin(5, 12, 5, 2) + + # TODO: Test with real input by writing to master fd. + for c in 'spam\n'[::-1]: + curses.ungetch(c) + self.assertEqual(win.getch(3, 1), b's'[0]) + self.assertEqual(win.getyx(), (3, 1)) + self.assertEqual(win.getch(3, 4), b'p'[0]) + self.assertEqual(win.getyx(), (3, 4)) + self.assertEqual(win.getch(), b'a'[0]) + self.assertEqual(win.getyx(), (3, 4)) + self.assertEqual(win.getch(), b'm'[0]) + self.assertEqual(win.getch(), b'\n'[0]) + + def test_getstr(self): + win = curses.newwin(5, 12, 5, 2) + curses.echo() + self.addCleanup(curses.noecho) + + self.assertRaises(ValueError, win.getstr, -400) + self.assertRaises(ValueError, win.getstr, 2, 3, -400) + + # TODO: Test with real input by writing to master fd. + for c in 'Lorem\nipsum\ndolor\nsit\namet\n'[::-1]: + curses.ungetch(c) + self.assertEqual(win.getstr(3, 1, 2), b'Lo') + self.assertEqual(win.instr(3, 0), b' Lo ') + self.assertEqual(win.getstr(3, 5, 10), b'ipsum') + self.assertEqual(win.instr(3, 0), b' Lo ipsum ') + self.assertEqual(win.getstr(1, 5), b'dolor') + self.assertEqual(win.instr(1, 0), b' dolor ') + self.assertEqual(win.getstr(2), b'si') + self.assertEqual(win.instr(1, 0), b'si dolor ') + self.assertEqual(win.getstr(), b'amet') + self.assertEqual(win.instr(1, 0), b'amet dolor ') + + def test_clear(self): + win = curses.newwin(5, 15, 5, 2) + lorem_ipsum(win) + + win.move(0, 8) + win.clrtoeol() + self.assertEqual(win.instr(0, 0).rstrip(), b'Lorem ip') + self.assertEqual(win.instr(1, 0).rstrip(), b'dolor sit amet,') + + win.move(0, 3) + win.clrtobot() + self.assertEqual(win.instr(0, 0).rstrip(), b'Lor') + self.assertEqual(win.instr(1, 0).rstrip(), b'') + + for func in [win.erase, win.clear]: + lorem_ipsum(win) + func() + self.assertEqual(win.instr(0, 0).rstrip(), b'') + self.assertEqual(win.instr(1, 0).rstrip(), b'') + + def test_insert_delete(self): + win = curses.newwin(5, 15, 5, 2) + lorem_ipsum(win) + + win.move(0, 2) + win.delch() + self.assertEqual(win.instr(0, 0), b'Loem ipsum ') + win.delch(0, 7) + self.assertEqual(win.instr(0, 0), b'Loem ipum ') + + win.move(1, 5) + win.deleteln() + self.assertEqual(win.instr(0, 0), b'Loem ipum ') + self.assertEqual(win.instr(1, 0), b'consectetur ') + self.assertEqual(win.instr(2, 0), b'adipiscing elit') + self.assertEqual(win.instr(3, 0), b'sed do eiusmod ') + self.assertEqual(win.instr(4, 0), b' ') + + win.move(1, 5) + win.insertln() + self.assertEqual(win.instr(0, 0), b'Loem ipum ') + self.assertEqual(win.instr(1, 0), b' ') + self.assertEqual(win.instr(2, 0), b'consectetur ') + + win.clear() + lorem_ipsum(win) + win.move(1, 5) + win.insdelln(2) + self.assertEqual(win.instr(0, 0), b'Lorem ipsum ') + self.assertEqual(win.instr(1, 0), b' ') + self.assertEqual(win.instr(2, 0), b' ') + self.assertEqual(win.instr(3, 0), b'dolor sit amet,') + + win.clear() + lorem_ipsum(win) + win.move(1, 5) + win.insdelln(-2) + self.assertEqual(win.instr(0, 0), b'Lorem ipsum ') + self.assertEqual(win.instr(1, 0), b'adipiscing elit') + self.assertEqual(win.instr(2, 0), b'sed do eiusmod ') + self.assertEqual(win.instr(3, 0), b' ') + + def test_scroll(self): + win = curses.newwin(5, 15, 5, 2) + lorem_ipsum(win) + win.scrollok(True) + win.scroll() + self.assertEqual(win.instr(0, 0), b'dolor sit amet,') + win.scroll(2) + self.assertEqual(win.instr(0, 0), b'adipiscing elit') + win.scroll(-3) + self.assertEqual(win.instr(0, 0), b' ') + self.assertEqual(win.instr(2, 0), b' ') + self.assertEqual(win.instr(3, 0), b'adipiscing elit') + win.scrollok(False) + + def test_attributes(self): + # TODO: attr_get(), attr_set(), ... + win = curses.newwin(5, 15, 5, 2) + win.attron(curses.A_BOLD) + win.attroff(curses.A_BOLD) + win.attrset(curses.A_BOLD) + + win.standout() + win.standend() + + @requires_curses_window_meth('chgat') + def test_chgat(self): + win = curses.newwin(5, 15, 5, 2) + win.addstr(2, 0, 'Lorem ipsum') + win.addstr(3, 0, 'dolor sit amet') + + win.move(2, 8) + win.chgat(curses.A_BLINK) + self.assertEqual(win.inch(2, 7), b'p'[0]) + self.assertEqual(win.inch(2, 8), b's'[0] | curses.A_BLINK) + self.assertEqual(win.inch(2, 14), b' '[0] | curses.A_BLINK) + + win.move(2, 1) + win.chgat(3, curses.A_BOLD) + self.assertEqual(win.inch(2, 0), b'L'[0]) + self.assertEqual(win.inch(2, 1), b'o'[0] | curses.A_BOLD) + self.assertEqual(win.inch(2, 3), b'e'[0] | curses.A_BOLD) + self.assertEqual(win.inch(2, 4), b'm'[0]) + + win.chgat(3, 2, curses.A_UNDERLINE) + self.assertEqual(win.inch(3, 1), b'o'[0]) + self.assertEqual(win.inch(3, 2), b'l'[0] | curses.A_UNDERLINE) + self.assertEqual(win.inch(3, 14), b' '[0] | curses.A_UNDERLINE) + + win.chgat(3, 4, 7, curses.A_BLINK) + self.assertEqual(win.inch(3, 3), b'o'[0] | curses.A_UNDERLINE) + self.assertEqual(win.inch(3, 4), b'r'[0] | curses.A_BLINK) + self.assertEqual(win.inch(3, 10), b'a'[0] | curses.A_BLINK) + self.assertEqual(win.inch(3, 11), b'm'[0] | curses.A_UNDERLINE) + self.assertEqual(win.inch(3, 14), b' '[0] | curses.A_UNDERLINE) + + def test_background(self): + win = curses.newwin(5, 15, 5, 2) + win.addstr(0, 0, 'Lorem ipsum') + + self.assertEqual(win.getbkgd(), 0) + + # bkgdset() + win.bkgdset('_') + self.assertEqual(win.getbkgd(), b'_'[0]) + win.bkgdset(b'#') + self.assertEqual(win.getbkgd(), b'#'[0]) + win.bkgdset(65) + self.assertEqual(win.getbkgd(), 65) + win.bkgdset(0) + self.assertEqual(win.getbkgd(), 32) + + win.bkgdset('#', curses.A_REVERSE) + self.assertEqual(win.getbkgd(), b'#'[0] | curses.A_REVERSE) + self.assertEqual(win.inch(0, 0), b'L'[0]) + self.assertEqual(win.inch(0, 5), b' '[0]) + win.bkgdset(0) + + # bkgd() + win.bkgd('_') + self.assertEqual(win.getbkgd(), b'_'[0]) + self.assertEqual(win.inch(0, 0), b'L'[0]) + self.assertEqual(win.inch(0, 5), b'_'[0]) + + win.bkgd('#', curses.A_REVERSE) + self.assertEqual(win.getbkgd(), b'#'[0] | curses.A_REVERSE) + self.assertEqual(win.inch(0, 0), b'L'[0] | curses.A_REVERSE) + self.assertEqual(win.inch(0, 5), b'#'[0] | curses.A_REVERSE) + + def test_overlay(self): + srcwin = curses.newwin(5, 18, 3, 4) + lorem_ipsum(srcwin) + dstwin = curses.newwin(7, 17, 5, 7) + for i in range(6): + dstwin.addstr(i, 0, '_'*17) + + srcwin.overlay(dstwin) + self.assertEqual(dstwin.instr(0, 0), b'sectetur_________') + self.assertEqual(dstwin.instr(1, 0), b'piscing_elit,____') + self.assertEqual(dstwin.instr(2, 0), b'_do_eiusmod______') + self.assertEqual(dstwin.instr(3, 0), b'_________________') + + srcwin.overwrite(dstwin) + self.assertEqual(dstwin.instr(0, 0), b'sectetur __') + self.assertEqual(dstwin.instr(1, 0), b'piscing elit, __') + self.assertEqual(dstwin.instr(2, 0), b' do eiusmod __') + self.assertEqual(dstwin.instr(3, 0), b'_________________') + + srcwin.overlay(dstwin, 1, 4, 3, 2, 4, 11) + self.assertEqual(dstwin.instr(3, 0), b'__r_sit_amet_____') + self.assertEqual(dstwin.instr(4, 0), b'__ectetur________') + self.assertEqual(dstwin.instr(5, 0), b'_________________') + + srcwin.overwrite(dstwin, 1, 4, 3, 2, 4, 11) + self.assertEqual(dstwin.instr(3, 0), b'__r sit amet_____') + self.assertEqual(dstwin.instr(4, 0), b'__ectetur _____') + self.assertEqual(dstwin.instr(5, 0), b'_________________') + + def test_refresh(self): + win = curses.newwin(5, 15, 2, 5) + win.noutrefresh() + win.redrawln(1, 2) + win.redrawwin() + win.refresh() + curses.doupdate() + + @requires_curses_window_meth('resize') + def test_resize(self): + win = curses.newwin(5, 15, 2, 5) + win.resize(4, 20) + self.assertEqual(win.getmaxyx(), (4, 20)) + win.resize(5, 15) + self.assertEqual(win.getmaxyx(), (5, 15)) + + @requires_curses_window_meth('enclose') + def test_enclose(self): + win = curses.newwin(5, 15, 2, 5) + # TODO: Return bool instead of 1/0 + self.assertTrue(win.enclose(2, 5)) + self.assertFalse(win.enclose(1, 5)) + self.assertFalse(win.enclose(2, 4)) + self.assertTrue(win.enclose(6, 19)) + self.assertFalse(win.enclose(7, 19)) + self.assertFalse(win.enclose(6, 20)) + + def test_putwin(self): + win = curses.newwin(5, 12, 1, 2) + win.addstr(2, 1, 'Lorem ipsum') + with tempfile.TemporaryFile() as f: + win.putwin(f) + del win + f.seek(0) + win = curses.getwin(f) + self.assertEqual(win.getbegyx(), (1, 2)) + self.assertEqual(win.getmaxyx(), (5, 12)) + self.assertEqual(win.instr(2, 0), b' Lorem ipsum') + + def test_borders_and_lines(self): + win = curses.newwin(5, 10, 5, 2) win.border('|', '!', '-', '_', '+', '\\', '#', '/') - with self.assertRaises(TypeError, - msg="Expected win.border() to raise TypeError"): - win.border(65, 66, 67, 68, - 69, [], 71, 72) - - win.box(65, 67) - win.box('!', '_') + self.assertEqual(win.instr(0, 0), b'+--------\\') + self.assertEqual(win.instr(1, 0), b'| !') + self.assertEqual(win.instr(4, 0), b'#________/') + win.border(b'|', b'!', b'-', b'_', + b'+', b'\\', b'#', b'/') + win.border(65, 66, 67, 68, + 69, 70, 71, 72) + self.assertRaises(TypeError, win.border, + 65, 66, 67, 68, 69, [], 71, 72) + self.assertRaises(TypeError, win.border, + 65, 66, 67, 68, 69, 70, 71, 72, 73) + self.assertRaises(TypeError, win.border, + 65, 66, 67, 68, 69, 70, 71, 72, 73) + win.border(65, 66, 67, 68, 69, 70, 71) + win.border(65, 66, 67, 68, 69, 70) + win.border(65, 66, 67, 68, 69) + win.border(65, 66, 67, 68) + win.border(65, 66, 67) + win.border(65, 66) + win.border(65) + win.border() + + win.box(':', '~') + self.assertEqual(win.instr(0, 1, 8), b'~~~~~~~~') + self.assertEqual(win.instr(1, 0), b': :') + self.assertEqual(win.instr(4, 1, 8), b'~~~~~~~~') win.box(b':', b'~') + win.box(65, 67) self.assertRaises(TypeError, win.box, 65, 66, 67) self.assertRaises(TypeError, win.box, 65) win.box() - stdscr.clearok(1) + win.move(1, 2) + win.hline('-', 5) + self.assertEqual(win.instr(1, 1, 7), b' ----- ') + win.hline(b'-', 5) + win.hline(45, 5) + win.hline('-', 5, curses.A_BOLD) + win.hline(1, 1, '-', 5) + win.hline(1, 1, '-', 5, curses.A_BOLD) + + win.move(1, 2) + win.vline('a', 3) + win.vline(b'a', 3) + win.vline(97, 3) + win.vline('a', 3, curses.A_STANDOUT) + win.vline(1, 1, 'a', 3) + win.vline(1, 1, ';', 2, curses.A_STANDOUT) + self.assertEqual(win.inch(1, 1), b';'[0] | curses.A_STANDOUT) + self.assertEqual(win.inch(2, 1), b';'[0] | curses.A_STANDOUT) + self.assertEqual(win.inch(3, 1), b'a'[0]) + + def test_unctrl(self): + # TODO: wunctrl() + self.assertEqual(curses.unctrl(b'A'), b'A') + self.assertEqual(curses.unctrl('A'), b'A') + self.assertEqual(curses.unctrl(65), b'A') + self.assertEqual(curses.unctrl(b'\n'), b'^J') + self.assertEqual(curses.unctrl('\n'), b'^J') + self.assertEqual(curses.unctrl(10), b'^J') + self.assertRaises(TypeError, curses.unctrl, b'') + self.assertRaises(TypeError, curses.unctrl, b'AB') + self.assertRaises(TypeError, curses.unctrl, '') + self.assertRaises(TypeError, curses.unctrl, 'AB') + self.assertRaises(OverflowError, curses.unctrl, 2**64) + + def test_endwin(self): + if not self.isatty: + self.skipTest('requires terminal') + self.assertIs(curses.isendwin(), False) + curses.endwin() + self.assertIs(curses.isendwin(), True) + curses.doupdate() + self.assertIs(curses.isendwin(), False) + + def test_terminfo(self): + self.assertIsInstance(curses.tigetflag('hc'), int) + self.assertEqual(curses.tigetflag('cols'), -1) + self.assertEqual(curses.tigetflag('cr'), -1) + + self.assertIsInstance(curses.tigetnum('cols'), int) + self.assertEqual(curses.tigetnum('hc'), -2) + self.assertEqual(curses.tigetnum('cr'), -2) + + self.assertIsInstance(curses.tigetstr('cr'), (bytes, type(None))) + self.assertIsNone(curses.tigetstr('hc')) + self.assertIsNone(curses.tigetstr('cols')) + + cud = curses.tigetstr('cud') + if cud is not None: + # See issue10570. + self.assertIsInstance(cud, bytes) + curses.tparm(cud, 2) + cud_2 = curses.tparm(cud, 2) + self.assertIsInstance(cud_2, bytes) + curses.putp(cud_2) + + curses.putp(b'abc\n') + + def test_misc_module_funcs(self): + curses.delay_output(1) + curses.flushinp() - win4 = stdscr.derwin(2,2) - win4 = stdscr.derwin(1,1, 5,5) - win4.mvderwin(9,9) + curses.doupdate() + self.assertIs(curses.isendwin(), False) - stdscr.echochar('a') - stdscr.echochar('a', curses.A_BOLD) - stdscr.hline('-', 5) - stdscr.hline('-', 5, curses.A_BOLD) - stdscr.hline(1,1,'-', 5) - stdscr.hline(1,1,'-', 5, curses.A_BOLD) + curses.napms(100) + + curses.newpad(50, 50) + + def test_env_queries(self): + # TODO: term_attrs(), erasewchar(), killwchar() + self.assertIsInstance(curses.termname(), bytes) + self.assertIsInstance(curses.longname(), bytes) + self.assertIsInstance(curses.baudrate(), int) + self.assertIsInstance(curses.has_ic(), bool) + self.assertIsInstance(curses.has_il(), bool) + self.assertIsInstance(curses.termattrs(), int) + + c = curses.killchar() + self.assertIsInstance(c, bytes) + self.assertEqual(len(c), 1) + c = curses.erasechar() + self.assertIsInstance(c, bytes) + self.assertEqual(len(c), 1) + + def test_output_options(self): + stdscr = self.stdscr + + stdscr.clearok(True) + stdscr.clearok(False) + + stdscr.idcok(True) + stdscr.idcok(False) + + stdscr.idlok(False) + stdscr.idlok(True) - stdscr.idcok(1) - stdscr.idlok(1) if hasattr(stdscr, 'immedok'): - stdscr.immedok(1) - stdscr.immedok(0) - stdscr.insch('c') - stdscr.insdelln(1) - stdscr.insnstr('abc', 3) - stdscr.insnstr('abc', 3, curses.A_BOLD) - stdscr.insnstr(5, 5, 'abc', 3) - stdscr.insnstr(5, 5, 'abc', 3, curses.A_BOLD) - - stdscr.insstr('def') - stdscr.insstr('def', curses.A_BOLD) - stdscr.insstr(5, 5, 'def') - stdscr.insstr(5, 5, 'def', curses.A_BOLD) - stdscr.is_linetouched(0) - stdscr.keypad(1) - stdscr.leaveok(1) - stdscr.move(3,3) - win.mvwin(2,2) - stdscr.nodelay(1) - stdscr.notimeout(1) - win2.overlay(win) - win2.overwrite(win) - win2.overlay(win, 1, 2, 2, 1, 3, 3) - win2.overwrite(win, 1, 2, 2, 1, 3, 3) - stdscr.redrawln(1,2) - - stdscr.scrollok(1) - stdscr.scroll() - stdscr.scroll(2) - stdscr.scroll(-3) - - stdscr.move(12, 2) - stdscr.setscrreg(10,15) - win3 = stdscr.subwin(10,10) - win3 = stdscr.subwin(10,10, 5,5) - if hasattr(stdscr, 'syncok') and not sys.platform.startswith("sunos"): - stdscr.syncok(1) - stdscr.timeout(5) - stdscr.touchline(5,5) - stdscr.touchline(5,5,0) - stdscr.vline('a', 3) - stdscr.vline('a', 3, curses.A_STANDOUT) - if hasattr(stdscr, 'chgat'): - stdscr.chgat(5, 2, 3, curses.A_BLINK) - stdscr.chgat(3, curses.A_BOLD) - stdscr.chgat(5, 8, curses.A_UNDERLINE) - stdscr.chgat(curses.A_BLINK) - stdscr.refresh() + stdscr.immedok(True) + stdscr.immedok(False) - stdscr.vline(1,1, 'a', 3) - stdscr.vline(1,1, 'a', 3, curses.A_STANDOUT) + stdscr.leaveok(True) + stdscr.leaveok(False) - if hasattr(stdscr, 'resize'): - stdscr.resize(25, 80) - if hasattr(stdscr, 'enclose'): - stdscr.enclose(10, 10) + stdscr.scrollok(True) + stdscr.scrollok(False) - with tempfile.TemporaryFile() as f: - self.stdscr.putwin(f) - f.seek(0) - curses.getwin(f) + stdscr.setscrreg(5, 10) - self.assertRaises(ValueError, stdscr.getstr, -400) - self.assertRaises(ValueError, stdscr.getstr, 2, 3, -400) - self.assertRaises(ValueError, stdscr.instr, -2) - self.assertRaises(ValueError, stdscr.instr, 2, 3, -2) + curses.nonl() + curses.nl(True) + curses.nl(False) + curses.nl() - def test_embedded_null_chars(self): - # reject embedded null bytes and characters + + def test_input_options(self): stdscr = self.stdscr - for arg in ['a', b'a']: - with self.subTest(arg=arg): - self.assertRaises(ValueError, stdscr.addstr, 'a\0') - self.assertRaises(ValueError, stdscr.addnstr, 'a\0', 1) - self.assertRaises(ValueError, stdscr.insstr, 'a\0') - self.assertRaises(ValueError, stdscr.insnstr, 'a\0', 1) - - def test_module_funcs(self): - "Test module-level functions" - for func in [curses.baudrate, curses.beep, curses.can_change_color, - curses.doupdate, curses.flash, curses.flushinp, - curses.has_colors, curses.has_ic, curses.has_il, - curses.isendwin, curses.killchar, curses.longname, - curses.noecho, curses.nonl, curses.noqiflush, - curses.termattrs, curses.termname, curses.erasechar]: - with self.subTest(func=func.__qualname__): - func() + if self.isatty: - for func in [curses.cbreak, curses.def_prog_mode, - curses.nocbreak, curses.noraw, - curses.reset_prog_mode]: - with self.subTest(func=func.__qualname__): - func() - if hasattr(curses, 'filter'): - curses.filter() - if hasattr(curses, 'getsyx'): - curses.getsyx() - - # Functions that actually need arguments - if curses.tigetstr("cnorm"): - curses.curs_set(1) - curses.delay_output(1) - curses.echo() ; curses.echo(1) + curses.nocbreak() + curses.cbreak() + curses.cbreak(False) + curses.cbreak(True) + + curses.intrflush(True) + curses.intrflush(False) + curses.raw() + curses.raw(False) + curses.raw(True) + curses.noraw() + + curses.noecho() + curses.echo() + curses.echo(False) + curses.echo(True) + + curses.halfdelay(255) curses.halfdelay(1) - if self.isatty: - curses.intrflush(1) - curses.meta(1) - curses.napms(100) - curses.newpad(50,50) - win = curses.newwin(5,5) - win = curses.newwin(5,5, 1,1) - curses.nl() ; curses.nl(1) - curses.putp(b'abc') + + stdscr.keypad(True) + stdscr.keypad(False) + + curses.meta(True) + curses.meta(False) + + stdscr.nodelay(True) + stdscr.nodelay(False) + + curses.noqiflush() + curses.qiflush(True) + curses.qiflush(False) curses.qiflush() - if self.isatty: - curses.raw() ; curses.raw(1) + + stdscr.notimeout(True) + stdscr.notimeout(False) + + stdscr.timeout(-1) + stdscr.timeout(0) + stdscr.timeout(5) + + @requires_curses_func('typeahead') + def test_typeahead(self): + curses.typeahead(sys.__stdin__.fileno()) + curses.typeahead(-1) + + def test_prog_mode(self): + if not self.isatty: + self.skipTest('requires terminal') + curses.def_prog_mode() + curses.reset_prog_mode() + + def test_beep(self): + if (curses.tigetstr("bel") is not None + or curses.tigetstr("flash") is not None): + curses.beep() + else: + try: + curses.beep() + except curses.error: + self.skipTest('beep() failed') + + def test_flash(self): + if (curses.tigetstr("bel") is not None + or curses.tigetstr("flash") is not None): + curses.flash() + else: + try: + curses.flash() + except curses.error: + self.skipTest('flash() failed') + + def test_curs_set(self): + for vis, cap in [(0, 'civis'), (2, 'cvvis'), (1, 'cnorm')]: + if curses.tigetstr(cap) is not None: + curses.curs_set(vis) + else: + try: + curses.curs_set(vis) + except curses.error: + pass + + @requires_curses_func('get_escdelay') + def test_escdelay(self): + escdelay = curses.get_escdelay() + self.assertIsInstance(escdelay, int) curses.set_escdelay(25) self.assertEqual(curses.get_escdelay(), 25) + curses.set_escdelay(escdelay) + + @requires_curses_func('get_tabsize') + def test_tabsize(self): + tabsize = curses.get_tabsize() + self.assertIsInstance(tabsize, int) curses.set_tabsize(4) self.assertEqual(curses.get_tabsize(), 4) - if hasattr(curses, 'setsyx'): - curses.setsyx(5,5) - curses.tigetflag('hc') - curses.tigetnum('co') - curses.tigetstr('cr') - curses.tparm(b'cr') - if hasattr(curses, 'typeahead'): - curses.typeahead(sys.__stdin__.fileno()) - curses.unctrl('a') - curses.ungetch('a') - if hasattr(curses, 'use_env'): - curses.use_env(1) - - # Functions only available on a few platforms + curses.set_tabsize(tabsize) + + @requires_curses_func('getsyx') + def test_getsyx(self): + y, x = curses.getsyx() + self.assertIsInstance(y, int) + self.assertIsInstance(x, int) + curses.setsyx(4, 5) + self.assertEqual(curses.getsyx(), (4, 5)) def bad_colors(self): return (-2**31 - 1, 2**31, -2**63 - 1, 2**63, 2**64) @@ -323,6 +844,10 @@ def bad_colors(self): def bad_pairs(self): return (-2**31 - 1, 2**31, -2**63 - 1, 2**63, 2**64) + def test_has_colors(self): + self.assertIsInstance(curses.has_colors(), bool) + self.assertIsInstance(curses.can_change_color(), bool) + def test_start_color(self): if not curses.has_colors(): self.skipTest('requires colors support') @@ -346,7 +871,7 @@ def test_color_content(self): @requires_colors def test_init_color(self): - if not curses.can_change_color: + if not curses.can_change_color(): self.skipTest('cannot change color') old = curses.color_content(0) @@ -434,14 +959,22 @@ def test_color_attrs(self): @requires_curses_func('use_default_colors') @requires_colors def test_use_default_colors(self): - self.assertIn(curses.pair_content(0), - ((curses.COLOR_WHITE, curses.COLOR_BLACK), (-1, -1))) - curses.use_default_colors() + old = curses.pair_content(0) + try: + curses.use_default_colors() + except curses.error: + self.skipTest('cannot change color (use_default_colors() failed)') self.assertEqual(curses.pair_content(0), (-1, -1)) + self.assertIn(old, [(curses.COLOR_WHITE, curses.COLOR_BLACK), (-1, -1), (0, 0)]) - @requires_curses_func('keyname') def test_keyname(self): - curses.keyname(13) + # TODO: key_name() + self.assertEqual(curses.keyname(65), b'A') + self.assertEqual(curses.keyname(13), b'^M') + self.assertEqual(curses.keyname(127), b'^?') + self.assertEqual(curses.keyname(0), b'^@') + self.assertRaises(ValueError, curses.keyname, -1) + self.assertIsInstance(curses.keyname(256), bytes) @requires_curses_func('has_key') def test_has_key(self): @@ -497,22 +1030,46 @@ def test_new_curses_panel(self): @requires_curses_func('is_term_resized') def test_is_term_resized(self): - curses.is_term_resized(*self.stdscr.getmaxyx()) + lines, cols = curses.LINES, curses.COLS + self.assertIs(curses.is_term_resized(lines, cols), False) + self.assertIs(curses.is_term_resized(lines-1, cols-1), True) @requires_curses_func('resize_term') def test_resize_term(self): - curses.resize_term(*self.stdscr.getmaxyx()) + curses.update_lines_cols() + lines, cols = curses.LINES, curses.COLS + new_lines = lines - 1 + new_cols = cols + 1 + curses.resize_term(new_lines, new_cols) + self.assertEqual(curses.LINES, new_lines) + self.assertEqual(curses.COLS, new_cols) + + curses.resize_term(lines, cols) + self.assertEqual(curses.LINES, lines) + self.assertEqual(curses.COLS, cols) @requires_curses_func('resizeterm') def test_resizeterm(self): + curses.update_lines_cols() lines, cols = curses.LINES, curses.COLS new_lines = lines - 1 new_cols = cols + 1 curses.resizeterm(new_lines, new_cols) - self.assertEqual(curses.LINES, new_lines) self.assertEqual(curses.COLS, new_cols) + curses.resizeterm(lines, cols) + self.assertEqual(curses.LINES, lines) + self.assertEqual(curses.COLS, cols) + + def test_ungetch(self): + curses.ungetch(b'A') + self.assertEqual(self.stdscr.getkey(), 'A') + curses.ungetch('B') + self.assertEqual(self.stdscr.getkey(), 'B') + curses.ungetch(67) + self.assertEqual(self.stdscr.getkey(), 'C') + def test_issue6243(self): curses.ungetch(1025) self.stdscr.getkey() @@ -541,10 +1098,6 @@ def test_unget_wch(self): read = stdscr.get_wch() self.assertEqual(read, ch) - def test_issue10570(self): - b = curses.tparm(curses.tigetstr("cup"), 5, 3) - self.assertIs(type(b), bytes) - def test_encoding(self): stdscr = self.stdscr import codecs @@ -584,26 +1137,25 @@ def test_issue21088(self): human_readable_signature = stdscr.addch.__doc__.split("\n")[0] self.assertIn("[y, x,]", human_readable_signature) + @requires_curses_window_meth('resize') def test_issue13051(self): - stdscr = self.stdscr - if not hasattr(stdscr, 'resize'): - raise unittest.SkipTest('requires curses.window.resize') - box = curses.textpad.Textbox(stdscr, insert_mode=True) - lines, cols = stdscr.getmaxyx() - stdscr.resize(lines-2, cols-2) + win = curses.newwin(5, 15, 2, 5) + box = curses.textpad.Textbox(win, insert_mode=True) + lines, cols = win.getmaxyx() + win.resize(lines-2, cols-2) # this may cause infinite recursion, leading to a RuntimeError box._insert_printable_char('a') class MiscTests(unittest.TestCase): - @requires_curses_func('update_lines_cols') def test_update_lines_cols(self): - # this doesn't actually test that LINES and COLS are updated, - # because we can't automate changing them. See Issue #4254 for - # a manual test script. We can only test that the function - # can be called. curses.update_lines_cols() + lines, cols = curses.LINES, curses.COLS + curses.LINES = curses.COLS = 0 + curses.update_lines_cols() + self.assertEqual(curses.LINES, lines) + self.assertEqual(curses.COLS, cols) @requires_curses_func('ncurses_version') def test_ncurses_version(self): @@ -625,6 +1177,7 @@ def test_ncurses_version(self): self.assertGreaterEqual(v.minor, 0) self.assertGreaterEqual(v.patch, 0) + class TestAscii(unittest.TestCase): def test_controlnames(self): @@ -713,5 +1266,21 @@ def test_unctrl(self): self.assertEqual(unctrl(ord('\xc1')), '!A') +def lorem_ipsum(win): + text = [ + 'Lorem ipsum', + 'dolor sit amet,', + 'consectetur', + 'adipiscing elit,', + 'sed do eiusmod', + 'tempor incididunt', + 'ut labore et', + 'dolore magna', + 'aliqua.', + ] + maxy, maxx = win.getmaxyx() + for y, line in enumerate(text[:maxy]): + win.addstr(y, 0, line[:maxx - (y == maxy - 1)]) + if __name__ == '__main__': unittest.main() From 3c8d6934436e20163be802f5239c5b4e4925eeec Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sun, 31 Jan 2021 21:44:31 +0200 Subject: [PATCH 0919/1314] [3.9] bpo-41604: Don't decrement the reference count of the previous user_ptr when set_panel_usertpr fails (GH-21933). (GH-24403) (cherry picked from commit 3243e8a4b4b4cf321f9b28335d565742a34b1976) Co-authored-by: Anonymous Maarten --- .../next/Library/2020-08-21-15-24-14.bpo-41604.rTXleO.rst | 2 ++ Modules/_curses_panel.c | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Library/2020-08-21-15-24-14.bpo-41604.rTXleO.rst diff --git a/Misc/NEWS.d/next/Library/2020-08-21-15-24-14.bpo-41604.rTXleO.rst b/Misc/NEWS.d/next/Library/2020-08-21-15-24-14.bpo-41604.rTXleO.rst new file mode 100644 index 00000000000000..0f9794cbdb321e --- /dev/null +++ b/Misc/NEWS.d/next/Library/2020-08-21-15-24-14.bpo-41604.rTXleO.rst @@ -0,0 +1,2 @@ +Don't decrement the reference count of the previous user_ptr when +set_panel_userptr fails. diff --git a/Modules/_curses_panel.c b/Modules/_curses_panel.c index f124803493d88b..4f026794e34177 100644 --- a/Modules/_curses_panel.c +++ b/Modules/_curses_panel.c @@ -440,7 +440,9 @@ _curses_panel_panel_set_userptr(PyCursesPanelObject *self, PyObject *obj) /* In case of an ncurses error, decref the new object again */ Py_DECREF(obj); } - Py_XDECREF(oldobj); + else { + Py_XDECREF(oldobj); + } return PyCursesCheckERR(rc, "set_panel_userptr"); } From d6675fee1aac1af87dc31c411d04a5bfc1f39079 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 31 Jan 2021 20:22:48 -0800 Subject: [PATCH 0920/1314] bpo-42504: Ensure that get_config_var('MACOSX_DEPLOYMENT_TARGET') is a string (GH-24341) (GH-24410) * bpo-42504: Ensure that get_config_var('MACOSX_DEPLOYMENT_TARGET') is a string (cherry picked from commit 49926cf2bcc8b44d9b8f148d81979ada191dd9d5) Co-authored-by: Ronald Oussoren --- Lib/distutils/spawn.py | 4 ++-- Lib/distutils/tests/test_build_ext.py | 4 ++-- Lib/sysconfig.py | 12 ++++++++++++ Lib/test/test_posix.py | 2 +- .../macOS/2021-01-26-14-36-11.bpo-42504.ZxWt71.rst | 3 +++ setup.py | 2 +- 6 files changed, 21 insertions(+), 6 deletions(-) create mode 100644 Misc/NEWS.d/next/macOS/2021-01-26-14-36-11.bpo-42504.ZxWt71.rst diff --git a/Lib/distutils/spawn.py b/Lib/distutils/spawn.py index f50edd2da97100..0d1bd0391e6f11 100644 --- a/Lib/distutils/spawn.py +++ b/Lib/distutils/spawn.py @@ -54,8 +54,8 @@ def spawn(cmd, search_path=1, verbose=0, dry_run=0): global _cfg_target, _cfg_target_split if _cfg_target is None: from distutils import sysconfig - _cfg_target = str(sysconfig.get_config_var( - 'MACOSX_DEPLOYMENT_TARGET') or '') + _cfg_target = sysconfig.get_config_var( + 'MACOSX_DEPLOYMENT_TARGET') or '' if _cfg_target: _cfg_target_split = [int(x) for x in _cfg_target.split('.')] if _cfg_target: diff --git a/Lib/distutils/tests/test_build_ext.py b/Lib/distutils/tests/test_build_ext.py index 1b034c93025213..808c0dc2874cd5 100644 --- a/Lib/distutils/tests/test_build_ext.py +++ b/Lib/distutils/tests/test_build_ext.py @@ -455,7 +455,7 @@ def test_deployment_target_higher_ok(self): deptarget = sysconfig.get_config_var('MACOSX_DEPLOYMENT_TARGET') if deptarget: # increment the minor version number (i.e. 10.6 -> 10.7) - deptarget = [int(x) for x in str(deptarget).split('.')] + deptarget = [int(x) for x in deptarget.split('.')] deptarget[-1] += 1 deptarget = '.'.join(str(i) for i in deptarget) self._try_compile_deployment_target('<', deptarget) @@ -488,7 +488,7 @@ def _try_compile_deployment_target(self, operator, target): # get the deployment target that the interpreter was built with target = sysconfig.get_config_var('MACOSX_DEPLOYMENT_TARGET') - target = tuple(map(int, str(target).split('.')[0:2])) + target = tuple(map(int, target.split('.')[0:2])) # format the target value as defined in the Apple # Availability Macros. We can't use the macro names since # at least one value we test with will not exist yet. diff --git a/Lib/sysconfig.py b/Lib/sysconfig.py index 59da8e529025d2..e3f79bfde52948 100644 --- a/Lib/sysconfig.py +++ b/Lib/sysconfig.py @@ -18,6 +18,11 @@ 'parse_config_h', ] +# Keys for get_config_var() that are never converted to Python integers. +_ALWAYS_STR = { + 'MACOSX_DEPLOYMENT_TARGET', +} + _INSTALL_SCHEMES = { 'posix_prefix': { 'stdlib': '{installed_base}/{platlibdir}/python{py_version_short}', @@ -240,6 +245,9 @@ def _parse_makefile(filename, vars=None): notdone[n] = v else: try: + if n in _ALWAYS_STR: + raise ValueError + v = int(v) except ValueError: # insert literal `$' @@ -298,6 +306,8 @@ def _parse_makefile(filename, vars=None): notdone[name] = value else: try: + if name in _ALWAYS_STR: + raise ValueError value = int(value) except ValueError: done[name] = value.strip() @@ -459,6 +469,8 @@ def parse_config_h(fp, vars=None): if m: n, v = m.group(1, 2) try: + if n in _ALWAYS_STR: + raise ValueError v = int(v) except ValueError: pass diff --git a/Lib/test/test_posix.py b/Lib/test/test_posix.py index bfbcbab3b62f96..f4edb8bd9575f4 100644 --- a/Lib/test/test_posix.py +++ b/Lib/test/test_posix.py @@ -1045,7 +1045,7 @@ def test_getgroups(self): if sys.platform == 'darwin': import sysconfig dt = sysconfig.get_config_var('MACOSX_DEPLOYMENT_TARGET') or '10.0' - if tuple(int(n) for n in str(dt).split('.')[0:2]) < (10, 6): + if tuple(int(n) for n in dt.split('.')[0:2]) < (10, 6): raise unittest.SkipTest("getgroups(2) is broken prior to 10.6") # 'id -G' and 'os.getgroups()' should return the same diff --git a/Misc/NEWS.d/next/macOS/2021-01-26-14-36-11.bpo-42504.ZxWt71.rst b/Misc/NEWS.d/next/macOS/2021-01-26-14-36-11.bpo-42504.ZxWt71.rst new file mode 100644 index 00000000000000..a47776effe905e --- /dev/null +++ b/Misc/NEWS.d/next/macOS/2021-01-26-14-36-11.bpo-42504.ZxWt71.rst @@ -0,0 +1,3 @@ +Ensure that the value of +sysconfig.get_config_var('MACOSX_DEPLOYMENT_TARGET') is always a string, +even in when the value is parsable as an integer. diff --git a/setup.py b/setup.py index bd5f73692441cb..d42eb9d1174ec5 100644 --- a/setup.py +++ b/setup.py @@ -1013,7 +1013,7 @@ def detect_readline_curses(self): os_release = int(os.uname()[2].split('.')[0]) dep_target = sysconfig.get_config_var('MACOSX_DEPLOYMENT_TARGET') if (dep_target and - (tuple(int(n) for n in str(dep_target).split('.')[0:2]) + (tuple(int(n) for n in dep_target.split('.')[0:2]) < (10, 5) ) ): os_release = 8 if os_release < 9: From 7e729978fa08a360cbf936dc215ba7dd25a06a08 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 31 Jan 2021 21:15:23 -0800 Subject: [PATCH 0921/1314] bpo-42688: Fix ffi alloc/free when using external libffi on macos (GH-23868) (GH-23888) Automerge-Triggered-By: GH:ronaldoussoren (cherry picked from commit b3c77ecbbe0ad3e3cc6dbd885792203e9e6ec858) Co-authored-by: erykoff --- Modules/_ctypes/malloc_closure.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/Modules/_ctypes/malloc_closure.c b/Modules/_ctypes/malloc_closure.c index 4f220e42ff3fcc..788bae6a96c7f4 100644 --- a/Modules/_ctypes/malloc_closure.c +++ b/Modules/_ctypes/malloc_closure.c @@ -91,11 +91,15 @@ static void more_core(void) /* put the item back into the free list */ void Py_ffi_closure_free(void *p) { -#if USING_APPLE_OS_LIBFFI && HAVE_FFI_CLOSURE_ALLOC +#if HAVE_FFI_CLOSURE_ALLOC +#if USING_APPLE_OS_LIBFFI if (__builtin_available(macos 10.15, ios 13, watchos 6, tvos 13, *)) { +#endif ffi_closure_free(p); return; +#if USING_APPLE_OS_LIBFFI } +#endif #endif ITEM *item = (ITEM *)p; item->next = free_list; @@ -105,10 +109,14 @@ void Py_ffi_closure_free(void *p) /* return one item from the free list, allocating more if needed */ void *Py_ffi_closure_alloc(size_t size, void** codeloc) { -#if USING_APPLE_OS_LIBFFI && HAVE_FFI_CLOSURE_ALLOC +#if HAVE_FFI_CLOSURE_ALLOC +#if USING_APPLE_OS_LIBFFI if (__builtin_available(macos 10.15, ios 13, watchos 6, tvos 13, *)) { +#endif return ffi_closure_alloc(size, codeloc); +#if USING_APPLE_OS_LIBFFI } +#endif #endif ITEM *item; if (!free_list) From 304f9d2622fa4fd0833d60d31ddf7321a6a8141b Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 31 Jan 2021 23:37:29 -0800 Subject: [PATCH 0922/1314] bpo-43016: Fix test_curses on platform without cursesw (GH-24405) (GH-24407) (cherry picked from commit a1e9a1e120a11c563e166c15721169184c802f8b) Co-authored-by: Serhiy Storchaka --- Lib/test/test_curses.py | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/Lib/test/test_curses.py b/Lib/test/test_curses.py index f5287e0143fcbf..c1ad23b456e206 100644 --- a/Lib/test/test_curses.py +++ b/Lib/test/test_curses.py @@ -239,13 +239,21 @@ def test_refresh_control(self): def test_output_character(self): stdscr = self.stdscr + encoding = stdscr.encoding # addch() stdscr.refresh() stdscr.move(0, 0) stdscr.addch('A') stdscr.addch(b'A') stdscr.addch(65) - stdscr.addch('\u20ac') + c = '\u20ac' + try: + stdscr.addch(c) + except UnicodeEncodeError: + self.assertRaises(UnicodeEncodeError, c.encode, encoding) + except OverflowError: + encoded = c.encode(encoding) + self.assertNotEqual(len(encoded), 1, repr(encoded)) stdscr.addch('A', curses.A_BOLD) stdscr.addch(1, 2, 'A') stdscr.addch(2, 3, 'A', curses.A_BOLD) @@ -257,19 +265,25 @@ def test_output_character(self): stdscr.echochar('A') stdscr.echochar(b'A') stdscr.echochar(65) - self.assertRaises(OverflowError, stdscr.echochar, '\u20ac') + with self.assertRaises((UnicodeEncodeError, OverflowError)): + stdscr.echochar('\u20ac') stdscr.echochar('A', curses.A_BOLD) self.assertIs(stdscr.is_wintouched(), False) def test_output_string(self): stdscr = self.stdscr + encoding = stdscr.encoding # addstr()/insstr() for func in [stdscr.addstr, stdscr.insstr]: with self.subTest(func.__qualname__): stdscr.move(0, 0) func('abcd') func(b'abcd') - func('àßçđ') + s = 'àßçđ' + try: + func(s) + except UnicodeEncodeError: + self.assertRaises(UnicodeEncodeError, s.encode, encoding) func('abcd', curses.A_BOLD) func(1, 2, 'abcd') func(2, 3, 'abcd', curses.A_BOLD) @@ -280,7 +294,11 @@ def test_output_string(self): stdscr.move(0, 0) func('1234', 3) func(b'1234', 3) - func('\u0661\u0662\u0663\u0664', 3) + s = '\u0661\u0662\u0663\u0664' + try: + func(s, 3) + except UnicodeEncodeError: + self.assertRaises(UnicodeEncodeError, s.encode, encoding) func('1234', 5) func('1234', 3, curses.A_BOLD) func(1, 2, '1234', 3) @@ -470,7 +488,7 @@ def test_background(self): win = curses.newwin(5, 15, 5, 2) win.addstr(0, 0, 'Lorem ipsum') - self.assertEqual(win.getbkgd(), 0) + self.assertIn(win.getbkgd(), (0, 32)) # bkgdset() win.bkgdset('_') From 0874491bcc392f7bd9c394ec2fdab183e3f320dd Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 1 Feb 2021 12:54:43 -0800 Subject: [PATCH 0923/1314] bpo-41748: Handles unquoted attributes with commas (GH-24072) * bpo-41748: Adds tests for unquoted attributes with comma * bpo-41748: Handles unquoted attributes with comma * bpo-41748: Addresses review comments * bpo-41748: Addresses review comments * Adds more test cases * Simplifies the regex for handling spaces * bpo-41748: Moves attributes tests under the right class * bpo-41748: Addresses review about duplicate attributes * bpo-41748: Adds NEWS.d entry for this patch (cherry picked from commit 9eb11a139fac5514d8456626806a68b3e3b7eafb) Co-authored-by: Karl Dubost --- Lib/html/parser.py | 2 +- Lib/test/test_htmlparser.py | 92 +++++++++++-------- .../2021-01-05-21-26-29.bpo-41748.KdC0w3.rst | 2 + 3 files changed, 59 insertions(+), 37 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2021-01-05-21-26-29.bpo-41748.KdC0w3.rst diff --git a/Lib/html/parser.py b/Lib/html/parser.py index 60830779816a03..9e49effca1fcc5 100644 --- a/Lib/html/parser.py +++ b/Lib/html/parser.py @@ -46,7 +46,7 @@ |"[^"]*" # LIT-enclosed value |(?!['"])[^>\s]* # bare value ) - (?:\s*,)* # possibly followed by a comma + \s* # possibly followed by a space )?(?:\s|/(?!>))* )* )? diff --git a/Lib/test/test_htmlparser.py b/Lib/test/test_htmlparser.py index a2bfb39d16a571..12917755a56017 100644 --- a/Lib/test/test_htmlparser.py +++ b/Lib/test/test_htmlparser.py @@ -452,42 +452,6 @@ def test_illegal_declarations(self): self._run_check('', [('comment', 'spacer type="block" height="25"')]) - def test_with_unquoted_attributes(self): - # see #12008 - html = ("" - "" - "
" - "- software-and-i" - "- library
") - expected = [ - ('starttag', 'html', []), - ('starttag', 'body', [('bgcolor', 'd0ca90'), ('text', '181008')]), - ('starttag', 'table', - [('cellspacing', '0'), ('cellpadding', '1'), ('width', '100%')]), - ('starttag', 'tr', []), - ('starttag', 'td', [('align', 'left')]), - ('starttag', 'font', [('size', '-1')]), - ('data', '- '), ('starttag', 'a', [('href', '/rabota/')]), - ('starttag', 'span', [('class', 'en')]), ('data', ' software-and-i'), - ('endtag', 'span'), ('endtag', 'a'), - ('data', '- '), ('starttag', 'a', [('href', '/1/')]), - ('starttag', 'span', [('class', 'en')]), ('data', ' library'), - ('endtag', 'span'), ('endtag', 'a'), ('endtag', 'table') - ] - self._run_check(html, expected) - - def test_comma_between_attributes(self): - self._run_check('
', [ - ('starttag', 'form', - [('action', '/xxx.php?a=1&b=2&'), - (',', None), ('method', 'post')])]) - - def test_weird_chars_in_unquoted_attribute_values(self): - self._run_check('', [ - ('starttag', 'form', - [('action', 'bogus|&#()value')])]) - def test_invalid_end_tags(self): # A collection of broken end tags.
is used as separator. # see http://www.w3.org/TR/html5/tokenization.html#end-tag-open-state @@ -766,6 +730,62 @@ def test_end_tag_in_attribute_value(self): [("href", "http://www.example.org/\">;")]), ("data", "spam"), ("endtag", "a")]) + def test_with_unquoted_attributes(self): + # see #12008 + html = ("" + "" + "
" + "- software-and-i" + "- library
") + expected = [ + ('starttag', 'html', []), + ('starttag', 'body', [('bgcolor', 'd0ca90'), ('text', '181008')]), + ('starttag', 'table', + [('cellspacing', '0'), ('cellpadding', '1'), ('width', '100%')]), + ('starttag', 'tr', []), + ('starttag', 'td', [('align', 'left')]), + ('starttag', 'font', [('size', '-1')]), + ('data', '- '), ('starttag', 'a', [('href', '/rabota/')]), + ('starttag', 'span', [('class', 'en')]), ('data', ' software-and-i'), + ('endtag', 'span'), ('endtag', 'a'), + ('data', '- '), ('starttag', 'a', [('href', '/1/')]), + ('starttag', 'span', [('class', 'en')]), ('data', ' library'), + ('endtag', 'span'), ('endtag', 'a'), ('endtag', 'table') + ] + self._run_check(html, expected) + + def test_comma_between_attributes(self): + # see bpo 41478 + # HTMLParser preserves duplicate attributes, leaving the task of + # removing duplicate attributes to a conformant html tree builder + html = ('
' # between attrs (unquoted) + '
' # between attrs (quoted) + '
' # after values (unquoted) + '
' # after values (quoted) + '
' # one comma values (quoted) + '
' # before values (unquoted) + '
' # before values (quoted) + '
' # before names + '
' # after names + ) + expected = [ + ('starttag', 'div', [('class', 'bar,baz=asd'),]), + ('starttag', 'div', [('class', 'bar'), (',baz', 'asd')]), + ('starttag', 'div', [('class', 'bar,'), ('baz', 'asd,')]), + ('starttag', 'div', [('class', 'bar'), (',', None), + ('baz', 'asd'), (',', None)]), + ('starttag', 'div', [('class', 'bar'), (',', None)]), + ('starttag', 'div', [('class', ',bar'), ('baz', ',asd')]), + ('starttag', 'div', [('class', ',"bar"'), ('baz', ',"asd"')]), + ('starttag', 'div', [(',class', 'bar'), (',baz', 'asd')]), + ('starttag', 'div', [('class,', 'bar'), ('baz,', 'asd')]), + ] + self._run_check(html, expected) + + def test_weird_chars_in_unquoted_attribute_values(self): + self._run_check('', [ + ('starttag', 'form', + [('action', 'bogus|&#()value')])]) if __name__ == "__main__": unittest.main() diff --git a/Misc/NEWS.d/next/Library/2021-01-05-21-26-29.bpo-41748.KdC0w3.rst b/Misc/NEWS.d/next/Library/2021-01-05-21-26-29.bpo-41748.KdC0w3.rst new file mode 100644 index 00000000000000..52efa3ac3d40eb --- /dev/null +++ b/Misc/NEWS.d/next/Library/2021-01-05-21-26-29.bpo-41748.KdC0w3.rst @@ -0,0 +1,2 @@ +Fix HTMLParser parsing rules for element attributes containing +commas with spaces. Patch by Karl Dubost. \ No newline at end of file From 3b9452691ae8f3ccf6591769b4529b03c42bc268 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 2 Feb 2021 17:35:55 -0800 Subject: [PATCH 0924/1314] Add link to Microsoft docs for limitations in Windows Store package (GH-24422) (cherry picked from commit 1ba08a121a25fcf7c947d8d37e72e46dae59168c) Co-authored-by: Steve Dower --- Doc/using/windows.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Doc/using/windows.rst b/Doc/using/windows.rst index d0c342e1dad868..857308e77dd1bf 100644 --- a/Doc/using/windows.rst +++ b/Doc/using/windows.rst @@ -339,6 +339,11 @@ full write access to shared locations such as ``TEMP`` and the registry. Instead, it will write to a private copy. If your scripts must modify the shared locations, you will need to install the full installer. +For more detail on the technical basis for these limitations, please consult +Microsoft's documentation on packaged full-trust apps, currently available at +`docs.microsoft.com/en-us/windows/msix/desktop/desktop-to-uwp-behind-the-scenes +`_ + .. _windows-nuget: From f02ef7afcf67db52f169f809a1b0babb80ec8370 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 2 Feb 2021 19:33:35 -0800 Subject: [PATCH 0925/1314] bpo-43082: Remove redundant 'the' in Descriptor howto (GH-24394) (GH-24427) --- Doc/howto/descriptor.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/howto/descriptor.rst b/Doc/howto/descriptor.rst index ab5a573c6a06d1..0f999c95596aaf 100644 --- a/Doc/howto/descriptor.rst +++ b/Doc/howto/descriptor.rst @@ -497,7 +497,7 @@ Definition and introduction In general, a descriptor is an attribute value that has one of the methods in the descriptor protocol. Those methods are :meth:`__get__`, :meth:`__set__`, -and :meth:`__delete__`. If any of those methods are defined for an the +and :meth:`__delete__`. If any of those methods are defined for an attribute, it is said to be a :term:`descriptor`. The default behavior for attribute access is to get, set, or delete the From 12bfc595c49ef9681265407fe33b53b7a3623abc Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 3 Feb 2021 05:41:09 -0800 Subject: [PATCH 0926/1314] bpo-43108: Fix a reference leak in the curses module (GH-24420) (cherry picked from commit bb739ec922c6992a2be38f9fd3c544c2cc322dde) Co-authored-by: Pablo Galindo --- .../next/Library/2021-02-02-20-23-31.bpo-43108.lqcCZ6.rst | 1 + Modules/_cursesmodule.c | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Library/2021-02-02-20-23-31.bpo-43108.lqcCZ6.rst diff --git a/Misc/NEWS.d/next/Library/2021-02-02-20-23-31.bpo-43108.lqcCZ6.rst b/Misc/NEWS.d/next/Library/2021-02-02-20-23-31.bpo-43108.lqcCZ6.rst new file mode 100644 index 00000000000000..8e45640bceae13 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2021-02-02-20-23-31.bpo-43108.lqcCZ6.rst @@ -0,0 +1 @@ +Fixed a reference leak in the :mod:`curses` module. Patch by Pablo Galindo diff --git a/Modules/_cursesmodule.c b/Modules/_cursesmodule.c index d129248e363472..c84f8382274b5e 100644 --- a/Modules/_cursesmodule.c +++ b/Modules/_cursesmodule.c @@ -365,6 +365,7 @@ PyCurses_ConvertToString(PyCursesWindowObject *win, PyObject *obj, *bytes = obj; /* check for embedded null bytes */ if (PyBytes_AsStringAndSize(*bytes, &str, NULL) < 0) { + Py_DECREF(obj); return 0; } return 1; @@ -679,8 +680,9 @@ _curses_window_addstr_impl(PyCursesWindowObject *self, int group_left_1, #else strtype = PyCurses_ConvertToString(self, str, &bytesobj, NULL); #endif - if (strtype == 0) + if (strtype == 0) { return NULL; + } if (use_attr) { attr_old = getattrs(self->win); (void)wattrset(self->win,attr); From 2603d77a6b3200f08b890bd9bb4dc821970d68fe Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 3 Feb 2021 13:48:22 -0800 Subject: [PATCH 0927/1314] Fix typo (GH-23019) Fixed possible typo in comment (cherry picked from commit bfe544d2f2c2e7a7c03a764bed3276a1e27a0f5c) Co-authored-by: Harry --- Lib/datetime.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/datetime.py b/Lib/datetime.py index e508d996fb1ed1..23d2bf0918145f 100644 --- a/Lib/datetime.py +++ b/Lib/datetime.py @@ -2358,7 +2358,7 @@ def _name_from_offset(delta): # This is again a requirement for a sane tzinfo class. # # 4. (x+k).s = x.s -# This follows from #2, and that datimetimetz+timedelta preserves tzinfo. +# This follows from #2, and that datetime.timetz+timedelta preserves tzinfo. # # 5. (x+k).n = x.n + k # Again follows from how arithmetic is defined. From 0898dcb3a0400d3c93e27f9feb4c2207eb1a996d Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 3 Feb 2021 15:38:55 -0800 Subject: [PATCH 0928/1314] bpo-42773: fix tests not being run on pushes (GH-24004) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There was a typo, we were checking if the "GITHUB_BASE_REF" string literal was empty instead of the $GITHUB_BASE_REF value. When $GITHUB_BASE_REF is empty, the action that triggered the run was not a pull request, so we always run the full test suite. Signed-off-by: Filipe Laíns (cherry picked from commit 4ac923f2756f835f512339ee181348cc535ab07f) Co-authored-by: Filipe Laíns --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 3d7c9901a8e996..07369ecad27cc8 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -28,7 +28,7 @@ jobs: - name: Check for source changes id: check run: | - if [ -z "GITHUB_BASE_REF" ]; then + if [ -z "$GITHUB_BASE_REF" ]; then echo '::set-output name=run_tests::true' else git fetch origin $GITHUB_BASE_REF --depth=1 From 48d16b4b0fb0d0558bdbc1aee850650a671ecc77 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 4 Feb 2021 11:21:37 -0800 Subject: [PATCH 0929/1314] build(deps): bump actions/upload-artifact from v2.2.1 to v2.2.2 (GH-24411) Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from v2.2.1 to v2.2.2. - [Release notes](https://github.com/actions/upload-artifact/releases) - [Commits](https://github.com/actions/upload-artifact/compare/v2.2.1...e448a9b857ee2131e752b06002bf0e093c65e571) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> (cherry picked from commit aa4caf9887944ab280a87712460e2dd49b55fe5e) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/doc.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/doc.yml b/.github/workflows/doc.yml index 02e7c865cd5684..18efd7f328c251 100644 --- a/.github/workflows/doc.yml +++ b/.github/workflows/doc.yml @@ -36,7 +36,7 @@ jobs: - name: 'Build documentation' run: xvfb-run make -C Doc/ PYTHON=../python SPHINXOPTS="-q -W -j4" doctest suspicious html - name: 'Upload' - uses: actions/upload-artifact@v2.2.1 + uses: actions/upload-artifact@v2.2.2 with: name: doc-html path: Doc/build/html From 29584aa6acbc70091dc23636db51ee1696e65072 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 4 Feb 2021 16:12:34 -0800 Subject: [PATCH 0930/1314] bpo-43102: Set namedtuple __new__'s internal builtins to a dict. (GH-24439) (GH-24452) --- Lib/collections/__init__.py | 2 +- Lib/test/test_collections.py | 5 +++++ .../next/Library/2021-02-03-22-55-27.bpo-43102.TSlZ6J.rst | 2 ++ 3 files changed, 8 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Library/2021-02-03-22-55-27.bpo-43102.TSlZ6J.rst diff --git a/Lib/collections/__init__.py b/Lib/collections/__init__.py index bc69a6757f2948..5bdd3b3516d3b2 100644 --- a/Lib/collections/__init__.py +++ b/Lib/collections/__init__.py @@ -424,7 +424,7 @@ def namedtuple(typename, field_names, *, rename=False, defaults=None, module=Non namespace = { '_tuple_new': tuple_new, - '__builtins__': None, + '__builtins__': {}, '__name__': f'namedtuple_{typename}', } code = f'lambda _cls, {arg_list}: _tuple_new(_cls, ({arg_list}))' diff --git a/Lib/test/test_collections.py b/Lib/test/test_collections.py index 057ec92015cf4f..3ff660cf7a37be 100644 --- a/Lib/test/test_collections.py +++ b/Lib/test/test_collections.py @@ -680,6 +680,11 @@ class NewPoint(tuple): self.assertEqual(np.x, 1) self.assertEqual(np.y, 2) + def test_new_builtins_issue_43102(self): + self.assertEqual( + namedtuple('C', ()).__new__.__globals__['__builtins__'], + {}) + ################################################################################ ### Abstract Base Classes diff --git a/Misc/NEWS.d/next/Library/2021-02-03-22-55-27.bpo-43102.TSlZ6J.rst b/Misc/NEWS.d/next/Library/2021-02-03-22-55-27.bpo-43102.TSlZ6J.rst new file mode 100644 index 00000000000000..985fd68a03a935 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2021-02-03-22-55-27.bpo-43102.TSlZ6J.rst @@ -0,0 +1,2 @@ +The namedtuple __new__ method had its __builtins__ set to None instead +of an actual dictionary. This created problems for introspection tools. From b0b01811bb28d3d6c70846e47fa2f6ba03ed03f1 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 4 Feb 2021 20:44:17 -0800 Subject: [PATCH 0931/1314] bpo-35295: Remove outdated comment. (GH-24453) (cherry picked from commit d938816acf71a74f1bd13fdf0534b3d9ea962e44) Co-authored-by: Inada Naoki --- Include/cpython/unicodeobject.h | 7 ------- 1 file changed, 7 deletions(-) diff --git a/Include/cpython/unicodeobject.h b/Include/cpython/unicodeobject.h index 503b079db275a5..17db79cffbc547 100644 --- a/Include/cpython/unicodeobject.h +++ b/Include/cpython/unicodeobject.h @@ -760,13 +760,6 @@ PyAPI_FUNC(const char *) PyUnicode_AsUTF8AndSize( Use of this API is DEPRECATED since no size information can be extracted from the returned data. - - *** This API is for interpreter INTERNAL USE ONLY and will likely - *** be removed or changed for Python 3.1. - - *** If you need to access the Unicode object as UTF-8 bytes string, - *** please use PyUnicode_AsUTF8String() instead. - */ PyAPI_FUNC(const char *) PyUnicode_AsUTF8(PyObject *unicode); From c8b4375fe1aca1188f57ecf482547abd77e3ef91 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 5 Feb 2021 09:13:40 -0800 Subject: [PATCH 0932/1314] bpo-43132: Fix incorrect handling of PyObject_RichCompareBool() in _zoneinfo (GH-24450) (GH-24457) PyObject_RichCompareBool() returns -1 on error, but this case is not handled by the find_in_strong_cache() function. Any exception raised by PyObject_RichCompareBool() should be propagated. (cherry picked from commit effaec0bb54f381db8ccfa62514bc26b00946b40) Co-authored-by: Zackery Spytz --- Modules/_zoneinfo.c | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/Modules/_zoneinfo.c b/Modules/_zoneinfo.c index 0a4b38a6dc5ad7..f655768496e132 100644 --- a/Modules/_zoneinfo.c +++ b/Modules/_zoneinfo.c @@ -163,7 +163,7 @@ is_leap_year(int year); static size_t _bisect(const int64_t value, const int64_t *arr, size_t size); -static void +static int eject_from_strong_cache(const PyTypeObject *const type, PyObject *key); static void clear_strong_cache(const PyTypeObject *const type); @@ -265,7 +265,7 @@ zoneinfo_new(PyTypeObject *type, PyObject *args, PyObject *kw) } PyObject *instance = zone_from_strong_cache(type, key); - if (instance != NULL) { + if (instance != NULL || PyErr_Occurred()) { return instance; } @@ -428,7 +428,10 @@ zoneinfo_clear_cache(PyObject *cls, PyObject *args, PyObject *kwargs) while ((item = PyIter_Next(iter))) { // Remove from strong cache - eject_from_strong_cache(type, item); + if (eject_from_strong_cache(type, item) < 0) { + Py_DECREF(item); + break; + } // Remove from weak cache PyObject *tmp = PyObject_CallMethodObjArgs(weak_cache, pop, item, @@ -2347,7 +2350,11 @@ find_in_strong_cache(const StrongCacheNode *const root, PyObject *const key) { const StrongCacheNode *node = root; while (node != NULL) { - if (PyObject_RichCompareBool(key, node->key, Py_EQ)) { + int rv = PyObject_RichCompareBool(key, node->key, Py_EQ); + if (rv < 0) { + return NULL; + } + if (rv) { return (StrongCacheNode *)node; } @@ -2361,11 +2368,11 @@ find_in_strong_cache(const StrongCacheNode *const root, PyObject *const key) * * This function is used to enable the per-key functionality in clear_cache. */ -static void +static int eject_from_strong_cache(const PyTypeObject *const type, PyObject *key) { if (type != &PyZoneInfo_ZoneInfoType) { - return; + return 0; } StrongCacheNode *node = find_in_strong_cache(ZONEINFO_STRONG_CACHE, key); @@ -2374,6 +2381,10 @@ eject_from_strong_cache(const PyTypeObject *const type, PyObject *key) strong_cache_node_free(node); } + else if (PyErr_Occurred()) { + return -1; + } + return 0; } /* Moves a node to the front of the LRU cache. From 39aeb9ff9064808b08ec629403edbc36a232369b Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 5 Feb 2021 10:44:23 -0800 Subject: [PATCH 0933/1314] Simple typo fix (GH-24448) (cherry picked from commit 5f18c223391eef8c7d01241b51a7b2429609dd84) Co-authored-by: Andrew Tennikoff --- Doc/howto/urllib2.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/howto/urllib2.rst b/Doc/howto/urllib2.rst index 046a88af62f0b3..12d525771ddc28 100644 --- a/Doc/howto/urllib2.rst +++ b/Doc/howto/urllib2.rst @@ -97,7 +97,7 @@ schemes. For example, you can make an FTP request like so:: In the case of HTTP, there are two extra things that Request objects allow you to do: First, you can pass data to be sent to the server. Second, you can pass -extra information ("metadata") *about* the data or the about request itself, to +extra information ("metadata") *about* the data or about the request itself, to the server - this information is sent as HTTP "headers". Let's look at each of these in turn. From 863eb7170b3017399fb2b786a1e3feb6457e54c2 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 7 Feb 2021 06:14:16 -0800 Subject: [PATCH 0934/1314] bpo-16781: In 'exec' doc, add 'nonlocal' to 'yield' and 'return' (GH-2446) These 3 statements cannot be used at module scope -- nor in exec with one namespace. (cherry picked from commit 0ec57e25c918b859b9f8d464e34e0ac859c2f8b3) Co-authored-by: Terry Jan Reedy Co-authored-by: Terry Jan Reedy --- Doc/library/functions.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Doc/library/functions.rst b/Doc/library/functions.rst index 9d13967c04fffa..990fc10c8cc974 100644 --- a/Doc/library/functions.rst +++ b/Doc/library/functions.rst @@ -508,7 +508,8 @@ are always available. They are listed here in alphabetical order. occurs). [#]_ If it is a code object, it is simply executed. In all cases, the code that's executed is expected to be valid as file input (see the section "File input" in the Reference Manual). Be aware that the - :keyword:`return` and :keyword:`yield` statements may not be used outside of + :keyword:`nonlocal`, :keyword:`yield`, and :keyword:`return` + statements may not be used outside of function definitions even within the context of code passed to the :func:`exec` function. The return value is ``None``. From 917eca700aa341f8544ace43b75d41b477e98b72 Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Wed, 10 Feb 2021 00:55:03 +0800 Subject: [PATCH 0935/1314] bpo-41824: Add versionadded for typing.ForwardRef docs (#24224) (#24493) --- Doc/library/typing.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst index af2cafb8b9969c..688564f1d24f51 100644 --- a/Doc/library/typing.rst +++ b/Doc/library/typing.rst @@ -1714,6 +1714,8 @@ Introspection helpers ``list[ForwardRef("SomeClass")]``. This class should not be instantiated by a user, but may be used by introspection tools. + .. versionadded:: 3.7.4 + Constant -------- From 68d6bc798b34eccabdfbf94e563273759c4cef1f Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 11 Feb 2021 20:33:35 -0800 Subject: [PATCH 0936/1314] bpo-43174: Windows: Use /utf-8 compiler option. (GH-24498) (cherry picked from commit fedd86df2448370cdf62a229fd6f31dc92daf379) Co-authored-by: Inada Naoki --- Misc/NEWS.d/next/Build/2021-02-10-14-11-53.bpo-43174.F9zwXQ.rst | 1 + PCbuild/pyproject.props | 1 + 2 files changed, 2 insertions(+) create mode 100644 Misc/NEWS.d/next/Build/2021-02-10-14-11-53.bpo-43174.F9zwXQ.rst diff --git a/Misc/NEWS.d/next/Build/2021-02-10-14-11-53.bpo-43174.F9zwXQ.rst b/Misc/NEWS.d/next/Build/2021-02-10-14-11-53.bpo-43174.F9zwXQ.rst new file mode 100644 index 00000000000000..64c80188d02f62 --- /dev/null +++ b/Misc/NEWS.d/next/Build/2021-02-10-14-11-53.bpo-43174.F9zwXQ.rst @@ -0,0 +1 @@ +Windows build now uses ``/utf-8`` compiler option. diff --git a/PCbuild/pyproject.props b/PCbuild/pyproject.props index d7762ca1bc685f..98e5ab030321db 100644 --- a/PCbuild/pyproject.props +++ b/PCbuild/pyproject.props @@ -46,6 +46,7 @@ true OnlyExplicitInline OnlyExplicitInline + /utf-8 %(AdditionalOptions) Disabled From df2197f2ec410817299f671e353c2fb0a3d61cbd Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 12 Feb 2021 03:18:38 -0800 Subject: [PATCH 0937/1314] bpo-43204: Fix LibTomCrypt URL in md5module.c and sha*module.c comments (GH-24507) Automerge-Triggered-By: GH:tiran (cherry picked from commit 5ec7d535581bc99918e032891167a96abd224ed6) Co-authored-by: Erlend Egeberg Aasland --- Modules/md5module.c | 2 +- Modules/sha1module.c | 2 +- Modules/sha256module.c | 2 +- Modules/sha512module.c | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Modules/md5module.c b/Modules/md5module.c index e4d9db40f22df3..6ed843376ae784 100644 --- a/Modules/md5module.c +++ b/Modules/md5module.c @@ -74,7 +74,7 @@ typedef struct { * The library is free for all purposes without any express * guarantee it works. * - * Tom St Denis, tomstdenis@gmail.com, http://libtom.org + * Tom St Denis, tomstdenis@gmail.com, https://www.libtom.net */ /* rotate the hard way (platform optimizations could be done) */ diff --git a/Modules/sha1module.c b/Modules/sha1module.c index b0656d83b3ae8b..9c75cc99dba771 100644 --- a/Modules/sha1module.c +++ b/Modules/sha1module.c @@ -74,7 +74,7 @@ typedef struct { * The library is free for all purposes without any express * guarantee it works. * - * Tom St Denis, tomstdenis@gmail.com, http://libtom.org + * Tom St Denis, tomstdenis@gmail.com, https://www.libtom.net */ /* rotate the hard way (platform optimizations could be done) */ diff --git a/Modules/sha256module.c b/Modules/sha256module.c index 8edb1d53828835..9b885c72553081 100644 --- a/Modules/sha256module.c +++ b/Modules/sha256module.c @@ -93,7 +93,7 @@ static void SHAcopy(SHAobject *src, SHAobject *dest) * The library is free for all purposes without any express * guarantee it works. * - * Tom St Denis, tomstdenis@iahu.ca, http://libtom.org + * Tom St Denis, tomstdenis@iahu.ca, https://www.libtom.net */ diff --git a/Modules/sha512module.c b/Modules/sha512module.c index 561ef8ef0e8676..831160c324d559 100644 --- a/Modules/sha512module.c +++ b/Modules/sha512module.c @@ -94,7 +94,7 @@ static void SHAcopy(SHAobject *src, SHAobject *dest) * The library is free for all purposes without any express * guarantee it works. * - * Tom St Denis, tomstdenis@iahu.ca, http://libtom.org + * Tom St Denis, tomstdenis@iahu.ca, https://www.libtom.net */ From 242f6c9ffe3dd8f613942d5364b816cc89c384be Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 12 Feb 2021 21:20:24 -0800 Subject: [PATCH 0938/1314] bpo-43200: Fix link to shutil.copy() in the shutil doc (GH-24505) Co-authored-by: Zackery Spytz Co-authored-by: Terry Jan Reedy (cherry picked from commit 762fe7deed34a1d5294bf82071d318c8427b4893) --- Doc/library/shutil.rst | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Doc/library/shutil.rst b/Doc/library/shutil.rst index 435787c27661d5..d5080da15bba41 100644 --- a/Doc/library/shutil.rst +++ b/Doc/library/shutil.rst @@ -443,8 +443,9 @@ Directory and files operations Platform-dependent efficient copy operations ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Starting from Python 3.8 all functions involving a file copy (:func:`copyfile`, -:func:`copy`, :func:`copy2`, :func:`copytree`, and :func:`move`) may use +Starting from Python 3.8, all functions involving a file copy +(:func:`copyfile`, :func:`~shutil.copy`, :func:`copy2`, +:func:`copytree`, and :func:`move`) may use platform-specific "fast-copy" syscalls in order to copy the file more efficiently (see :issue:`33671`). "fast-copy" means that the copying operation occurs within the kernel, avoiding From c9f07813ab8e664d8c34413c4fc2d4f86c061a92 Mon Sep 17 00:00:00 2001 From: Senthil Kumaran Date: Mon, 15 Feb 2021 10:03:31 -0800 Subject: [PATCH 0939/1314] [3.9] bpo-42967: only use '&' as a query string separator (GH-24297) (#24528) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit (cherry picked from commit fcbe0cb04d35189401c0c880ebfb4311e952d776) * [3.9] bpo-42967: only use '&' as a query string separator (GH-24297) bpo-42967: [security] Address a web cache-poisoning issue reported in urllib.parse.parse_qsl(). urllib.parse will only us "&" as query string separator by default instead of both ";" and "&" as allowed in earlier versions. An optional argument seperator with default value "&" is added to specify the separator. Co-authored-by: Éric Araujo Co-authored-by: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Co-authored-by: Adam Goldschmidt --- Doc/library/cgi.rst | 9 ++- Doc/library/urllib.parse.rst | 21 +++++- Doc/whatsnew/3.6.rst | 13 ++++ Doc/whatsnew/3.7.rst | 13 ++++ Doc/whatsnew/3.8.rst | 13 ++++ Doc/whatsnew/3.9.rst | 13 ++++ Lib/cgi.py | 23 ++++--- Lib/test/test_cgi.py | 29 ++++++-- Lib/test/test_urlparse.py | 68 +++++++++++++------ Lib/urllib/parse.py | 19 ++++-- .../2021-02-14-15-59-16.bpo-42967.YApqDS.rst | 1 + 11 files changed, 176 insertions(+), 46 deletions(-) create mode 100644 Misc/NEWS.d/next/Security/2021-02-14-15-59-16.bpo-42967.YApqDS.rst diff --git a/Doc/library/cgi.rst b/Doc/library/cgi.rst index 4048592e7361f7..e60a3f13595cf0 100644 --- a/Doc/library/cgi.rst +++ b/Doc/library/cgi.rst @@ -277,14 +277,14 @@ These are useful if you want more control, or if you want to employ some of the algorithms implemented in this module in other circumstances. -.. function:: parse(fp=None, environ=os.environ, keep_blank_values=False, strict_parsing=False) +.. function:: parse(fp=None, environ=os.environ, keep_blank_values=False, strict_parsing=False, separator="&") Parse a query in the environment or from a file (the file defaults to - ``sys.stdin``). The *keep_blank_values* and *strict_parsing* parameters are + ``sys.stdin``). The *keep_blank_values*, *strict_parsing* and *separator* parameters are passed to :func:`urllib.parse.parse_qs` unchanged. -.. function:: parse_multipart(fp, pdict, encoding="utf-8", errors="replace") +.. function:: parse_multipart(fp, pdict, encoding="utf-8", errors="replace", separator="&") Parse input of type :mimetype:`multipart/form-data` (for file uploads). Arguments are *fp* for the input file, *pdict* for a dictionary containing @@ -303,6 +303,9 @@ algorithms implemented in this module in other circumstances. Added the *encoding* and *errors* parameters. For non-file fields, the value is now a list of strings, not bytes. + .. versionchanged:: 3.9.2 + Added the *separator* parameter. + .. function:: parse_header(string) diff --git a/Doc/library/urllib.parse.rst b/Doc/library/urllib.parse.rst index 536cf952bda434..38e2986334c807 100644 --- a/Doc/library/urllib.parse.rst +++ b/Doc/library/urllib.parse.rst @@ -165,7 +165,7 @@ or on combining URL components into a URL string. now raise :exc:`ValueError`. -.. function:: parse_qs(qs, keep_blank_values=False, strict_parsing=False, encoding='utf-8', errors='replace', max_num_fields=None) +.. function:: parse_qs(qs, keep_blank_values=False, strict_parsing=False, encoding='utf-8', errors='replace', max_num_fields=None, separator='&') Parse a query string given as a string argument (data of type :mimetype:`application/x-www-form-urlencoded`). Data are returned as a @@ -190,6 +190,9 @@ or on combining URL components into a URL string. read. If set, then throws a :exc:`ValueError` if there are more than *max_num_fields* fields read. + The optional argument *separator* is the symbol to use for separating the + query arguments. It defaults to ``&``. + Use the :func:`urllib.parse.urlencode` function (with the ``doseq`` parameter set to ``True``) to convert such dictionaries into query strings. @@ -201,8 +204,14 @@ or on combining URL components into a URL string. .. versionchanged:: 3.8 Added *max_num_fields* parameter. + .. versionchanged:: 3.9.2 + Added *separator* parameter with the default value of ``&``. Python + versions earlier than Python 3.9.2 allowed using both ``;`` and ``&`` as + query parameter separator. This has been changed to allow only a single + separator key, with ``&`` as the default separator. + -.. function:: parse_qsl(qs, keep_blank_values=False, strict_parsing=False, encoding='utf-8', errors='replace', max_num_fields=None) +.. function:: parse_qsl(qs, keep_blank_values=False, strict_parsing=False, encoding='utf-8', errors='replace', max_num_fields=None, separator='&') Parse a query string given as a string argument (data of type :mimetype:`application/x-www-form-urlencoded`). Data are returned as a list of @@ -226,6 +235,8 @@ or on combining URL components into a URL string. read. If set, then throws a :exc:`ValueError` if there are more than *max_num_fields* fields read. + The optional argument *separator* is the symbol to use for separating the query arguments. It defaults to ``&``. + Use the :func:`urllib.parse.urlencode` function to convert such lists of pairs into query strings. @@ -235,6 +246,12 @@ or on combining URL components into a URL string. .. versionchanged:: 3.8 Added *max_num_fields* parameter. + .. versionchanged:: 3.9.2 + Added *separator* parameter with the default value of ``&``. Python + versions earlier than Python 3.9.2 allowed using both ``;`` and ``&`` as + query parameter separator. This has been changed to allow only a single + separator key, with ``&`` as the default separator. + .. function:: urlunparse(parts) diff --git a/Doc/whatsnew/3.6.rst b/Doc/whatsnew/3.6.rst index 85a6657fdfbdac..03a877a3d91785 100644 --- a/Doc/whatsnew/3.6.rst +++ b/Doc/whatsnew/3.6.rst @@ -2443,3 +2443,16 @@ because of the behavior of the socket option ``SO_REUSEADDR`` in UDP. For more details, see the documentation for ``loop.create_datagram_endpoint()``. (Contributed by Kyle Stanley, Antoine Pitrou, and Yury Selivanov in :issue:`37228`.) + +Notable changes in Python 3.6.13 +================================ + +Earlier Python versions allowed using both ``;`` and ``&`` as +query parameter separators in :func:`urllib.parse.parse_qs` and +:func:`urllib.parse.parse_qsl`. Due to security concerns, and to conform with +newer W3C recommendations, this has been changed to allow only a single +separator key, with ``&`` as the default. This change also affects +:func:`cgi.parse` and :func:`cgi.parse_multipart` as they use the affected +functions internally. For more details, please see their respective +documentation. +(Contributed by Adam Goldschmidt, Senthil Kumaran and Ken Jin in :issue:`42967`.) diff --git a/Doc/whatsnew/3.7.rst b/Doc/whatsnew/3.7.rst index 25b1e1e33e325c..9204cc7fbf8c47 100644 --- a/Doc/whatsnew/3.7.rst +++ b/Doc/whatsnew/3.7.rst @@ -2556,3 +2556,16 @@ because of the behavior of the socket option ``SO_REUSEADDR`` in UDP. For more details, see the documentation for ``loop.create_datagram_endpoint()``. (Contributed by Kyle Stanley, Antoine Pitrou, and Yury Selivanov in :issue:`37228`.) + +Notable changes in Python 3.7.10 +================================ + +Earlier Python versions allowed using both ``;`` and ``&`` as +query parameter separators in :func:`urllib.parse.parse_qs` and +:func:`urllib.parse.parse_qsl`. Due to security concerns, and to conform with +newer W3C recommendations, this has been changed to allow only a single +separator key, with ``&`` as the default. This change also affects +:func:`cgi.parse` and :func:`cgi.parse_multipart` as they use the affected +functions internally. For more details, please see their respective +documentation. +(Contributed by Adam Goldschmidt, Senthil Kumaran and Ken Jin in :issue:`42967`.) diff --git a/Doc/whatsnew/3.8.rst b/Doc/whatsnew/3.8.rst index 0b4820f3333e13..dbc3875aae61b3 100644 --- a/Doc/whatsnew/3.8.rst +++ b/Doc/whatsnew/3.8.rst @@ -2234,3 +2234,16 @@ because of the behavior of the socket option ``SO_REUSEADDR`` in UDP. For more details, see the documentation for ``loop.create_datagram_endpoint()``. (Contributed by Kyle Stanley, Antoine Pitrou, and Yury Selivanov in :issue:`37228`.) + +Notable changes in Python 3.8.8 +=============================== + +Earlier Python versions allowed using both ``;`` and ``&`` as +query parameter separators in :func:`urllib.parse.parse_qs` and +:func:`urllib.parse.parse_qsl`. Due to security concerns, and to conform with +newer W3C recommendations, this has been changed to allow only a single +separator key, with ``&`` as the default. This change also affects +:func:`cgi.parse` and :func:`cgi.parse_multipart` as they use the affected +functions internally. For more details, please see their respective +documentation. +(Contributed by Adam Goldschmidt, Senthil Kumaran and Ken Jin in :issue:`42967`.) diff --git a/Doc/whatsnew/3.9.rst b/Doc/whatsnew/3.9.rst index 68b1e504da89ef..3086930569dc98 100644 --- a/Doc/whatsnew/3.9.rst +++ b/Doc/whatsnew/3.9.rst @@ -1516,3 +1516,16 @@ invalid forms of parameterizing :class:`collections.abc.Callable` which may have passed silently in Python 3.9.1. This :exc:`DeprecationWarning` will become a :exc:`TypeError` in Python 3.10. (Contributed by Ken Jin in :issue:`42195`.) + +urllib.parse +------------ + +Earlier Python versions allowed using both ``;`` and ``&`` as +query parameter separators in :func:`urllib.parse.parse_qs` and +:func:`urllib.parse.parse_qsl`. Due to security concerns, and to conform with +newer W3C recommendations, this has been changed to allow only a single +separator key, with ``&`` as the default. This change also affects +:func:`cgi.parse` and :func:`cgi.parse_multipart` as they use the affected +functions internally. For more details, please see their respective +documentation. +(Contributed by Adam Goldschmidt, Senthil Kumaran and Ken Jin in :issue:`42967`.) diff --git a/Lib/cgi.py b/Lib/cgi.py index 77ab703cc03600..1e880e51848af2 100755 --- a/Lib/cgi.py +++ b/Lib/cgi.py @@ -115,7 +115,8 @@ def closelog(): # 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 +135,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 +158,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 +182,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: @@ -205,7 +209,7 @@ def parse_multipart(fp, pdict, encoding="utf-8", errors="replace"): 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): @@ -315,7 +319,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: @@ -363,6 +367,7 @@ def __init__(self, fp=None, headers=None, outerboundary=b'', 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 @@ -589,7 +594,7 @@ def read_urlencoded(self): 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() @@ -605,7 +610,7 @@ def read_multi(self, environ, keep_blank_values, strict_parsing): 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__ @@ -649,7 +654,7 @@ def read_multi(self, environ, keep_blank_values, strict_parsing): 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 diff --git a/Lib/test/test_cgi.py b/Lib/test/test_cgi.py index 101942de947fb4..4e1506a6468b93 100644 --- a/Lib/test/test_cgi.py +++ b/Lib/test/test_cgi.py @@ -53,12 +53,9 @@ def do_test(buf, method): ("", ValueError("bad query field: ''")), ("&", ValueError("bad query field: ''")), ("&&", ValueError("bad query field: ''")), - (";", ValueError("bad query field: ''")), - (";&;", ValueError("bad query field: ''")), # Should the next few really be valid? ("=", {}), ("=&=", {}), - ("=;=", {}), # This rest seem to make sense ("=a", {'': ['a']}), ("&=a", ValueError("bad query field: ''")), @@ -73,8 +70,6 @@ def do_test(buf, method): ("a=a+b&b=b+c", {'a': ['a b'], 'b': ['b c']}), ("a=a+b&a=b+a", {'a': ['a b', 'b a']}), ("x=1&y=2.0&z=2-3.%2b0", {'x': ['1'], 'y': ['2.0'], 'z': ['2-3.+0']}), - ("x=1;y=2.0&z=2-3.%2b0", {'x': ['1'], 'y': ['2.0'], 'z': ['2-3.+0']}), - ("x=1;y=2.0;z=2-3.%2b0", {'x': ['1'], 'y': ['2.0'], 'z': ['2-3.+0']}), ("Hbc5161168c542333633315dee1182227:key_store_seqid=400006&cuyer=r&view=bustomer&order_id=0bb2e248638833d48cb7fed300000f1b&expire=964546263&lobale=en-US&kid=130003.300038&ss=env", {'Hbc5161168c542333633315dee1182227:key_store_seqid': ['400006'], 'cuyer': ['r'], @@ -201,6 +196,30 @@ def test_strict(self): else: self.assertEqual(fs.getvalue(key), expect_val[0]) + def test_separator(self): + parse_semicolon = [ + ("x=1;y=2.0", {'x': ['1'], 'y': ['2.0']}), + ("x=1;y=2.0;z=2-3.%2b0", {'x': ['1'], 'y': ['2.0'], 'z': ['2-3.+0']}), + (";", ValueError("bad query field: ''")), + (";;", ValueError("bad query field: ''")), + ("=;a", ValueError("bad query field: 'a'")), + (";b=a", ValueError("bad query field: ''")), + ("b;=a", ValueError("bad query field: 'b'")), + ("a=a+b;b=b+c", {'a': ['a b'], 'b': ['b c']}), + ("a=a+b;a=b+a", {'a': ['a b', 'b a']}), + ] + for orig, expect in parse_semicolon: + env = {'QUERY_STRING': orig} + fs = cgi.FieldStorage(separator=';', environ=env) + if isinstance(expect, dict): + for key in expect.keys(): + expect_val = expect[key] + self.assertIn(key, fs) + if len(expect_val) > 1: + self.assertEqual(fs.getvalue(key), expect_val) + else: + self.assertEqual(fs.getvalue(key), expect_val[0]) + def test_log(self): cgi.log("Testing") diff --git a/Lib/test/test_urlparse.py b/Lib/test/test_urlparse.py index 762500789f73ac..3b1c360625b5a6 100644 --- a/Lib/test/test_urlparse.py +++ b/Lib/test/test_urlparse.py @@ -32,16 +32,10 @@ (b"&a=b", [(b'a', b'b')]), (b"a=a+b&b=b+c", [(b'a', b'a b'), (b'b', b'b c')]), (b"a=1&a=2", [(b'a', b'1'), (b'a', b'2')]), - (";", []), - (";;", []), - (";a=b", [('a', 'b')]), - ("a=a+b;b=b+c", [('a', 'a b'), ('b', 'b c')]), - ("a=1;a=2", [('a', '1'), ('a', '2')]), - (b";", []), - (b";;", []), - (b";a=b", [(b'a', b'b')]), - (b"a=a+b;b=b+c", [(b'a', b'a b'), (b'b', b'b c')]), - (b"a=1;a=2", [(b'a', b'1'), (b'a', b'2')]), + (";a=b", [(';a', 'b')]), + ("a=a+b;b=b+c", [('a', 'a b;b=b c')]), + (b";a=b", [(b';a', b'b')]), + (b"a=a+b;b=b+c", [(b'a', b'a b;b=b c')]), ] # Each parse_qs testcase is a two-tuple that contains @@ -68,16 +62,10 @@ (b"&a=b", {b'a': [b'b']}), (b"a=a+b&b=b+c", {b'a': [b'a b'], b'b': [b'b c']}), (b"a=1&a=2", {b'a': [b'1', b'2']}), - (";", {}), - (";;", {}), - (";a=b", {'a': ['b']}), - ("a=a+b;b=b+c", {'a': ['a b'], 'b': ['b c']}), - ("a=1;a=2", {'a': ['1', '2']}), - (b";", {}), - (b";;", {}), - (b";a=b", {b'a': [b'b']}), - (b"a=a+b;b=b+c", {b'a': [b'a b'], b'b': [b'b c']}), - (b"a=1;a=2", {b'a': [b'1', b'2']}), + (";a=b", {';a': ['b']}), + ("a=a+b;b=b+c", {'a': ['a b;b=b c']}), + (b";a=b", {b';a': [b'b']}), + (b"a=a+b;b=b+c", {b'a':[ b'a b;b=b c']}), ] class UrlParseTestCase(unittest.TestCase): @@ -886,10 +874,46 @@ def test_parse_qsl_encoding(self): def test_parse_qsl_max_num_fields(self): with self.assertRaises(ValueError): urllib.parse.parse_qs('&'.join(['a=a']*11), max_num_fields=10) - with self.assertRaises(ValueError): - urllib.parse.parse_qs(';'.join(['a=a']*11), max_num_fields=10) urllib.parse.parse_qs('&'.join(['a=a']*10), max_num_fields=10) + def test_parse_qs_separator(self): + parse_qs_semicolon_cases = [ + (";", {}), + (";;", {}), + (";a=b", {'a': ['b']}), + ("a=a+b;b=b+c", {'a': ['a b'], 'b': ['b c']}), + ("a=1;a=2", {'a': ['1', '2']}), + (b";", {}), + (b";;", {}), + (b";a=b", {b'a': [b'b']}), + (b"a=a+b;b=b+c", {b'a': [b'a b'], b'b': [b'b c']}), + (b"a=1;a=2", {b'a': [b'1', b'2']}), + ] + for orig, expect in parse_qs_semicolon_cases: + with self.subTest(f"Original: {orig!r}, Expected: {expect!r}"): + result = urllib.parse.parse_qs(orig, separator=';') + self.assertEqual(result, expect, "Error parsing %r" % orig) + + + def test_parse_qsl_separator(self): + parse_qsl_semicolon_cases = [ + (";", []), + (";;", []), + (";a=b", [('a', 'b')]), + ("a=a+b;b=b+c", [('a', 'a b'), ('b', 'b c')]), + ("a=1;a=2", [('a', '1'), ('a', '2')]), + (b";", []), + (b";;", []), + (b";a=b", [(b'a', b'b')]), + (b"a=a+b;b=b+c", [(b'a', b'a b'), (b'b', b'b c')]), + (b"a=1;a=2", [(b'a', b'1'), (b'a', b'2')]), + ] + for orig, expect in parse_qsl_semicolon_cases: + with self.subTest(f"Original: {orig!r}, Expected: {expect!r}"): + result = urllib.parse.parse_qsl(orig, separator=';') + self.assertEqual(result, expect, "Error parsing %r" % orig) + + def test_urlencode_sequences(self): # Other tests incidentally urlencode things; test non-covered cases: # Sequence and object values. diff --git a/Lib/urllib/parse.py b/Lib/urllib/parse.py index ea897c3032257b..335e183498d8bd 100644 --- a/Lib/urllib/parse.py +++ b/Lib/urllib/parse.py @@ -662,7 +662,7 @@ def unquote(string, encoding='utf-8', errors='replace'): def parse_qs(qs, keep_blank_values=False, strict_parsing=False, - encoding='utf-8', errors='replace', max_num_fields=None): + encoding='utf-8', errors='replace', max_num_fields=None, separator='&'): """Parse a query given as a string argument. Arguments: @@ -686,12 +686,15 @@ def parse_qs(qs, keep_blank_values=False, strict_parsing=False, max_num_fields: int. If set, then throws a ValueError if there are more than n fields read by parse_qsl(). + separator: str. The symbol to use for separating the query arguments. + Defaults to &. + Returns a dictionary. """ parsed_result = {} pairs = parse_qsl(qs, keep_blank_values, strict_parsing, encoding=encoding, errors=errors, - max_num_fields=max_num_fields) + max_num_fields=max_num_fields, separator=separator) for name, value in pairs: if name in parsed_result: parsed_result[name].append(value) @@ -701,7 +704,7 @@ def parse_qs(qs, keep_blank_values=False, strict_parsing=False, def parse_qsl(qs, keep_blank_values=False, strict_parsing=False, - encoding='utf-8', errors='replace', max_num_fields=None): + encoding='utf-8', errors='replace', max_num_fields=None, separator='&'): """Parse a query given as a string argument. Arguments: @@ -724,19 +727,25 @@ def parse_qsl(qs, keep_blank_values=False, strict_parsing=False, max_num_fields: int. If set, then throws a ValueError if there are more than n fields read by parse_qsl(). + separator: str. The symbol to use for separating the query arguments. + Defaults to &. + Returns a list, as G-d intended. """ qs, _coerce_result = _coerce_args(qs) + if not separator or (not isinstance(separator, (str, bytes))): + raise ValueError("Separator must be of type string or bytes.") + # If max_num_fields is defined then check that the number of fields # is less than max_num_fields. This prevents a memory exhaustion DOS # attack via post bodies with many fields. if max_num_fields is not None: - num_fields = 1 + qs.count('&') + qs.count(';') + num_fields = 1 + qs.count(separator) if max_num_fields < num_fields: raise ValueError('Max number of fields exceeded') - pairs = [s2 for s1 in qs.split('&') for s2 in s1.split(';')] + pairs = [s1 for s1 in qs.split(separator)] r = [] for name_value in pairs: if not name_value and not strict_parsing: diff --git a/Misc/NEWS.d/next/Security/2021-02-14-15-59-16.bpo-42967.YApqDS.rst b/Misc/NEWS.d/next/Security/2021-02-14-15-59-16.bpo-42967.YApqDS.rst new file mode 100644 index 00000000000000..f08489b41494ea --- /dev/null +++ b/Misc/NEWS.d/next/Security/2021-02-14-15-59-16.bpo-42967.YApqDS.rst @@ -0,0 +1 @@ +Fix web cache poisoning vulnerability by defaulting the query args separator to ``&``, and allowing the user to choose a custom separator. From 9cc70bc22040932d257f6ba04bab812134110a74 Mon Sep 17 00:00:00 2001 From: Pablo Galindo Date: Mon, 15 Feb 2021 23:02:41 +0000 Subject: [PATCH 0940/1314] [3.9] Minor improvements to the convolve() recipe (GH-24520) --- Doc/library/itertools.rst | 4 ++-- Doc/tools/susp-ignored.csv | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Doc/library/itertools.rst b/Doc/library/itertools.rst index ff5b60d70ff4ed..6da55f8a3f49cf 100644 --- a/Doc/library/itertools.rst +++ b/Doc/library/itertools.rst @@ -774,9 +774,9 @@ which incur interpreter overhead. # convolve(data, [0.25, 0.25, 0.25, 0.25]) --> Moving average (blur) # convolve(data, [1, -1]) --> 1st finite difference (1st derivative) # convolve(data, [1, -2, 1]) --> 2nd finite difference (2nd derivative) - kernel = list(reversed(kernel)) + kernel = tuple(kernel)[::-1] n = len(kernel) - window = collections.deque([0] * n, maxlen=n) + window = collections.deque([0], maxlen=n) * n for x in chain(signal, repeat(0, n-1)): window.append(x) yield sum(map(operator.mul, kernel, window)) diff --git a/Doc/tools/susp-ignored.csv b/Doc/tools/susp-ignored.csv index c9777c6be9334d..9f0c42a9bb5abc 100644 --- a/Doc/tools/susp-ignored.csv +++ b/Doc/tools/susp-ignored.csv @@ -171,6 +171,7 @@ library/ipaddress,,:db00,2001:db00::0/ffff:ff00:: library/ipaddress,,::,2001:db00::0/ffff:ff00:: library/itertools,,:step,elements from seq[start:stop:step] library/itertools,,:stop,elements from seq[start:stop:step] +library/itertools,,::,kernel = tuple(kernel)[::-1] library/logging.handlers,,:port,host:port library/mmap,,:i2,obj[i1:i2] library/multiprocessing,,`,# Add more tasks using `put()` From 85fd9f4e45ee95e2608dbc8cc6d4fe28e4d2abc4 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 15 Feb 2021 16:18:07 -0800 Subject: [PATCH 0941/1314] bpo-42819, readline: Disable bracketed paste (GH-24108) (GH-24545) (cherry picked from commit 755f3c1521b422bc2177013d289f5439975fdc4f) Co-authored-by: Dustin Rodrigues Co-authored-by: Dustin Rodrigues --- Misc/ACKS | 1 + .../2021-01-04-23-54-34.bpo-42819.4KO6wU.rst | 8 +++++++ Modules/readline.c | 23 +++++++++++++++++++ 3 files changed, 32 insertions(+) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2021-01-04-23-54-34.bpo-42819.4KO6wU.rst diff --git a/Misc/ACKS b/Misc/ACKS index 58a4accd13451a..73d35c2d86bdc0 100644 --- a/Misc/ACKS +++ b/Misc/ACKS @@ -1444,6 +1444,7 @@ Mark Roddy Kevin Rodgers Sean Rodman Giampaolo Rodola +Dustin Rodrigues Mauro S. M. Rodrigues Elson Rodriguez Adi Roiban diff --git a/Misc/NEWS.d/next/Core and Builtins/2021-01-04-23-54-34.bpo-42819.4KO6wU.rst b/Misc/NEWS.d/next/Core and Builtins/2021-01-04-23-54-34.bpo-42819.4KO6wU.rst new file mode 100644 index 00000000000000..d067f0bfa76448 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2021-01-04-23-54-34.bpo-42819.4KO6wU.rst @@ -0,0 +1,8 @@ +:mod:`readline`: Explicitly disable bracketed paste in the interactive +interpreter, even if it's set in the inputrc, is enabled by default (eg GNU +Readline 8.1), or a user calls ``readline.read_init_file()``. The Python REPL +has not implemented bracketed paste support. Also, bracketed mode writes the +``"\x1b[?2004h"`` escape sequence into stdout which causes test failures in +applications that don't support it. It can still be explicitly enabled by +calling ``readline.parse_and_bind("set enable-bracketed-paste on")``. Patch by +Dustin Rodrigues. diff --git a/Modules/readline.c b/Modules/readline.c index 12d6cc78e38a77..1e74f997b07112 100644 --- a/Modules/readline.c +++ b/Modules/readline.c @@ -146,6 +146,26 @@ decode(const char *s) } +/* +Explicitly disable bracketed paste in the interactive interpreter, even if it's +set in the inputrc, is enabled by default (eg GNU Readline 8.1), or a user calls +readline.read_init_file(). The Python REPL has not implemented bracketed +paste support. Also, bracketed mode writes the "\x1b[?2004h" escape sequence +into stdout which causes test failures in applications that don't support it. +It can still be explicitly enabled by calling readline.parse_and_bind("set +enable-bracketed-paste on"). See bpo-42819 for more details. + +This should be removed if bracketed paste mode is implemented (bpo-39820). +*/ + +static void +disable_bracketed_paste(void) +{ + if (!using_libedit_emulation) { + rl_variable_bind ("enable-bracketed-paste", "off"); + } +} + /* Exported function to send one line to readline's init file parser */ static PyObject * @@ -192,6 +212,7 @@ read_init_file(PyObject *self, PyObject *args) errno = rl_read_init_file(NULL); if (errno) return PyErr_SetFromErrno(PyExc_OSError); + disable_bracketed_paste(); Py_RETURN_NONE; } @@ -1152,6 +1173,8 @@ setup_readline(readlinestate *mod_state) else rl_initialize(); + disable_bracketed_paste(); + RESTORE_LOCALE(saved_locale) return 0; } From 4064156d62622c1009d32bb87ba17a5e9ecb9d37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Langa?= Date: Tue, 16 Feb 2021 21:10:19 +0100 Subject: [PATCH 0942/1314] Python 3.9.2rc1 --- Include/patchlevel.h | 8 +- Lib/pydoc_data/topics.py | 141 ++-- Misc/NEWS.d/3.9.2rc1.rst | 746 ++++++++++++++++++ .../2020-02-28-14-33-15.bpo-29076.Gtixi5.rst | 1 - .../2020-12-13-14-43-10.bpo-42598.7ipr5H.rst | 2 - .../2020-12-20-02-35-28.bpo-42604.gRd89w.rst | 4 - .../2021-01-04-05-07-30.bpo-42692.OO11SN.rst | 1 - .../2021-02-10-14-11-53.bpo-43174.F9zwXQ.rst | 1 - .../2020-03-24-09-27-10.bpo-40052.27P2KG.rst | 2 - .../2020-12-10-10-43-03.bpo-42591.CXNY8G.rst | 3 - .../2021-01-27-10-27-47.bpo-43030.loDcD_.rst | 2 - .../2020-11-20-00-57-47.bpo-42195.HeqcpS.rst | 11 - .../2020-12-02-20-23-31.bpo-42536.Kx3ZOu.rst | 26 - .../2020-12-04-17-17-44.bpo-32381.NY5t2S.rst | 3 - .../2020-12-31-20-58-22.bpo-40631.deRMCx.rst | 2 - .../2021-01-03-00-20-38.bpo-42806.mLAobJ.rst | 2 - .../2021-01-04-23-54-34.bpo-42819.4KO6wU.rst | 8 - .../2020-12-16-21-06-16.bpo-17140.1leSEg.rst | 1 - .../2021-01-07-12-08-59.bpo-42811.ePF7EC.rst | 2 - .../2021-01-20-23-03-49.bpo-40304.-LK7Ps.rst | 2 - .../2019-06-30-20-31-09.bpo-32631.e7_4BG.rst | 2 - .../2019-11-14-23-41-07.bpo-23544.3etemb.rst | 2 - .../2021-01-10-01-25-43.bpo-33065.zmyHYJ.rst | 1 - .../2021-01-26-18-12-17.bpo-43008.mbQUc7.rst | 2 - .../2018-04-23-13-44-10.bpo-33289.anBnUr.rst | 2 - .../2019-12-16-17-55-31.bpo-39068.Ti3f9P.rst | 2 - .../2020-03-29-21-32-00.bpo-40084.MCYwcv.rst | 1 - .../2020-07-13-19-43-11.bpo-40219.MUoJEP.rst | 1 - .../2020-08-21-15-24-14.bpo-41604.rTXleO.rst | 2 - .../2020-09-30-13-35-29.bpo-41891.pNAeYI.rst | 1 - .../2020-10-01-16-17-11.bpo-41889.qLkNh8.rst | 1 - .../2020-10-02-10-19-49.bpo-41907.wiIEsz.rst | 1 - .../2020-10-11-13-48-03.bpo-42005.Jq6Az-.rst | 2 - .../2020-10-11-21-43-03.bpo-39101.-I49Pm.rst | 1 - .../2020-10-17-12-42-08.bpo-42059.ZGMZ3D.rst | 1 - .../2020-10-20-08-28-26.bpo-39825.n6KnG0.rst | 5 - .../2020-10-29-09-22-56.bpo-42163.O4VcCY.rst | 1 - .../2020-11-14-13-46-27.bpo-42318.wYAcBD.rst | 1 - .../2020-11-17-14-30-12.bpo-42383.ubl0Y_.rst | 2 - .../2020-11-17-14-32-39.bpo-42384.1ZnQSn.rst | 1 - .../2020-11-19-04-13-53.bpo-42375.U8bp4s.rst | 1 - .../2020-11-20-19-00-27.bpo-34463.aJcm56.rst | 1 - .../2020-11-22-11-22-28.bpo-42388.LMgM6B.rst | 2 - .../2020-12-02-07-37-59.bpo-42532.ObNep_.rst | 1 - .../2020-12-08-22-43-35.bpo-42678.ba9ktU.rst | 1 - .../2020-12-09-10-59-16.bpo-42517.FKEVcZ.rst | 2 - .../2020-12-14-08-23-57.bpo-36541.qdEtZv.rst | 2 - .../2020-12-15-10-00-04.bpo-42644.XgLCNx.rst | 3 - .../2020-12-15-17-51-27.bpo-42630.jf4jBl.rst | 4 - .../2020-12-16-16-16-33.bpo-37961.jrESEq.rst | 1 - .../2020-12-20-22-50-15.bpo-42681.lDO6jb.rst | 1 - .../2020-12-23-19-43-06.bpo-42727.WH3ODh.rst | 2 - .../2020-12-25-12-32-47.bpo-42655.W5ytpV.rst | 2 - .../2020-12-27-18-47-01.bpo-23328._xqepZ.rst | 1 - .../2020-12-27-21-22-01.bpo-42756.dHMPJ9.rst | 2 - .../2020-12-27-22-19-26.bpo-42759.lGi_03.rst | 3 - .../2021-01-05-21-26-29.bpo-41748.KdC0w3.rst | 2 - .../2021-01-07-11-44-22.bpo-42851.uyQFyd.rst | 1 - .../2021-01-08-15-49-20.bpo-42780.rtqi6B.rst | 1 - .../2021-01-15-00-23-50.bpo-42931.QD6U2B.rst | 1 - .../2021-01-18-10-41-44.bpo-42944.RrONvy.rst | 1 - .../2021-02-02-20-23-31.bpo-43108.lqcCZ6.rst | 1 - .../2021-02-03-22-55-27.bpo-43102.TSlZ6J.rst | 2 - .../2021-01-18-09-27-31.bpo-42938.4Zn4Mp.rst | 2 - .../2021-02-14-15-59-16.bpo-42967.YApqDS.rst | 1 - .../2020-05-30-10-56-38.bpo-40810.LPqDLQ.rst | 1 - .../2021-01-01-08-52-36.bpo-42794.-7-XGz.rst | 2 - .../2020-12-16-09-10-32.bpo-42613.J-jnm5.rst | 2 - .../2020-12-23-19-42-11.bpo-42726.a5EkTv.rst | 2 - .../2020-12-07-11-40-52.bpo-42584.AsYnVX.rst | 1 - .../2021-01-05-20-36-40.bpo-41837.bmS7vB.rst | 1 - .../2020-12-07-11-37-35.bpo-42584.LygmqQ.rst | 1 - .../2021-01-04-00-48-08.bpo-41837.dX-unJ.rst | 1 - .../2021-01-04-01-17-17.bpo-42361.eolZAi.rst | 2 - .../2021-01-26-14-36-11.bpo-42504.ZxWt71.rst | 3 - README.rst | 4 +- 76 files changed, 828 insertions(+), 233 deletions(-) create mode 100644 Misc/NEWS.d/3.9.2rc1.rst delete mode 100644 Misc/NEWS.d/next/Build/2020-02-28-14-33-15.bpo-29076.Gtixi5.rst delete mode 100644 Misc/NEWS.d/next/Build/2020-12-13-14-43-10.bpo-42598.7ipr5H.rst delete mode 100644 Misc/NEWS.d/next/Build/2020-12-20-02-35-28.bpo-42604.gRd89w.rst delete mode 100644 Misc/NEWS.d/next/Build/2021-01-04-05-07-30.bpo-42692.OO11SN.rst delete mode 100644 Misc/NEWS.d/next/Build/2021-02-10-14-11-53.bpo-43174.F9zwXQ.rst delete mode 100644 Misc/NEWS.d/next/C API/2020-03-24-09-27-10.bpo-40052.27P2KG.rst delete mode 100644 Misc/NEWS.d/next/C API/2020-12-10-10-43-03.bpo-42591.CXNY8G.rst delete mode 100644 Misc/NEWS.d/next/C API/2021-01-27-10-27-47.bpo-43030.loDcD_.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2020-11-20-00-57-47.bpo-42195.HeqcpS.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2020-12-02-20-23-31.bpo-42536.Kx3ZOu.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2020-12-04-17-17-44.bpo-32381.NY5t2S.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2020-12-31-20-58-22.bpo-40631.deRMCx.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2021-01-03-00-20-38.bpo-42806.mLAobJ.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2021-01-04-23-54-34.bpo-42819.4KO6wU.rst delete mode 100644 Misc/NEWS.d/next/Documentation/2020-12-16-21-06-16.bpo-17140.1leSEg.rst delete mode 100644 Misc/NEWS.d/next/Documentation/2021-01-07-12-08-59.bpo-42811.ePF7EC.rst delete mode 100644 Misc/NEWS.d/next/Documentation/2021-01-20-23-03-49.bpo-40304.-LK7Ps.rst delete mode 100644 Misc/NEWS.d/next/IDLE/2019-06-30-20-31-09.bpo-32631.e7_4BG.rst delete mode 100644 Misc/NEWS.d/next/IDLE/2019-11-14-23-41-07.bpo-23544.3etemb.rst delete mode 100644 Misc/NEWS.d/next/IDLE/2021-01-10-01-25-43.bpo-33065.zmyHYJ.rst delete mode 100644 Misc/NEWS.d/next/IDLE/2021-01-26-18-12-17.bpo-43008.mbQUc7.rst delete mode 100644 Misc/NEWS.d/next/Library/2018-04-23-13-44-10.bpo-33289.anBnUr.rst delete mode 100644 Misc/NEWS.d/next/Library/2019-12-16-17-55-31.bpo-39068.Ti3f9P.rst delete mode 100644 Misc/NEWS.d/next/Library/2020-03-29-21-32-00.bpo-40084.MCYwcv.rst delete mode 100644 Misc/NEWS.d/next/Library/2020-07-13-19-43-11.bpo-40219.MUoJEP.rst delete mode 100644 Misc/NEWS.d/next/Library/2020-08-21-15-24-14.bpo-41604.rTXleO.rst delete mode 100644 Misc/NEWS.d/next/Library/2020-09-30-13-35-29.bpo-41891.pNAeYI.rst delete mode 100644 Misc/NEWS.d/next/Library/2020-10-01-16-17-11.bpo-41889.qLkNh8.rst delete mode 100644 Misc/NEWS.d/next/Library/2020-10-02-10-19-49.bpo-41907.wiIEsz.rst delete mode 100644 Misc/NEWS.d/next/Library/2020-10-11-13-48-03.bpo-42005.Jq6Az-.rst delete mode 100644 Misc/NEWS.d/next/Library/2020-10-11-21-43-03.bpo-39101.-I49Pm.rst delete mode 100644 Misc/NEWS.d/next/Library/2020-10-17-12-42-08.bpo-42059.ZGMZ3D.rst delete mode 100644 Misc/NEWS.d/next/Library/2020-10-20-08-28-26.bpo-39825.n6KnG0.rst delete mode 100644 Misc/NEWS.d/next/Library/2020-10-29-09-22-56.bpo-42163.O4VcCY.rst delete mode 100644 Misc/NEWS.d/next/Library/2020-11-14-13-46-27.bpo-42318.wYAcBD.rst delete mode 100644 Misc/NEWS.d/next/Library/2020-11-17-14-30-12.bpo-42383.ubl0Y_.rst delete mode 100644 Misc/NEWS.d/next/Library/2020-11-17-14-32-39.bpo-42384.1ZnQSn.rst delete mode 100644 Misc/NEWS.d/next/Library/2020-11-19-04-13-53.bpo-42375.U8bp4s.rst delete mode 100644 Misc/NEWS.d/next/Library/2020-11-20-19-00-27.bpo-34463.aJcm56.rst delete mode 100644 Misc/NEWS.d/next/Library/2020-11-22-11-22-28.bpo-42388.LMgM6B.rst delete mode 100644 Misc/NEWS.d/next/Library/2020-12-02-07-37-59.bpo-42532.ObNep_.rst delete mode 100644 Misc/NEWS.d/next/Library/2020-12-08-22-43-35.bpo-42678.ba9ktU.rst delete mode 100644 Misc/NEWS.d/next/Library/2020-12-09-10-59-16.bpo-42517.FKEVcZ.rst delete mode 100644 Misc/NEWS.d/next/Library/2020-12-14-08-23-57.bpo-36541.qdEtZv.rst delete mode 100644 Misc/NEWS.d/next/Library/2020-12-15-10-00-04.bpo-42644.XgLCNx.rst delete mode 100644 Misc/NEWS.d/next/Library/2020-12-15-17-51-27.bpo-42630.jf4jBl.rst delete mode 100644 Misc/NEWS.d/next/Library/2020-12-16-16-16-33.bpo-37961.jrESEq.rst delete mode 100644 Misc/NEWS.d/next/Library/2020-12-20-22-50-15.bpo-42681.lDO6jb.rst delete mode 100644 Misc/NEWS.d/next/Library/2020-12-23-19-43-06.bpo-42727.WH3ODh.rst delete mode 100644 Misc/NEWS.d/next/Library/2020-12-25-12-32-47.bpo-42655.W5ytpV.rst delete mode 100644 Misc/NEWS.d/next/Library/2020-12-27-18-47-01.bpo-23328._xqepZ.rst delete mode 100644 Misc/NEWS.d/next/Library/2020-12-27-21-22-01.bpo-42756.dHMPJ9.rst delete mode 100644 Misc/NEWS.d/next/Library/2020-12-27-22-19-26.bpo-42759.lGi_03.rst delete mode 100644 Misc/NEWS.d/next/Library/2021-01-05-21-26-29.bpo-41748.KdC0w3.rst delete mode 100644 Misc/NEWS.d/next/Library/2021-01-07-11-44-22.bpo-42851.uyQFyd.rst delete mode 100644 Misc/NEWS.d/next/Library/2021-01-08-15-49-20.bpo-42780.rtqi6B.rst delete mode 100644 Misc/NEWS.d/next/Library/2021-01-15-00-23-50.bpo-42931.QD6U2B.rst delete mode 100644 Misc/NEWS.d/next/Library/2021-01-18-10-41-44.bpo-42944.RrONvy.rst delete mode 100644 Misc/NEWS.d/next/Library/2021-02-02-20-23-31.bpo-43108.lqcCZ6.rst delete mode 100644 Misc/NEWS.d/next/Library/2021-02-03-22-55-27.bpo-43102.TSlZ6J.rst delete mode 100644 Misc/NEWS.d/next/Security/2021-01-18-09-27-31.bpo-42938.4Zn4Mp.rst delete mode 100644 Misc/NEWS.d/next/Security/2021-02-14-15-59-16.bpo-42967.YApqDS.rst delete mode 100644 Misc/NEWS.d/next/Tests/2020-05-30-10-56-38.bpo-40810.LPqDLQ.rst delete mode 100644 Misc/NEWS.d/next/Tests/2021-01-01-08-52-36.bpo-42794.-7-XGz.rst delete mode 100644 Misc/NEWS.d/next/Tools-Demos/2020-12-16-09-10-32.bpo-42613.J-jnm5.rst delete mode 100644 Misc/NEWS.d/next/Tools-Demos/2020-12-23-19-42-11.bpo-42726.a5EkTv.rst delete mode 100644 Misc/NEWS.d/next/Windows/2020-12-07-11-40-52.bpo-42584.AsYnVX.rst delete mode 100644 Misc/NEWS.d/next/Windows/2021-01-05-20-36-40.bpo-41837.bmS7vB.rst delete mode 100644 Misc/NEWS.d/next/macOS/2020-12-07-11-37-35.bpo-42584.LygmqQ.rst delete mode 100644 Misc/NEWS.d/next/macOS/2021-01-04-00-48-08.bpo-41837.dX-unJ.rst delete mode 100644 Misc/NEWS.d/next/macOS/2021-01-04-01-17-17.bpo-42361.eolZAi.rst delete mode 100644 Misc/NEWS.d/next/macOS/2021-01-26-14-36-11.bpo-42504.ZxWt71.rst diff --git a/Include/patchlevel.h b/Include/patchlevel.h index 253421378be4aa..ef02372f8b22ca 100644 --- a/Include/patchlevel.h +++ b/Include/patchlevel.h @@ -18,12 +18,12 @@ /*--start constants--*/ #define PY_MAJOR_VERSION 3 #define PY_MINOR_VERSION 9 -#define PY_MICRO_VERSION 1 -#define PY_RELEASE_LEVEL PY_RELEASE_LEVEL_FINAL -#define PY_RELEASE_SERIAL 0 +#define PY_MICRO_VERSION 2 +#define PY_RELEASE_LEVEL PY_RELEASE_LEVEL_GAMMA +#define PY_RELEASE_SERIAL 1 /* Version as a string */ -#define PY_VERSION "3.9.1+" +#define PY_VERSION "3.9.2rc1" /*--end constants--*/ /* Version as a single 4-byte hex number, e.g. 0x010502B2 == 1.5.2b2. diff --git a/Lib/pydoc_data/topics.py b/Lib/pydoc_data/topics.py index d8dd8c536aa708..acaae371aeb229 100644 --- a/Lib/pydoc_data/topics.py +++ b/Lib/pydoc_data/topics.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -# Autogenerated by Sphinx on Mon Dec 7 15:00:07 2020 +# Autogenerated by Sphinx on Tue Feb 16 21:03:59 2021 topics = {'assert': 'The "assert" statement\n' '**********************\n' '\n' @@ -459,13 +459,12 @@ '\n' ' async_for_stmt ::= "async" for_stmt\n' '\n' - 'An *asynchronous iterable* is able to call asynchronous code in ' - 'its\n' - '*iter* implementation, and *asynchronous iterator* can call\n' - 'asynchronous code in its *next* method.\n' + 'An *asynchronous iterable* provides an "__aiter__" method that\n' + 'directly returns an *asynchronous iterator*, which can call\n' + 'asynchronous code in its "__anext__" method.\n' '\n' 'The "async for" statement allows convenient iteration over\n' - 'asynchronous iterators.\n' + 'asynchronous iterables.\n' '\n' 'The following code:\n' '\n' @@ -2381,8 +2380,9 @@ 'compatible\n' 'with an exception if it is the class or a base class of the ' 'exception\n' - 'object or a tuple containing an item compatible with the ' - 'exception.\n' + 'object, or a tuple containing an item that is the class or a ' + 'base\n' + 'class of the exception object.\n' '\n' 'If no except clause matches the exception, the search for an ' 'exception\n' @@ -2991,13 +2991,12 @@ '\n' ' async_for_stmt ::= "async" for_stmt\n' '\n' - 'An *asynchronous iterable* is able to call asynchronous code in ' - 'its\n' - '*iter* implementation, and *asynchronous iterator* can call\n' - 'asynchronous code in its *next* method.\n' + 'An *asynchronous iterable* provides an "__aiter__" method that\n' + 'directly returns an *asynchronous iterator*, which can call\n' + 'asynchronous code in its "__anext__" method.\n' '\n' 'The "async for" statement allows convenient iteration over\n' - 'asynchronous iterators.\n' + 'asynchronous iterables.\n' '\n' 'The following code:\n' '\n' @@ -5530,44 +5529,51 @@ ' | | formats the result in either fixed-point ' 'format or in |\n' ' | | scientific notation, depending on its ' - 'magnitude. The |\n' - ' | | precise rules are as follows: suppose that ' - 'the result |\n' + 'magnitude. A |\n' + ' | | precision of "0" is treated as equivalent ' + 'to a precision |\n' + ' | | of "1". The precise rules are as follows: ' + 'suppose that |\n' + ' | | the result formatted with presentation ' + 'type "\'e\'" and |\n' + ' | | precision "p-1" would have exponent ' + '"exp". Then, if "m <= |\n' + ' | | exp < p", where "m" is -4 for floats and ' + '-6 for |\n' + ' | | "Decimals", the number is formatted with ' + 'presentation type |\n' + ' | | "\'f\'" and precision "p-1-exp". ' + 'Otherwise, the number is |\n' ' | | formatted with presentation type "\'e\'" ' - 'and precision "p-1" |\n' - ' | | would have exponent "exp". Then, if "m <= ' - 'exp < p", where |\n' - ' | | "m" is -4 for floats and -6 for ' - '"Decimals", the number is |\n' - ' | | formatted with presentation type "\'f\'" ' 'and precision |\n' - ' | | "p-1-exp". Otherwise, the number is ' - 'formatted with |\n' - ' | | presentation type "\'e\'" and precision ' - '"p-1". In both cases |\n' - ' | | insignificant trailing zeros are removed ' - 'from the |\n' - ' | | significand, and the decimal point is also ' - 'removed if |\n' - ' | | there are no remaining digits following ' - 'it, unless the |\n' - ' | | "\'#\'" option is used. Positive and ' - 'negative infinity, |\n' - ' | | positive and negative zero, and nans, are ' - 'formatted as |\n' - ' | | "inf", "-inf", "0", "-0" and "nan" ' - 'respectively, |\n' - ' | | regardless of the precision. A precision ' - 'of "0" is |\n' - ' | | treated as equivalent to a precision of ' - '"1". With no |\n' - ' | | precision given, uses a precision of "6" ' - 'significant |\n' - ' | | digits for "float", and shows all ' - 'coefficient digits for |\n' - ' | | ' - '"Decimal". ' - '|\n' + ' | | "p-1". In both cases insignificant ' + 'trailing zeros are |\n' + ' | | removed from the significand, and the ' + 'decimal point is |\n' + ' | | also removed if there are no remaining ' + 'digits following |\n' + ' | | it, unless the "\'#\'" option is used. ' + 'With no precision |\n' + ' | | given, uses a precision of "6" significant ' + 'digits for |\n' + ' | | "float". For "Decimal", the coefficient of ' + 'the result is |\n' + ' | | formed from the coefficient digits of the ' + 'value; |\n' + ' | | scientific notation is used for values ' + 'smaller than "1e-6" |\n' + ' | | in absolute value and values where the ' + 'place value of the |\n' + ' | | least significant digit is larger than 1, ' + 'and fixed-point |\n' + ' | | notation is used otherwise. Positive and ' + 'negative |\n' + ' | | infinity, positive and negative zero, and ' + 'nans, are |\n' + ' | | formatted as "inf", "-inf", "0", "-0" and ' + '"nan" |\n' + ' | | respectively, regardless of the ' + 'precision. |\n' ' ' '+-----------+------------------------------------------------------------+\n' ' | "\'G\'" | General format. Same as "\'g\'" except ' @@ -5592,19 +5598,24 @@ 'percent sign. |\n' ' ' '+-----------+------------------------------------------------------------+\n' - ' | None | Similar to "\'g\'", except that ' - 'fixed-point notation, when |\n' - ' | | used, has at least one digit past the ' - 'decimal point. The |\n' - ' | | default precision is as high as needed to ' - 'represent the |\n' - ' | | particular value. The overall effect is to ' - 'match the |\n' - ' | | output of "str()" as altered by the other ' - 'format |\n' - ' | | ' - 'modifiers. ' - '|\n' + ' | None | For "float" this is the same as "\'g\'", ' + 'except that when |\n' + ' | | fixed-point notation is used to format the ' + 'result, it |\n' + ' | | always includes at least one digit past ' + 'the decimal point. |\n' + ' | | The precision used is as large as needed ' + 'to represent the |\n' + ' | | given value faithfully. For "Decimal", ' + 'this is the same |\n' + ' | | as either "\'g\'" or "\'G\'" depending on ' + 'the value of |\n' + ' | | "context.capitals" for the current decimal ' + 'context. The |\n' + ' | | overall effect is to match the output of ' + '"str()" as |\n' + ' | | altered by the other format ' + 'modifiers. |\n' ' ' '+-----------+------------------------------------------------------------+\n' '\n' @@ -7950,7 +7961,7 @@ 'immediate\n' ' subclasses. This method returns a list of all those ' 'references\n' - ' still alive. Example:\n' + ' still alive. The list is in definition order. Example:\n' '\n' ' >>> int.__subclasses__()\n' " []\n" @@ -11259,7 +11270,8 @@ 'object is “compatible†with the exception. An object is compatible\n' 'with an exception if it is the class or a base class of the ' 'exception\n' - 'object or a tuple containing an item compatible with the exception.\n' + 'object, or a tuple containing an item that is the class or a base\n' + 'class of the exception object.\n' '\n' 'If no except clause matches the exception, the search for an ' 'exception\n' @@ -11480,7 +11492,6 @@ ' There are two types of integers:\n' '\n' ' Integers ("int")\n' - '\n' ' These represent numbers in an unlimited range, subject to\n' ' available (virtual) memory only. For the purpose of ' 'shift\n' diff --git a/Misc/NEWS.d/3.9.2rc1.rst b/Misc/NEWS.d/3.9.2rc1.rst new file mode 100644 index 00000000000000..ba40d92281a1a4 --- /dev/null +++ b/Misc/NEWS.d/3.9.2rc1.rst @@ -0,0 +1,746 @@ +.. bpo: 42967 +.. date: 2021-02-14-15-59-16 +.. nonce: YApqDS +.. release date: 2021-02-16 +.. section: Security + +Fix web cache poisoning vulnerability by defaulting the query args separator +to ``&``, and allowing the user to choose a custom separator. + +.. + +.. bpo: 42938 +.. date: 2021-01-18-09-27-31 +.. nonce: 4Zn4Mp +.. section: Security + +Avoid static buffers when computing the repr of :class:`ctypes.c_double` and +:class:`ctypes.c_longdouble` values. + +.. + +.. bpo: 42819 +.. date: 2021-01-04-23-54-34 +.. nonce: 4KO6wU +.. section: Core and Builtins + +:mod:`readline`: Explicitly disable bracketed paste in the interactive +interpreter, even if it's set in the inputrc, is enabled by default (eg GNU +Readline 8.1), or a user calls ``readline.read_init_file()``. The Python +REPL has not implemented bracketed paste support. Also, bracketed mode +writes the ``"\x1b[?2004h"`` escape sequence into stdout which causes test +failures in applications that don't support it. It can still be explicitly +enabled by calling ``readline.parse_and_bind("set enable-bracketed-paste +on")``. Patch by Dustin Rodrigues. + +.. + +.. bpo: 42806 +.. date: 2021-01-03-00-20-38 +.. nonce: mLAobJ +.. section: Core and Builtins + +Fix the column offsets for f-strings :mod:`ast` nodes surrounded by +parentheses and for nodes that spawn multiple lines. Patch by Pablo Galindo. + +.. + +.. bpo: 40631 +.. date: 2020-12-31-20-58-22 +.. nonce: deRMCx +.. section: Core and Builtins + +Fix regression where a single parenthesized starred expression was a valid +assignment target. + +.. + +.. bpo: 32381 +.. date: 2020-12-04-17-17-44 +.. nonce: NY5t2S +.. section: Core and Builtins + +Fix encoding name when running a ``.pyc`` file on Windows: +:c:func:`PyRun_SimpleFileExFlags()` now uses the correct encoding to decode +the filename. + +.. + +.. bpo: 42536 +.. date: 2020-12-02-20-23-31 +.. nonce: Kx3ZOu +.. section: Core and Builtins + +Several built-in and standard library types now ensure that their internal +result tuples are always tracked by the :term:`garbage collector `: + +- :meth:`collections.OrderedDict.items() ` + +- :meth:`dict.items` + +- :func:`enumerate` + +- :func:`functools.reduce` + +- :func:`itertools.combinations` + +- :func:`itertools.combinations_with_replacement` + +- :func:`itertools.permutations` + +- :func:`itertools.product` + +- :func:`itertools.zip_longest` + +- :func:`zip` + +Previously, they could have become untracked by a prior garbage collection. +Patch by Brandt Bucher. + +.. + +.. bpo: 42195 +.. date: 2020-11-20-00-57-47 +.. nonce: HeqcpS +.. section: Core and Builtins + +The ``__args__`` of the parameterized generics for :data:`typing.Callable` +and :class:`collections.abc.Callable` are now consistent. The ``__args__`` +for :class:`collections.abc.Callable` are now flattened while +:data:`typing.Callable`'s have not changed. To allow this change, +:class:`types.GenericAlias` can now be subclassed and +``collections.abc.Callable``'s ``__class_getitem__`` will now return a +subclass of ``types.GenericAlias``. Tests for typing were also updated to +not subclass things like ``Callable[..., T]`` as that is not a valid base +class. Finally, both types no longer validate their ``argtypes``, in +``Callable[[argtypes], resulttype]`` to prepare for :pep:`612`. Patch by +Ken Jin. + +.. + +.. bpo: 43102 +.. date: 2021-02-03-22-55-27 +.. nonce: TSlZ6J +.. section: Library + +The namedtuple __new__ method had its __builtins__ set to None instead of an +actual dictionary. This created problems for introspection tools. + +.. + +.. bpo: 43108 +.. date: 2021-02-02-20-23-31 +.. nonce: lqcCZ6 +.. section: Library + +Fixed a reference leak in the :mod:`curses` module. Patch by Pablo Galindo + +.. + +.. bpo: 42944 +.. date: 2021-01-18-10-41-44 +.. nonce: RrONvy +.. section: Library + +Fix ``random.Random.sample`` when ``counts`` argument is not ``None``. + +.. + +.. bpo: 42931 +.. date: 2021-01-15-00-23-50 +.. nonce: QD6U2B +.. section: Library + +Add :func:`randbytes` to ``random.__all__``. + +.. + +.. bpo: 42780 +.. date: 2021-01-08-15-49-20 +.. nonce: rtqi6B +.. section: Library + +Fix os.set_inheritable() for O_PATH file descriptors on Linux. + +.. + +.. bpo: 42851 +.. date: 2021-01-07-11-44-22 +.. nonce: uyQFyd +.. section: Library + +remove __init_subclass__ support for Enum members + +.. + +.. bpo: 41748 +.. date: 2021-01-05-21-26-29 +.. nonce: KdC0w3 +.. section: Library + +Fix HTMLParser parsing rules for element attributes containing commas with +spaces. Patch by Karl Dubost. + +.. + +.. bpo: 42759 +.. date: 2020-12-27-22-19-26 +.. nonce: lGi_03 +.. section: Library + +Fixed equality comparison of :class:`tkinter.Variable` and +:class:`tkinter.font.Font`. Objects which belong to different Tcl +interpreters are now always different, even if they have the same name. + +.. + +.. bpo: 42756 +.. date: 2020-12-27-21-22-01 +.. nonce: dHMPJ9 +.. section: Library + +Configure LMTP Unix-domain socket to use socket global default timeout when +a timeout is not explicitly provided. + +.. + +.. bpo: 23328 +.. date: 2020-12-27-18-47-01 +.. nonce: _xqepZ +.. section: Library + +Allow / character in username, password fields on _PROXY envars. + +.. + +.. bpo: 42655 +.. date: 2020-12-25-12-32-47 +.. nonce: W5ytpV +.. section: Library + +:mod:`subprocess` *extra_groups* is now correctly passed into setgroups() +system call. + +.. + +.. bpo: 42727 +.. date: 2020-12-23-19-43-06 +.. nonce: WH3ODh +.. section: Library + +``EnumMeta.__prepare__`` now accepts ``**kwds`` to properly support +``__init_subclass__`` + +.. + +.. bpo: 42681 +.. date: 2020-12-20-22-50-15 +.. nonce: lDO6jb +.. section: Library + +Fixed range checks for color and pair numbers in :mod:`curses`. + +.. + +.. bpo: 37961 +.. date: 2020-12-16-16-16-33 +.. nonce: jrESEq +.. section: Library + +Fix crash in :func:`tracemalloc.Traceback.__repr__` (regressed in Python +3.9). + +.. + +.. bpo: 42630 +.. date: 2020-12-15-17-51-27 +.. nonce: jf4jBl +.. section: Library + +:mod:`tkinter` functions and constructors which need a default root window +raise now :exc:`RuntimeError` with descriptive message instead of obscure +:exc:`AttributeError` or :exc:`NameError` if it is not created yet or cannot +be created automatically. + +.. + +.. bpo: 42644 +.. date: 2020-12-15-10-00-04 +.. nonce: XgLCNx +.. section: Library + +`logging.disable` will now validate the types and value of its parameter. It +also now accepts strings representing the levels (as does `loging.setLevel`) +instead of only the numerical values. + +.. + +.. bpo: 36541 +.. date: 2020-12-14-08-23-57 +.. nonce: qdEtZv +.. section: Library + +Fixed lib2to3.pgen2 to be able to parse PEP-570 positional only argument +syntax. + +.. + +.. bpo: 42517 +.. date: 2020-12-09-10-59-16 +.. nonce: FKEVcZ +.. section: Library + +Enum: private names will raise a DeprecationWarning; in 3.10 they will +become normal attributes + +.. + +.. bpo: 42678 +.. date: 2020-12-08-22-43-35 +.. nonce: ba9ktU +.. section: Library + +`Enum`: call `__init_subclass__` after members have been added + +.. + +.. bpo: 42532 +.. date: 2020-12-02-07-37-59 +.. nonce: ObNep_ +.. section: Library + +Remove unexpected call of ``__bool__`` when passing a ``spec_arg`` argument +to a Mock. + +.. + +.. bpo: 42388 +.. date: 2020-11-22-11-22-28 +.. nonce: LMgM6B +.. section: Library + +Fix subprocess.check_output(..., input=None) behavior when text=True to be +consistent with that of the documentation and universal_newlines=True. + +.. + +.. bpo: 34463 +.. date: 2020-11-20-19-00-27 +.. nonce: aJcm56 +.. section: Library + +Fixed discrepancy between :mod:`traceback` and the interpreter in formatting +of SyntaxError with lineno not set (:mod:`traceback` was changed to match +interpreter). + +.. + +.. bpo: 42375 +.. date: 2020-11-19-04-13-53 +.. nonce: U8bp4s +.. section: Library + +subprocess module update for DragonFlyBSD support. + +.. + +.. bpo: 42384 +.. date: 2020-11-17-14-32-39 +.. nonce: 1ZnQSn +.. section: Library + +Make pdb populate sys.path[0] exactly the same as regular python execution. + +.. + +.. bpo: 42383 +.. date: 2020-11-17-14-30-12 +.. nonce: ubl0Y_ +.. section: Library + +Fix pdb: previously pdb would fail to restart the debugging target if it was +specified using a relative path and the current directory changed. + +.. + +.. bpo: 42318 +.. date: 2020-11-14-13-46-27 +.. nonce: wYAcBD +.. section: Library + +Fixed support of non-BMP characters in :mod:`tkinter` on macOS. + +.. + +.. bpo: 42163 +.. date: 2020-10-29-09-22-56 +.. nonce: O4VcCY +.. section: Library + +Restore compatibility for ``uname_result`` around deepcopy and _replace. + +.. + +.. bpo: 39825 +.. date: 2020-10-20-08-28-26 +.. nonce: n6KnG0 +.. section: Library + +Windows: Change ``sysconfig.get_config_var('EXT_SUFFIX')`` to the expected +full ``platform_tag.extension`` format. Previously it was hard-coded to +``.pyd``, now it is compatible with ``distutils.sysconfig`` and will result +in something like ``.cp38-win_amd64.pyd``. This brings windows into +conformance with the other platforms. + +.. + +.. bpo: 42059 +.. date: 2020-10-17-12-42-08 +.. nonce: ZGMZ3D +.. section: Library + +:class:`typing.TypedDict` types created using the alternative call-style +syntax now correctly respect the ``total`` keyword argument when setting +their ``__required_keys__`` and ``__optional_keys__`` class attributes. + +.. + +.. bpo: 39101 +.. date: 2020-10-11-21-43-03 +.. nonce: -I49Pm +.. section: Library + +Fixed tests using IsolatedAsyncioTestCase from hanging on BaseExceptions. + +.. + +.. bpo: 42005 +.. date: 2020-10-11-13-48-03 +.. nonce: Jq6Az- +.. section: Library + +Fix CLI of :mod:`cProfile` and :mod:`profile` to catch +:exc:`BrokenPipeError`. + +.. + +.. bpo: 41907 +.. date: 2020-10-02-10-19-49 +.. nonce: wiIEsz +.. section: Library + +fix `format()` behavior for `IntFlag` + +.. + +.. bpo: 41889 +.. date: 2020-10-01-16-17-11 +.. nonce: qLkNh8 +.. section: Library + +Enum: fix regression involving inheriting a multiply-inherited enum + +.. + +.. bpo: 41891 +.. date: 2020-09-30-13-35-29 +.. nonce: pNAeYI +.. section: Library + +Ensure asyncio.wait_for waits for task completion + +.. + +.. bpo: 41604 +.. date: 2020-08-21-15-24-14 +.. nonce: rTXleO +.. section: Library + +Don't decrement the reference count of the previous user_ptr when +set_panel_userptr fails. + +.. + +.. bpo: 40219 +.. date: 2020-07-13-19-43-11 +.. nonce: MUoJEP +.. section: Library + +Lowered :class:`tkinter.ttk.LabeledScale` dummy widget to prevent hiding +part of the content label. + +.. + +.. bpo: 40084 +.. date: 2020-03-29-21-32-00 +.. nonce: MCYwcv +.. section: Library + +Fix ``Enum.__dir__``: dir(Enum.member) now includes attributes as well as +methods. + +.. + +.. bpo: 39068 +.. date: 2019-12-16-17-55-31 +.. nonce: Ti3f9P +.. section: Library + +Fix initialization race condition in :func:`a85encode` and :func:`b85encode` +in :mod:`base64`. Patch by Brandon Stansbury. + +.. + +.. bpo: 33289 +.. date: 2018-04-23-13-44-10 +.. nonce: anBnUr +.. section: Library + +Correct call to :mod:`tkinter.colorchooser` to return RGB triplet of ints +instead of floats. Patch by Cheryl Sabella. + +.. + +.. bpo: 40304 +.. date: 2021-01-20-23-03-49 +.. nonce: -LK7Ps +.. section: Documentation + +Fix doc for type(name, bases, dict). Patch by Boris Verkhovskiy and Éric +Araujo. + +.. + +.. bpo: 42811 +.. date: 2021-01-07-12-08-59 +.. nonce: ePF7EC +.. section: Documentation + +Updated importlib.utils.resolve_name() doc to use __spec__.parent instead of +__package__. (Thanks Yair Frid.) + +.. + +.. bpo: 17140 +.. date: 2020-12-16-21-06-16 +.. nonce: 1leSEg +.. section: Documentation + +Add documentation for the :class:`multiprocessing.pool.ThreadPool` class. + +.. + +.. bpo: 42794 +.. date: 2021-01-01-08-52-36 +.. nonce: -7-XGz +.. section: Tests + +Update test_nntplib to use offical group name of news.aioe.org for testing. +Patch by Dong-hee Na. + +.. + +.. bpo: 40810 +.. date: 2020-05-30-10-56-38 +.. nonce: LPqDLQ +.. section: Tests + +In :mod:`sqlite3`, fix ``CheckTraceCallbackContent`` for SQLite pre 3.7.15. + +.. + +.. bpo: 43174 +.. date: 2021-02-10-14-11-53 +.. nonce: F9zwXQ +.. section: Build + +Windows build now uses ``/utf-8`` compiler option. + +.. + +.. bpo: 42692 +.. date: 2021-01-04-05-07-30 +.. nonce: OO11SN +.. section: Build + +Fix __builtin_available check on older compilers. Patch by Joshua Root. + +.. + +.. bpo: 42604 +.. date: 2020-12-20-02-35-28 +.. nonce: gRd89w +.. section: Build + +Now all platforms use a value for the "EXT_SUFFIX" build variable derived +from SOABI (for instance in freeBSD, "EXT_SUFFIX" is now ".cpython-310d.so" +instead of ".so"). Previosuly only Linux, Mac and VxWorks were using a value +for "EXT_SUFFIX" that included "SOABI". + +.. + +.. bpo: 42598 +.. date: 2020-12-13-14-43-10 +.. nonce: 7ipr5H +.. section: Build + +Fix implicit function declarations in configure which could have resulted in +incorrect configuration checks. Patch contributed by Joshua Root. + +.. + +.. bpo: 29076 +.. date: 2020-02-28-14-33-15 +.. nonce: Gtixi5 +.. section: Build + +Add fish shell support to macOS installer. + +.. + +.. bpo: 41837 +.. date: 2021-01-05-20-36-40 +.. nonce: bmS7vB +.. section: Windows + +Updated Windows installer to include OpenSSL 1.1.1i + +.. + +.. bpo: 42584 +.. date: 2020-12-07-11-40-52 +.. nonce: AsYnVX +.. section: Windows + +Upgrade Windows installer to use SQLite 3.34.0. + +.. + +.. bpo: 42504 +.. date: 2021-01-26-14-36-11 +.. nonce: ZxWt71 +.. section: macOS + +Ensure that the value of +sysconfig.get_config_var('MACOSX_DEPLOYMENT_TARGET') is always a string, +even in when the value is parsable as an integer. + +.. + +.. bpo: 42361 +.. date: 2021-01-04-01-17-17 +.. nonce: eolZAi +.. section: macOS + +Update macOS installer build to use Tcl/Tk 8.6.11 (rc2, expected to be final +release). + +.. + +.. bpo: 41837 +.. date: 2021-01-04-00-48-08 +.. nonce: dX-unJ +.. section: macOS + +Update macOS installer build to use OpenSSL 1.1.1i. + +.. + +.. bpo: 42584 +.. date: 2020-12-07-11-37-35 +.. nonce: LygmqQ +.. section: macOS + +Update macOS installer to use SQLite 3.34.0. + +.. + +.. bpo: 43008 +.. date: 2021-01-26-18-12-17 +.. nonce: mbQUc7 +.. section: IDLE + +Make IDLE invoke :func:`sys.excepthook` in normal, 2-process mode. Patch by +Ken Hilton. + +.. + +.. bpo: 33065 +.. date: 2021-01-10-01-25-43 +.. nonce: zmyHYJ +.. section: IDLE + +Fix problem debugging user classes with __repr__ method. + +.. + +.. bpo: 23544 +.. date: 2019-11-14-23-41-07 +.. nonce: 3etemb +.. section: IDLE + +Disable Debug=>Stack Viewer when user code is running or Debugger is active, +to prevent hang or crash. Patch by Zackery Spytz. + +.. + +.. bpo: 32631 +.. date: 2019-06-30-20-31-09 +.. nonce: e7_4BG +.. section: IDLE + +Finish zzdummy example extension module: make menu entries work; add +docstrings and tests with 100% coverage. + +.. + +.. bpo: 42726 +.. date: 2020-12-23-19-42-11 +.. nonce: a5EkTv +.. section: Tools/Demos + +Fixed Python 3 compatibility issue with gdb/libpython.py handling of +attribute dictionaries. + +.. + +.. bpo: 42613 +.. date: 2020-12-16-09-10-32 +.. nonce: J-jnm5 +.. section: Tools/Demos + +Fix ``freeze.py`` tool to use the prope config and library directories. +Patch by Victor Stinner. + +.. + +.. bpo: 43030 +.. date: 2021-01-27-10-27-47 +.. nonce: loDcD_ +.. section: C API + +Fixed a compiler warning in :c:func:`Py_UNICODE_ISSPACE()` on platforms with +signed ``wchar_t``. + +.. + +.. bpo: 42591 +.. date: 2020-12-10-10-43-03 +.. nonce: CXNY8G +.. section: C API + +Export the :c:func:`Py_FrozenMain` function: fix a Python 3.9.0 regression. +Python 3.9 uses ``-fvisibility=hidden`` and the function was not exported +explicitly and so not exported. + +.. + +.. bpo: 40052 +.. date: 2020-03-24-09-27-10 +.. nonce: 27P2KG +.. section: C API + +Fix an alignment build warning/error in function +``PyVectorcall_Function()``. Patch by Andreas Schneider, Antoine Pitrou and +Petr Viktorin. diff --git a/Misc/NEWS.d/next/Build/2020-02-28-14-33-15.bpo-29076.Gtixi5.rst b/Misc/NEWS.d/next/Build/2020-02-28-14-33-15.bpo-29076.Gtixi5.rst deleted file mode 100644 index b38beb0586951c..00000000000000 --- a/Misc/NEWS.d/next/Build/2020-02-28-14-33-15.bpo-29076.Gtixi5.rst +++ /dev/null @@ -1 +0,0 @@ -Add fish shell support to macOS installer. diff --git a/Misc/NEWS.d/next/Build/2020-12-13-14-43-10.bpo-42598.7ipr5H.rst b/Misc/NEWS.d/next/Build/2020-12-13-14-43-10.bpo-42598.7ipr5H.rst deleted file mode 100644 index 7dafc105c45ea9..00000000000000 --- a/Misc/NEWS.d/next/Build/2020-12-13-14-43-10.bpo-42598.7ipr5H.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix implicit function declarations in configure which could have resulted in -incorrect configuration checks. Patch contributed by Joshua Root. diff --git a/Misc/NEWS.d/next/Build/2020-12-20-02-35-28.bpo-42604.gRd89w.rst b/Misc/NEWS.d/next/Build/2020-12-20-02-35-28.bpo-42604.gRd89w.rst deleted file mode 100644 index caaada41cf9bad..00000000000000 --- a/Misc/NEWS.d/next/Build/2020-12-20-02-35-28.bpo-42604.gRd89w.rst +++ /dev/null @@ -1,4 +0,0 @@ -Now all platforms use a value for the "EXT_SUFFIX" build variable derived -from SOABI (for instance in freeBSD, "EXT_SUFFIX" is now ".cpython-310d.so" -instead of ".so"). Previosuly only Linux, Mac and VxWorks were using a value -for "EXT_SUFFIX" that included "SOABI". diff --git a/Misc/NEWS.d/next/Build/2021-01-04-05-07-30.bpo-42692.OO11SN.rst b/Misc/NEWS.d/next/Build/2021-01-04-05-07-30.bpo-42692.OO11SN.rst deleted file mode 100644 index 91582b945b803f..00000000000000 --- a/Misc/NEWS.d/next/Build/2021-01-04-05-07-30.bpo-42692.OO11SN.rst +++ /dev/null @@ -1 +0,0 @@ -Fix __builtin_available check on older compilers. Patch by Joshua Root. diff --git a/Misc/NEWS.d/next/Build/2021-02-10-14-11-53.bpo-43174.F9zwXQ.rst b/Misc/NEWS.d/next/Build/2021-02-10-14-11-53.bpo-43174.F9zwXQ.rst deleted file mode 100644 index 64c80188d02f62..00000000000000 --- a/Misc/NEWS.d/next/Build/2021-02-10-14-11-53.bpo-43174.F9zwXQ.rst +++ /dev/null @@ -1 +0,0 @@ -Windows build now uses ``/utf-8`` compiler option. diff --git a/Misc/NEWS.d/next/C API/2020-03-24-09-27-10.bpo-40052.27P2KG.rst b/Misc/NEWS.d/next/C API/2020-03-24-09-27-10.bpo-40052.27P2KG.rst deleted file mode 100644 index 538488e2fbaccd..00000000000000 --- a/Misc/NEWS.d/next/C API/2020-03-24-09-27-10.bpo-40052.27P2KG.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix an alignment build warning/error in function ``PyVectorcall_Function()``. -Patch by Andreas Schneider, Antoine Pitrou and Petr Viktorin. diff --git a/Misc/NEWS.d/next/C API/2020-12-10-10-43-03.bpo-42591.CXNY8G.rst b/Misc/NEWS.d/next/C API/2020-12-10-10-43-03.bpo-42591.CXNY8G.rst deleted file mode 100644 index 3519859f7be89d..00000000000000 --- a/Misc/NEWS.d/next/C API/2020-12-10-10-43-03.bpo-42591.CXNY8G.rst +++ /dev/null @@ -1,3 +0,0 @@ -Export the :c:func:`Py_FrozenMain` function: fix a Python 3.9.0 regression. -Python 3.9 uses ``-fvisibility=hidden`` and the function was not exported -explicitly and so not exported. diff --git a/Misc/NEWS.d/next/C API/2021-01-27-10-27-47.bpo-43030.loDcD_.rst b/Misc/NEWS.d/next/C API/2021-01-27-10-27-47.bpo-43030.loDcD_.rst deleted file mode 100644 index 7a432522db8a12..00000000000000 --- a/Misc/NEWS.d/next/C API/2021-01-27-10-27-47.bpo-43030.loDcD_.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fixed a compiler warning in :c:func:`Py_UNICODE_ISSPACE()` on platforms with -signed ``wchar_t``. diff --git a/Misc/NEWS.d/next/Core and Builtins/2020-11-20-00-57-47.bpo-42195.HeqcpS.rst b/Misc/NEWS.d/next/Core and Builtins/2020-11-20-00-57-47.bpo-42195.HeqcpS.rst deleted file mode 100644 index 636d4165a63897..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2020-11-20-00-57-47.bpo-42195.HeqcpS.rst +++ /dev/null @@ -1,11 +0,0 @@ -The ``__args__`` of the parameterized generics for :data:`typing.Callable` -and :class:`collections.abc.Callable` are now consistent. The ``__args__`` -for :class:`collections.abc.Callable` are now flattened while -:data:`typing.Callable`'s have not changed. To allow this change, -:class:`types.GenericAlias` can now be subclassed and -``collections.abc.Callable``'s ``__class_getitem__`` will now return a subclass -of ``types.GenericAlias``. Tests for typing were also updated to not subclass -things like ``Callable[..., T]`` as that is not a valid base class. Finally, -both types no longer validate their ``argtypes``, in -``Callable[[argtypes], resulttype]`` to prepare for :pep:`612`. Patch by Ken Jin. - diff --git a/Misc/NEWS.d/next/Core and Builtins/2020-12-02-20-23-31.bpo-42536.Kx3ZOu.rst b/Misc/NEWS.d/next/Core and Builtins/2020-12-02-20-23-31.bpo-42536.Kx3ZOu.rst deleted file mode 100644 index 6ccacab1f64f68..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2020-12-02-20-23-31.bpo-42536.Kx3ZOu.rst +++ /dev/null @@ -1,26 +0,0 @@ -Several built-in and standard library types now ensure that their internal -result tuples are always tracked by the :term:`garbage collector -`: - -- :meth:`collections.OrderedDict.items() ` - -- :meth:`dict.items` - -- :func:`enumerate` - -- :func:`functools.reduce` - -- :func:`itertools.combinations` - -- :func:`itertools.combinations_with_replacement` - -- :func:`itertools.permutations` - -- :func:`itertools.product` - -- :func:`itertools.zip_longest` - -- :func:`zip` - -Previously, they could have become untracked by a prior garbage collection. -Patch by Brandt Bucher. diff --git a/Misc/NEWS.d/next/Core and Builtins/2020-12-04-17-17-44.bpo-32381.NY5t2S.rst b/Misc/NEWS.d/next/Core and Builtins/2020-12-04-17-17-44.bpo-32381.NY5t2S.rst deleted file mode 100644 index f4d84f9d848d4f..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2020-12-04-17-17-44.bpo-32381.NY5t2S.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix encoding name when running a ``.pyc`` file on Windows: -:c:func:`PyRun_SimpleFileExFlags()` now uses the correct encoding to decode -the filename. diff --git a/Misc/NEWS.d/next/Core and Builtins/2020-12-31-20-58-22.bpo-40631.deRMCx.rst b/Misc/NEWS.d/next/Core and Builtins/2020-12-31-20-58-22.bpo-40631.deRMCx.rst deleted file mode 100644 index ac2db2938237f8..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2020-12-31-20-58-22.bpo-40631.deRMCx.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix regression where a single parenthesized starred expression was a valid -assignment target. diff --git a/Misc/NEWS.d/next/Core and Builtins/2021-01-03-00-20-38.bpo-42806.mLAobJ.rst b/Misc/NEWS.d/next/Core and Builtins/2021-01-03-00-20-38.bpo-42806.mLAobJ.rst deleted file mode 100644 index 10314fd650fa66..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2021-01-03-00-20-38.bpo-42806.mLAobJ.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix the column offsets for f-strings :mod:`ast` nodes surrounded by -parentheses and for nodes that spawn multiple lines. Patch by Pablo Galindo. diff --git a/Misc/NEWS.d/next/Core and Builtins/2021-01-04-23-54-34.bpo-42819.4KO6wU.rst b/Misc/NEWS.d/next/Core and Builtins/2021-01-04-23-54-34.bpo-42819.4KO6wU.rst deleted file mode 100644 index d067f0bfa76448..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2021-01-04-23-54-34.bpo-42819.4KO6wU.rst +++ /dev/null @@ -1,8 +0,0 @@ -:mod:`readline`: Explicitly disable bracketed paste in the interactive -interpreter, even if it's set in the inputrc, is enabled by default (eg GNU -Readline 8.1), or a user calls ``readline.read_init_file()``. The Python REPL -has not implemented bracketed paste support. Also, bracketed mode writes the -``"\x1b[?2004h"`` escape sequence into stdout which causes test failures in -applications that don't support it. It can still be explicitly enabled by -calling ``readline.parse_and_bind("set enable-bracketed-paste on")``. Patch by -Dustin Rodrigues. diff --git a/Misc/NEWS.d/next/Documentation/2020-12-16-21-06-16.bpo-17140.1leSEg.rst b/Misc/NEWS.d/next/Documentation/2020-12-16-21-06-16.bpo-17140.1leSEg.rst deleted file mode 100644 index cb1fd23a56e639..00000000000000 --- a/Misc/NEWS.d/next/Documentation/2020-12-16-21-06-16.bpo-17140.1leSEg.rst +++ /dev/null @@ -1 +0,0 @@ -Add documentation for the :class:`multiprocessing.pool.ThreadPool` class. diff --git a/Misc/NEWS.d/next/Documentation/2021-01-07-12-08-59.bpo-42811.ePF7EC.rst b/Misc/NEWS.d/next/Documentation/2021-01-07-12-08-59.bpo-42811.ePF7EC.rst deleted file mode 100644 index 179c0655c70680..00000000000000 --- a/Misc/NEWS.d/next/Documentation/2021-01-07-12-08-59.bpo-42811.ePF7EC.rst +++ /dev/null @@ -1,2 +0,0 @@ -Updated importlib.utils.resolve_name() doc to use __spec__.parent instead of -__package__. (Thanks Yair Frid.) diff --git a/Misc/NEWS.d/next/Documentation/2021-01-20-23-03-49.bpo-40304.-LK7Ps.rst b/Misc/NEWS.d/next/Documentation/2021-01-20-23-03-49.bpo-40304.-LK7Ps.rst deleted file mode 100644 index 3f2f14c2d7b893..00000000000000 --- a/Misc/NEWS.d/next/Documentation/2021-01-20-23-03-49.bpo-40304.-LK7Ps.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix doc for type(name, bases, dict). Patch by Boris Verkhovskiy and -Éric Araujo. diff --git a/Misc/NEWS.d/next/IDLE/2019-06-30-20-31-09.bpo-32631.e7_4BG.rst b/Misc/NEWS.d/next/IDLE/2019-06-30-20-31-09.bpo-32631.e7_4BG.rst deleted file mode 100644 index c422f43b6d6dd8..00000000000000 --- a/Misc/NEWS.d/next/IDLE/2019-06-30-20-31-09.bpo-32631.e7_4BG.rst +++ /dev/null @@ -1,2 +0,0 @@ -Finish zzdummy example extension module: make menu entries work; -add docstrings and tests with 100% coverage. diff --git a/Misc/NEWS.d/next/IDLE/2019-11-14-23-41-07.bpo-23544.3etemb.rst b/Misc/NEWS.d/next/IDLE/2019-11-14-23-41-07.bpo-23544.3etemb.rst deleted file mode 100644 index eb4a56bf100b59..00000000000000 --- a/Misc/NEWS.d/next/IDLE/2019-11-14-23-41-07.bpo-23544.3etemb.rst +++ /dev/null @@ -1,2 +0,0 @@ -Disable Debug=>Stack Viewer when user code is running or Debugger -is active, to prevent hang or crash. Patch by Zackery Spytz. diff --git a/Misc/NEWS.d/next/IDLE/2021-01-10-01-25-43.bpo-33065.zmyHYJ.rst b/Misc/NEWS.d/next/IDLE/2021-01-10-01-25-43.bpo-33065.zmyHYJ.rst deleted file mode 100644 index 87948f3cd1baa1..00000000000000 --- a/Misc/NEWS.d/next/IDLE/2021-01-10-01-25-43.bpo-33065.zmyHYJ.rst +++ /dev/null @@ -1 +0,0 @@ -Fix problem debugging user classes with __repr__ method. diff --git a/Misc/NEWS.d/next/IDLE/2021-01-26-18-12-17.bpo-43008.mbQUc7.rst b/Misc/NEWS.d/next/IDLE/2021-01-26-18-12-17.bpo-43008.mbQUc7.rst deleted file mode 100644 index 55ab67ca94959a..00000000000000 --- a/Misc/NEWS.d/next/IDLE/2021-01-26-18-12-17.bpo-43008.mbQUc7.rst +++ /dev/null @@ -1,2 +0,0 @@ -Make IDLE invoke :func:`sys.excepthook` in normal, 2-process mode. -Patch by Ken Hilton. diff --git a/Misc/NEWS.d/next/Library/2018-04-23-13-44-10.bpo-33289.anBnUr.rst b/Misc/NEWS.d/next/Library/2018-04-23-13-44-10.bpo-33289.anBnUr.rst deleted file mode 100644 index 52d9ac9dd902cd..00000000000000 --- a/Misc/NEWS.d/next/Library/2018-04-23-13-44-10.bpo-33289.anBnUr.rst +++ /dev/null @@ -1,2 +0,0 @@ -Correct call to :mod:`tkinter.colorchooser` to return RGB triplet of ints -instead of floats. Patch by Cheryl Sabella. diff --git a/Misc/NEWS.d/next/Library/2019-12-16-17-55-31.bpo-39068.Ti3f9P.rst b/Misc/NEWS.d/next/Library/2019-12-16-17-55-31.bpo-39068.Ti3f9P.rst deleted file mode 100644 index fe6503fdce6b63..00000000000000 --- a/Misc/NEWS.d/next/Library/2019-12-16-17-55-31.bpo-39068.Ti3f9P.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix initialization race condition in :func:`a85encode` and :func:`b85encode` -in :mod:`base64`. Patch by Brandon Stansbury. diff --git a/Misc/NEWS.d/next/Library/2020-03-29-21-32-00.bpo-40084.MCYwcv.rst b/Misc/NEWS.d/next/Library/2020-03-29-21-32-00.bpo-40084.MCYwcv.rst deleted file mode 100644 index 65ff4ce36e82ea..00000000000000 --- a/Misc/NEWS.d/next/Library/2020-03-29-21-32-00.bpo-40084.MCYwcv.rst +++ /dev/null @@ -1 +0,0 @@ -Fix ``Enum.__dir__``: dir(Enum.member) now includes attributes as well as methods. diff --git a/Misc/NEWS.d/next/Library/2020-07-13-19-43-11.bpo-40219.MUoJEP.rst b/Misc/NEWS.d/next/Library/2020-07-13-19-43-11.bpo-40219.MUoJEP.rst deleted file mode 100644 index aedc5c49b4087a..00000000000000 --- a/Misc/NEWS.d/next/Library/2020-07-13-19-43-11.bpo-40219.MUoJEP.rst +++ /dev/null @@ -1 +0,0 @@ -Lowered :class:`tkinter.ttk.LabeledScale` dummy widget to prevent hiding part of the content label. diff --git a/Misc/NEWS.d/next/Library/2020-08-21-15-24-14.bpo-41604.rTXleO.rst b/Misc/NEWS.d/next/Library/2020-08-21-15-24-14.bpo-41604.rTXleO.rst deleted file mode 100644 index 0f9794cbdb321e..00000000000000 --- a/Misc/NEWS.d/next/Library/2020-08-21-15-24-14.bpo-41604.rTXleO.rst +++ /dev/null @@ -1,2 +0,0 @@ -Don't decrement the reference count of the previous user_ptr when -set_panel_userptr fails. diff --git a/Misc/NEWS.d/next/Library/2020-09-30-13-35-29.bpo-41891.pNAeYI.rst b/Misc/NEWS.d/next/Library/2020-09-30-13-35-29.bpo-41891.pNAeYI.rst deleted file mode 100644 index 75c25127803153..00000000000000 --- a/Misc/NEWS.d/next/Library/2020-09-30-13-35-29.bpo-41891.pNAeYI.rst +++ /dev/null @@ -1 +0,0 @@ -Ensure asyncio.wait_for waits for task completion diff --git a/Misc/NEWS.d/next/Library/2020-10-01-16-17-11.bpo-41889.qLkNh8.rst b/Misc/NEWS.d/next/Library/2020-10-01-16-17-11.bpo-41889.qLkNh8.rst deleted file mode 100644 index 768865ae62116d..00000000000000 --- a/Misc/NEWS.d/next/Library/2020-10-01-16-17-11.bpo-41889.qLkNh8.rst +++ /dev/null @@ -1 +0,0 @@ -Enum: fix regression involving inheriting a multiply-inherited enum diff --git a/Misc/NEWS.d/next/Library/2020-10-02-10-19-49.bpo-41907.wiIEsz.rst b/Misc/NEWS.d/next/Library/2020-10-02-10-19-49.bpo-41907.wiIEsz.rst deleted file mode 100644 index aa337b38046e61..00000000000000 --- a/Misc/NEWS.d/next/Library/2020-10-02-10-19-49.bpo-41907.wiIEsz.rst +++ /dev/null @@ -1 +0,0 @@ -fix `format()` behavior for `IntFlag` diff --git a/Misc/NEWS.d/next/Library/2020-10-11-13-48-03.bpo-42005.Jq6Az-.rst b/Misc/NEWS.d/next/Library/2020-10-11-13-48-03.bpo-42005.Jq6Az-.rst deleted file mode 100644 index be4ed7f55ffded..00000000000000 --- a/Misc/NEWS.d/next/Library/2020-10-11-13-48-03.bpo-42005.Jq6Az-.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix CLI of :mod:`cProfile` and :mod:`profile` to catch -:exc:`BrokenPipeError`. diff --git a/Misc/NEWS.d/next/Library/2020-10-11-21-43-03.bpo-39101.-I49Pm.rst b/Misc/NEWS.d/next/Library/2020-10-11-21-43-03.bpo-39101.-I49Pm.rst deleted file mode 100644 index a571e8343cde12..00000000000000 --- a/Misc/NEWS.d/next/Library/2020-10-11-21-43-03.bpo-39101.-I49Pm.rst +++ /dev/null @@ -1 +0,0 @@ -Fixed tests using IsolatedAsyncioTestCase from hanging on BaseExceptions. \ No newline at end of file diff --git a/Misc/NEWS.d/next/Library/2020-10-17-12-42-08.bpo-42059.ZGMZ3D.rst b/Misc/NEWS.d/next/Library/2020-10-17-12-42-08.bpo-42059.ZGMZ3D.rst deleted file mode 100644 index 3f18824fe65987..00000000000000 --- a/Misc/NEWS.d/next/Library/2020-10-17-12-42-08.bpo-42059.ZGMZ3D.rst +++ /dev/null @@ -1 +0,0 @@ -:class:`typing.TypedDict` types created using the alternative call-style syntax now correctly respect the ``total`` keyword argument when setting their ``__required_keys__`` and ``__optional_keys__`` class attributes. diff --git a/Misc/NEWS.d/next/Library/2020-10-20-08-28-26.bpo-39825.n6KnG0.rst b/Misc/NEWS.d/next/Library/2020-10-20-08-28-26.bpo-39825.n6KnG0.rst deleted file mode 100644 index c337731f435843..00000000000000 --- a/Misc/NEWS.d/next/Library/2020-10-20-08-28-26.bpo-39825.n6KnG0.rst +++ /dev/null @@ -1,5 +0,0 @@ -Windows: Change ``sysconfig.get_config_var('EXT_SUFFIX')`` to the expected -full ``platform_tag.extension`` format. Previously it was hard-coded to -``.pyd``, now it is compatible with ``distutils.sysconfig`` and will result -in something like ``.cp38-win_amd64.pyd``. This brings windows into -conformance with the other platforms. diff --git a/Misc/NEWS.d/next/Library/2020-10-29-09-22-56.bpo-42163.O4VcCY.rst b/Misc/NEWS.d/next/Library/2020-10-29-09-22-56.bpo-42163.O4VcCY.rst deleted file mode 100644 index 0c357eb4ac1daf..00000000000000 --- a/Misc/NEWS.d/next/Library/2020-10-29-09-22-56.bpo-42163.O4VcCY.rst +++ /dev/null @@ -1 +0,0 @@ -Restore compatibility for ``uname_result`` around deepcopy and _replace. diff --git a/Misc/NEWS.d/next/Library/2020-11-14-13-46-27.bpo-42318.wYAcBD.rst b/Misc/NEWS.d/next/Library/2020-11-14-13-46-27.bpo-42318.wYAcBD.rst deleted file mode 100644 index e72daebb2f152a..00000000000000 --- a/Misc/NEWS.d/next/Library/2020-11-14-13-46-27.bpo-42318.wYAcBD.rst +++ /dev/null @@ -1 +0,0 @@ -Fixed support of non-BMP characters in :mod:`tkinter` on macOS. diff --git a/Misc/NEWS.d/next/Library/2020-11-17-14-30-12.bpo-42383.ubl0Y_.rst b/Misc/NEWS.d/next/Library/2020-11-17-14-30-12.bpo-42383.ubl0Y_.rst deleted file mode 100644 index ccf2106f28a93d..00000000000000 --- a/Misc/NEWS.d/next/Library/2020-11-17-14-30-12.bpo-42383.ubl0Y_.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix pdb: previously pdb would fail to restart the debugging target if it was -specified using a relative path and the current directory changed. diff --git a/Misc/NEWS.d/next/Library/2020-11-17-14-32-39.bpo-42384.1ZnQSn.rst b/Misc/NEWS.d/next/Library/2020-11-17-14-32-39.bpo-42384.1ZnQSn.rst deleted file mode 100644 index ae990162fbab75..00000000000000 --- a/Misc/NEWS.d/next/Library/2020-11-17-14-32-39.bpo-42384.1ZnQSn.rst +++ /dev/null @@ -1 +0,0 @@ -Make pdb populate sys.path[0] exactly the same as regular python execution. diff --git a/Misc/NEWS.d/next/Library/2020-11-19-04-13-53.bpo-42375.U8bp4s.rst b/Misc/NEWS.d/next/Library/2020-11-19-04-13-53.bpo-42375.U8bp4s.rst deleted file mode 100644 index 6d8c80c2f2c0ae..00000000000000 --- a/Misc/NEWS.d/next/Library/2020-11-19-04-13-53.bpo-42375.U8bp4s.rst +++ /dev/null @@ -1 +0,0 @@ -subprocess module update for DragonFlyBSD support. \ No newline at end of file diff --git a/Misc/NEWS.d/next/Library/2020-11-20-19-00-27.bpo-34463.aJcm56.rst b/Misc/NEWS.d/next/Library/2020-11-20-19-00-27.bpo-34463.aJcm56.rst deleted file mode 100644 index df183548236afb..00000000000000 --- a/Misc/NEWS.d/next/Library/2020-11-20-19-00-27.bpo-34463.aJcm56.rst +++ /dev/null @@ -1 +0,0 @@ -Fixed discrepancy between :mod:`traceback` and the interpreter in formatting of SyntaxError with lineno not set (:mod:`traceback` was changed to match interpreter). diff --git a/Misc/NEWS.d/next/Library/2020-11-22-11-22-28.bpo-42388.LMgM6B.rst b/Misc/NEWS.d/next/Library/2020-11-22-11-22-28.bpo-42388.LMgM6B.rst deleted file mode 100644 index 1b19247e841487..00000000000000 --- a/Misc/NEWS.d/next/Library/2020-11-22-11-22-28.bpo-42388.LMgM6B.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix subprocess.check_output(..., input=None) behavior when text=True to be -consistent with that of the documentation and universal_newlines=True. diff --git a/Misc/NEWS.d/next/Library/2020-12-02-07-37-59.bpo-42532.ObNep_.rst b/Misc/NEWS.d/next/Library/2020-12-02-07-37-59.bpo-42532.ObNep_.rst deleted file mode 100644 index 7465cb8e2e3d7b..00000000000000 --- a/Misc/NEWS.d/next/Library/2020-12-02-07-37-59.bpo-42532.ObNep_.rst +++ /dev/null @@ -1 +0,0 @@ -Remove unexpected call of ``__bool__`` when passing a ``spec_arg`` argument to a Mock. diff --git a/Misc/NEWS.d/next/Library/2020-12-08-22-43-35.bpo-42678.ba9ktU.rst b/Misc/NEWS.d/next/Library/2020-12-08-22-43-35.bpo-42678.ba9ktU.rst deleted file mode 100644 index 7c94cdf40dd4cc..00000000000000 --- a/Misc/NEWS.d/next/Library/2020-12-08-22-43-35.bpo-42678.ba9ktU.rst +++ /dev/null @@ -1 +0,0 @@ -`Enum`: call `__init_subclass__` after members have been added diff --git a/Misc/NEWS.d/next/Library/2020-12-09-10-59-16.bpo-42517.FKEVcZ.rst b/Misc/NEWS.d/next/Library/2020-12-09-10-59-16.bpo-42517.FKEVcZ.rst deleted file mode 100644 index e99294d9430d1a..00000000000000 --- a/Misc/NEWS.d/next/Library/2020-12-09-10-59-16.bpo-42517.FKEVcZ.rst +++ /dev/null @@ -1,2 +0,0 @@ -Enum: private names will raise a DeprecationWarning; in 3.10 they will -become normal attributes diff --git a/Misc/NEWS.d/next/Library/2020-12-14-08-23-57.bpo-36541.qdEtZv.rst b/Misc/NEWS.d/next/Library/2020-12-14-08-23-57.bpo-36541.qdEtZv.rst deleted file mode 100644 index 5678d8c595ca08..00000000000000 --- a/Misc/NEWS.d/next/Library/2020-12-14-08-23-57.bpo-36541.qdEtZv.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fixed lib2to3.pgen2 to be able to parse PEP-570 positional only argument -syntax. diff --git a/Misc/NEWS.d/next/Library/2020-12-15-10-00-04.bpo-42644.XgLCNx.rst b/Misc/NEWS.d/next/Library/2020-12-15-10-00-04.bpo-42644.XgLCNx.rst deleted file mode 100644 index f58b58e4002ada..00000000000000 --- a/Misc/NEWS.d/next/Library/2020-12-15-10-00-04.bpo-42644.XgLCNx.rst +++ /dev/null @@ -1,3 +0,0 @@ -`logging.disable` will now validate the types and value of its parameter. It -also now accepts strings representing the levels (as does `loging.setLevel`) -instead of only the numerical values. diff --git a/Misc/NEWS.d/next/Library/2020-12-15-17-51-27.bpo-42630.jf4jBl.rst b/Misc/NEWS.d/next/Library/2020-12-15-17-51-27.bpo-42630.jf4jBl.rst deleted file mode 100644 index 4b4a520931fda4..00000000000000 --- a/Misc/NEWS.d/next/Library/2020-12-15-17-51-27.bpo-42630.jf4jBl.rst +++ /dev/null @@ -1,4 +0,0 @@ -:mod:`tkinter` functions and constructors which need a default root window -raise now :exc:`RuntimeError` with descriptive message instead of obscure -:exc:`AttributeError` or :exc:`NameError` if it is not created yet or cannot -be created automatically. diff --git a/Misc/NEWS.d/next/Library/2020-12-16-16-16-33.bpo-37961.jrESEq.rst b/Misc/NEWS.d/next/Library/2020-12-16-16-16-33.bpo-37961.jrESEq.rst deleted file mode 100644 index 5b363ad22d6e3d..00000000000000 --- a/Misc/NEWS.d/next/Library/2020-12-16-16-16-33.bpo-37961.jrESEq.rst +++ /dev/null @@ -1 +0,0 @@ -Fix crash in :func:`tracemalloc.Traceback.__repr__` (regressed in Python 3.9). \ No newline at end of file diff --git a/Misc/NEWS.d/next/Library/2020-12-20-22-50-15.bpo-42681.lDO6jb.rst b/Misc/NEWS.d/next/Library/2020-12-20-22-50-15.bpo-42681.lDO6jb.rst deleted file mode 100644 index 34ea74a5a323d8..00000000000000 --- a/Misc/NEWS.d/next/Library/2020-12-20-22-50-15.bpo-42681.lDO6jb.rst +++ /dev/null @@ -1 +0,0 @@ -Fixed range checks for color and pair numbers in :mod:`curses`. diff --git a/Misc/NEWS.d/next/Library/2020-12-23-19-43-06.bpo-42727.WH3ODh.rst b/Misc/NEWS.d/next/Library/2020-12-23-19-43-06.bpo-42727.WH3ODh.rst deleted file mode 100644 index c2ef8eecb85e15..00000000000000 --- a/Misc/NEWS.d/next/Library/2020-12-23-19-43-06.bpo-42727.WH3ODh.rst +++ /dev/null @@ -1,2 +0,0 @@ -``EnumMeta.__prepare__`` now accepts ``**kwds`` to properly support -``__init_subclass__`` diff --git a/Misc/NEWS.d/next/Library/2020-12-25-12-32-47.bpo-42655.W5ytpV.rst b/Misc/NEWS.d/next/Library/2020-12-25-12-32-47.bpo-42655.W5ytpV.rst deleted file mode 100644 index 57c9a666e395aa..00000000000000 --- a/Misc/NEWS.d/next/Library/2020-12-25-12-32-47.bpo-42655.W5ytpV.rst +++ /dev/null @@ -1,2 +0,0 @@ -:mod:`subprocess` *extra_groups* is now correctly passed into setgroups() -system call. diff --git a/Misc/NEWS.d/next/Library/2020-12-27-18-47-01.bpo-23328._xqepZ.rst b/Misc/NEWS.d/next/Library/2020-12-27-18-47-01.bpo-23328._xqepZ.rst deleted file mode 100644 index 07b15d34e8d56b..00000000000000 --- a/Misc/NEWS.d/next/Library/2020-12-27-18-47-01.bpo-23328._xqepZ.rst +++ /dev/null @@ -1 +0,0 @@ -Allow / character in username, password fields on _PROXY envars. diff --git a/Misc/NEWS.d/next/Library/2020-12-27-21-22-01.bpo-42756.dHMPJ9.rst b/Misc/NEWS.d/next/Library/2020-12-27-21-22-01.bpo-42756.dHMPJ9.rst deleted file mode 100644 index 93a0bb010df2bb..00000000000000 --- a/Misc/NEWS.d/next/Library/2020-12-27-21-22-01.bpo-42756.dHMPJ9.rst +++ /dev/null @@ -1,2 +0,0 @@ -Configure LMTP Unix-domain socket to use socket global default timeout when -a timeout is not explicitly provided. diff --git a/Misc/NEWS.d/next/Library/2020-12-27-22-19-26.bpo-42759.lGi_03.rst b/Misc/NEWS.d/next/Library/2020-12-27-22-19-26.bpo-42759.lGi_03.rst deleted file mode 100644 index a5ec7d5820336d..00000000000000 --- a/Misc/NEWS.d/next/Library/2020-12-27-22-19-26.bpo-42759.lGi_03.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fixed equality comparison of :class:`tkinter.Variable` and -:class:`tkinter.font.Font`. Objects which belong to different Tcl -interpreters are now always different, even if they have the same name. diff --git a/Misc/NEWS.d/next/Library/2021-01-05-21-26-29.bpo-41748.KdC0w3.rst b/Misc/NEWS.d/next/Library/2021-01-05-21-26-29.bpo-41748.KdC0w3.rst deleted file mode 100644 index 52efa3ac3d40eb..00000000000000 --- a/Misc/NEWS.d/next/Library/2021-01-05-21-26-29.bpo-41748.KdC0w3.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix HTMLParser parsing rules for element attributes containing -commas with spaces. Patch by Karl Dubost. \ No newline at end of file diff --git a/Misc/NEWS.d/next/Library/2021-01-07-11-44-22.bpo-42851.uyQFyd.rst b/Misc/NEWS.d/next/Library/2021-01-07-11-44-22.bpo-42851.uyQFyd.rst deleted file mode 100644 index 927283521e80e3..00000000000000 --- a/Misc/NEWS.d/next/Library/2021-01-07-11-44-22.bpo-42851.uyQFyd.rst +++ /dev/null @@ -1 +0,0 @@ -remove __init_subclass__ support for Enum members diff --git a/Misc/NEWS.d/next/Library/2021-01-08-15-49-20.bpo-42780.rtqi6B.rst b/Misc/NEWS.d/next/Library/2021-01-08-15-49-20.bpo-42780.rtqi6B.rst deleted file mode 100644 index a491690507129e..00000000000000 --- a/Misc/NEWS.d/next/Library/2021-01-08-15-49-20.bpo-42780.rtqi6B.rst +++ /dev/null @@ -1 +0,0 @@ -Fix os.set_inheritable() for O_PATH file descriptors on Linux. diff --git a/Misc/NEWS.d/next/Library/2021-01-15-00-23-50.bpo-42931.QD6U2B.rst b/Misc/NEWS.d/next/Library/2021-01-15-00-23-50.bpo-42931.QD6U2B.rst deleted file mode 100644 index 01f8094944f70c..00000000000000 --- a/Misc/NEWS.d/next/Library/2021-01-15-00-23-50.bpo-42931.QD6U2B.rst +++ /dev/null @@ -1 +0,0 @@ -Add :func:`randbytes` to ``random.__all__``. diff --git a/Misc/NEWS.d/next/Library/2021-01-18-10-41-44.bpo-42944.RrONvy.rst b/Misc/NEWS.d/next/Library/2021-01-18-10-41-44.bpo-42944.RrONvy.rst deleted file mode 100644 index b78d10aa255454..00000000000000 --- a/Misc/NEWS.d/next/Library/2021-01-18-10-41-44.bpo-42944.RrONvy.rst +++ /dev/null @@ -1 +0,0 @@ -Fix ``random.Random.sample`` when ``counts`` argument is not ``None``. diff --git a/Misc/NEWS.d/next/Library/2021-02-02-20-23-31.bpo-43108.lqcCZ6.rst b/Misc/NEWS.d/next/Library/2021-02-02-20-23-31.bpo-43108.lqcCZ6.rst deleted file mode 100644 index 8e45640bceae13..00000000000000 --- a/Misc/NEWS.d/next/Library/2021-02-02-20-23-31.bpo-43108.lqcCZ6.rst +++ /dev/null @@ -1 +0,0 @@ -Fixed a reference leak in the :mod:`curses` module. Patch by Pablo Galindo diff --git a/Misc/NEWS.d/next/Library/2021-02-03-22-55-27.bpo-43102.TSlZ6J.rst b/Misc/NEWS.d/next/Library/2021-02-03-22-55-27.bpo-43102.TSlZ6J.rst deleted file mode 100644 index 985fd68a03a935..00000000000000 --- a/Misc/NEWS.d/next/Library/2021-02-03-22-55-27.bpo-43102.TSlZ6J.rst +++ /dev/null @@ -1,2 +0,0 @@ -The namedtuple __new__ method had its __builtins__ set to None instead -of an actual dictionary. This created problems for introspection tools. diff --git a/Misc/NEWS.d/next/Security/2021-01-18-09-27-31.bpo-42938.4Zn4Mp.rst b/Misc/NEWS.d/next/Security/2021-01-18-09-27-31.bpo-42938.4Zn4Mp.rst deleted file mode 100644 index 7df65a156feabd..00000000000000 --- a/Misc/NEWS.d/next/Security/2021-01-18-09-27-31.bpo-42938.4Zn4Mp.rst +++ /dev/null @@ -1,2 +0,0 @@ -Avoid static buffers when computing the repr of :class:`ctypes.c_double` and -:class:`ctypes.c_longdouble` values. diff --git a/Misc/NEWS.d/next/Security/2021-02-14-15-59-16.bpo-42967.YApqDS.rst b/Misc/NEWS.d/next/Security/2021-02-14-15-59-16.bpo-42967.YApqDS.rst deleted file mode 100644 index f08489b41494ea..00000000000000 --- a/Misc/NEWS.d/next/Security/2021-02-14-15-59-16.bpo-42967.YApqDS.rst +++ /dev/null @@ -1 +0,0 @@ -Fix web cache poisoning vulnerability by defaulting the query args separator to ``&``, and allowing the user to choose a custom separator. diff --git a/Misc/NEWS.d/next/Tests/2020-05-30-10-56-38.bpo-40810.LPqDLQ.rst b/Misc/NEWS.d/next/Tests/2020-05-30-10-56-38.bpo-40810.LPqDLQ.rst deleted file mode 100644 index eafd94cabede93..00000000000000 --- a/Misc/NEWS.d/next/Tests/2020-05-30-10-56-38.bpo-40810.LPqDLQ.rst +++ /dev/null @@ -1 +0,0 @@ -In :mod:`sqlite3`, fix ``CheckTraceCallbackContent`` for SQLite pre 3.7.15. diff --git a/Misc/NEWS.d/next/Tests/2021-01-01-08-52-36.bpo-42794.-7-XGz.rst b/Misc/NEWS.d/next/Tests/2021-01-01-08-52-36.bpo-42794.-7-XGz.rst deleted file mode 100644 index 577f2259e1f00c..00000000000000 --- a/Misc/NEWS.d/next/Tests/2021-01-01-08-52-36.bpo-42794.-7-XGz.rst +++ /dev/null @@ -1,2 +0,0 @@ -Update test_nntplib to use offical group name of news.aioe.org for testing. -Patch by Dong-hee Na. diff --git a/Misc/NEWS.d/next/Tools-Demos/2020-12-16-09-10-32.bpo-42613.J-jnm5.rst b/Misc/NEWS.d/next/Tools-Demos/2020-12-16-09-10-32.bpo-42613.J-jnm5.rst deleted file mode 100644 index 140ff8255b96b1..00000000000000 --- a/Misc/NEWS.d/next/Tools-Demos/2020-12-16-09-10-32.bpo-42613.J-jnm5.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix ``freeze.py`` tool to use the prope config and library directories. -Patch by Victor Stinner. diff --git a/Misc/NEWS.d/next/Tools-Demos/2020-12-23-19-42-11.bpo-42726.a5EkTv.rst b/Misc/NEWS.d/next/Tools-Demos/2020-12-23-19-42-11.bpo-42726.a5EkTv.rst deleted file mode 100644 index 01a6e7fe55f5b3..00000000000000 --- a/Misc/NEWS.d/next/Tools-Demos/2020-12-23-19-42-11.bpo-42726.a5EkTv.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fixed Python 3 compatibility issue with gdb/libpython.py handling of attribute -dictionaries. diff --git a/Misc/NEWS.d/next/Windows/2020-12-07-11-40-52.bpo-42584.AsYnVX.rst b/Misc/NEWS.d/next/Windows/2020-12-07-11-40-52.bpo-42584.AsYnVX.rst deleted file mode 100644 index afb6530c8f66d7..00000000000000 --- a/Misc/NEWS.d/next/Windows/2020-12-07-11-40-52.bpo-42584.AsYnVX.rst +++ /dev/null @@ -1 +0,0 @@ -Upgrade Windows installer to use SQLite 3.34.0. diff --git a/Misc/NEWS.d/next/Windows/2021-01-05-20-36-40.bpo-41837.bmS7vB.rst b/Misc/NEWS.d/next/Windows/2021-01-05-20-36-40.bpo-41837.bmS7vB.rst deleted file mode 100644 index 8d4bb34ff909c2..00000000000000 --- a/Misc/NEWS.d/next/Windows/2021-01-05-20-36-40.bpo-41837.bmS7vB.rst +++ /dev/null @@ -1 +0,0 @@ -Updated Windows installer to include OpenSSL 1.1.1i diff --git a/Misc/NEWS.d/next/macOS/2020-12-07-11-37-35.bpo-42584.LygmqQ.rst b/Misc/NEWS.d/next/macOS/2020-12-07-11-37-35.bpo-42584.LygmqQ.rst deleted file mode 100644 index 2a625f98e90781..00000000000000 --- a/Misc/NEWS.d/next/macOS/2020-12-07-11-37-35.bpo-42584.LygmqQ.rst +++ /dev/null @@ -1 +0,0 @@ -Update macOS installer to use SQLite 3.34.0. diff --git a/Misc/NEWS.d/next/macOS/2021-01-04-00-48-08.bpo-41837.dX-unJ.rst b/Misc/NEWS.d/next/macOS/2021-01-04-00-48-08.bpo-41837.dX-unJ.rst deleted file mode 100644 index 3f9415f4a36064..00000000000000 --- a/Misc/NEWS.d/next/macOS/2021-01-04-00-48-08.bpo-41837.dX-unJ.rst +++ /dev/null @@ -1 +0,0 @@ -Update macOS installer build to use OpenSSL 1.1.1i. diff --git a/Misc/NEWS.d/next/macOS/2021-01-04-01-17-17.bpo-42361.eolZAi.rst b/Misc/NEWS.d/next/macOS/2021-01-04-01-17-17.bpo-42361.eolZAi.rst deleted file mode 100644 index 39526b32935b8c..00000000000000 --- a/Misc/NEWS.d/next/macOS/2021-01-04-01-17-17.bpo-42361.eolZAi.rst +++ /dev/null @@ -1,2 +0,0 @@ -Update macOS installer build to use Tcl/Tk 8.6.11 (rc2, expected to be final -release). diff --git a/Misc/NEWS.d/next/macOS/2021-01-26-14-36-11.bpo-42504.ZxWt71.rst b/Misc/NEWS.d/next/macOS/2021-01-26-14-36-11.bpo-42504.ZxWt71.rst deleted file mode 100644 index a47776effe905e..00000000000000 --- a/Misc/NEWS.d/next/macOS/2021-01-26-14-36-11.bpo-42504.ZxWt71.rst +++ /dev/null @@ -1,3 +0,0 @@ -Ensure that the value of -sysconfig.get_config_var('MACOSX_DEPLOYMENT_TARGET') is always a string, -even in when the value is parsable as an integer. diff --git a/README.rst b/README.rst index bb43311ad2f95d..a2d2b831806870 100644 --- a/README.rst +++ b/README.rst @@ -1,5 +1,5 @@ -This is Python version 3.9.1 -============================ +This is Python version 3.9.2rc1 +=============================== .. image:: https://travis-ci.org/python/cpython.svg?branch=3.9 :alt: CPython build status on Travis CI From eba45a8ea704a7d898e5721ee2811344969c0d9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Langa?= Date: Tue, 16 Feb 2021 22:34:29 +0100 Subject: [PATCH 0943/1314] Post 3.9.2rc1 --- Include/patchlevel.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Include/patchlevel.h b/Include/patchlevel.h index ef02372f8b22ca..1e84a276d83635 100644 --- a/Include/patchlevel.h +++ b/Include/patchlevel.h @@ -23,7 +23,7 @@ #define PY_RELEASE_SERIAL 1 /* Version as a string */ -#define PY_VERSION "3.9.2rc1" +#define PY_VERSION "3.9.2rc1+" /*--end constants--*/ /* Version as a single 4-byte hex number, e.g. 0x010502B2 == 1.5.2b2. From ebe20d9e7eb138c053958bc0a3058d34c6e1a679 Mon Sep 17 00:00:00 2001 From: Zackery Spytz Date: Wed, 17 Feb 2021 03:53:45 -0700 Subject: [PATCH 0944/1314] bpo-43155: Add PyCMethod_New to PC/python3.def (GH-24500) (GH-24554) (cherry picked from commit 8a8b5df93f379f561aab4f2fc5b2ad54f5009f7a) --- .../NEWS.d/next/Windows/2021-02-10-04-16-51.bpo-43155.O1tURk.rst | 1 + PC/python3.def | 1 + 2 files changed, 2 insertions(+) create mode 100644 Misc/NEWS.d/next/Windows/2021-02-10-04-16-51.bpo-43155.O1tURk.rst diff --git a/Misc/NEWS.d/next/Windows/2021-02-10-04-16-51.bpo-43155.O1tURk.rst b/Misc/NEWS.d/next/Windows/2021-02-10-04-16-51.bpo-43155.O1tURk.rst new file mode 100644 index 00000000000000..2eeef2b0ea27a6 --- /dev/null +++ b/Misc/NEWS.d/next/Windows/2021-02-10-04-16-51.bpo-43155.O1tURk.rst @@ -0,0 +1 @@ +:c:func:`PyCMethod_New` is now present in ``python3.lib``. diff --git a/PC/python3.def b/PC/python3.def index fce01249758e29..d27d7d07128a41 100644 --- a/PC/python3.def +++ b/PC/python3.def @@ -40,6 +40,7 @@ EXPORTS PyCFunction_GetSelf=python39.PyCFunction_GetSelf PyCFunction_New=python39.PyCFunction_New PyCFunction_NewEx=python39.PyCFunction_NewEx + PyCMethod_New=python39.PyCMethod_New PyCFunction_Type=python39.PyCFunction_Type DATA PyCallIter_New=python39.PyCallIter_New PyCallIter_Type=python39.PyCallIter_Type DATA From ec2385e315fc6b28d92dfb4c97fefcbb1e7daa68 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 18 Feb 2021 12:07:30 -0800 Subject: [PATCH 0945/1314] Remove all links to mingw.org (GH-24552) This lease on this domain has lapsed. This not only makes these dead links, but a potential attack vector for readers of python.org as the domain can be obtained by an untrustworthy party. I considered redirecting these links to http://mingw-w64.org/ which is a maintained fork of mingw, but beyond my unfamiliarity with the exact level of compatibility, at the time of this PR that site had an expired cert and so is not much of a vulnerability fix. Automerge-Triggered-By: GH:Mariatta (cherry picked from commit 743932d50815edbe4ffd530ae091c53ae47dd34b) Co-authored-by: Jeremy Paige --- Doc/install/index.rst | 3 +-- Doc/using/windows.rst | 2 -- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/Doc/install/index.rst b/Doc/install/index.rst index e6d5a3e6ebde60..ae0d0294ef7773 100644 --- a/Doc/install/index.rst +++ b/Doc/install/index.rst @@ -1064,8 +1064,7 @@ normal libraries do. .. [#] This also means you could replace all existing COFF-libraries with OMF-libraries of the same name. -.. [#] Check https://www.sourceware.org/cygwin/ and http://www.mingw.org/ for more - information +.. [#] Check https://www.sourceware.org/cygwin/ for more information .. [#] Then you have no POSIX emulation available, but you also don't need :file:`cygwin1.dll`. diff --git a/Doc/using/windows.rst b/Doc/using/windows.rst index 857308e77dd1bf..4699e37509e6f3 100644 --- a/Doc/using/windows.rst +++ b/Doc/using/windows.rst @@ -1155,8 +1155,6 @@ For extension modules, consult :ref:`building-on-windows`. MinGW gcc under Windows" or "Installing Python extension with distutils and without Microsoft Visual C++" by Sébastien Sauvage, 2003 - `MingW -- Python extensions `_ - Other Platforms =============== From 138488750512b47f1773630f90e92ec5038b6978 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 18 Feb 2021 18:16:30 -0800 Subject: [PATCH 0946/1314] closes bpo-43254: Fix *snprintf() man page refs. (GH-24563) (cherry picked from commit e92d67dfbb4790df37aa6a0961fb6dc7e8d2fbbf) Co-authored-by: Erlend Egeberg Aasland --- Doc/c-api/conversion.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/c-api/conversion.rst b/Doc/c-api/conversion.rst index b310fcb5e4f91e..ee76accae62b8d 100644 --- a/Doc/c-api/conversion.rst +++ b/Doc/c-api/conversion.rst @@ -11,14 +11,14 @@ Functions for number conversion and formatted string output. .. c:function:: int PyOS_snprintf(char *str, size_t size, const char *format, ...) Output not more than *size* bytes to *str* according to the format string - *format* and the extra arguments. See the Unix man page :manpage:`snprintf(2)`. + *format* and the extra arguments. See the Unix man page :manpage:`snprintf(3)`. .. c:function:: int PyOS_vsnprintf(char *str, size_t size, const char *format, va_list va) Output not more than *size* bytes to *str* according to the format string *format* and the variable argument list *va*. Unix man page - :manpage:`vsnprintf(2)`. + :manpage:`vsnprintf(3)`. :c:func:`PyOS_snprintf` and :c:func:`PyOS_vsnprintf` wrap the Standard C library functions :c:func:`snprintf` and :c:func:`vsnprintf`. Their purpose is to From 1a79785e3e8fea80bcf6a800b45a04e06c787480 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Langa?= Date: Fri, 19 Feb 2021 13:31:44 +0100 Subject: [PATCH 0947/1314] Python 3.9.2 --- Include/patchlevel.h | 6 +++--- Lib/pydoc_data/topics.py | 2 +- Misc/NEWS.d/3.9.2.rst | 7 +++++++ .../next/Windows/2021-02-10-04-16-51.bpo-43155.O1tURk.rst | 1 - README.rst | 4 ++-- 5 files changed, 13 insertions(+), 7 deletions(-) create mode 100644 Misc/NEWS.d/3.9.2.rst delete mode 100644 Misc/NEWS.d/next/Windows/2021-02-10-04-16-51.bpo-43155.O1tURk.rst diff --git a/Include/patchlevel.h b/Include/patchlevel.h index 1e84a276d83635..a23b2f15f79f93 100644 --- a/Include/patchlevel.h +++ b/Include/patchlevel.h @@ -19,11 +19,11 @@ #define PY_MAJOR_VERSION 3 #define PY_MINOR_VERSION 9 #define PY_MICRO_VERSION 2 -#define PY_RELEASE_LEVEL PY_RELEASE_LEVEL_GAMMA -#define PY_RELEASE_SERIAL 1 +#define PY_RELEASE_LEVEL PY_RELEASE_LEVEL_FINAL +#define PY_RELEASE_SERIAL 0 /* Version as a string */ -#define PY_VERSION "3.9.2rc1+" +#define PY_VERSION "3.9.2" /*--end constants--*/ /* Version as a single 4-byte hex number, e.g. 0x010502B2 == 1.5.2b2. diff --git a/Lib/pydoc_data/topics.py b/Lib/pydoc_data/topics.py index acaae371aeb229..ae896c2e5afd6e 100644 --- a/Lib/pydoc_data/topics.py +++ b/Lib/pydoc_data/topics.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -# Autogenerated by Sphinx on Tue Feb 16 21:03:59 2021 +# Autogenerated by Sphinx on Fri Feb 19 13:29:38 2021 topics = {'assert': 'The "assert" statement\n' '**********************\n' '\n' diff --git a/Misc/NEWS.d/3.9.2.rst b/Misc/NEWS.d/3.9.2.rst new file mode 100644 index 00000000000000..a2756a9f9e0768 --- /dev/null +++ b/Misc/NEWS.d/3.9.2.rst @@ -0,0 +1,7 @@ +.. bpo: 43155 +.. date: 2021-02-10-04-16-51 +.. nonce: O1tURk +.. release date: 2021-02-19 +.. section: Windows + +:c:func:`PyCMethod_New` is now present in ``python3.lib``. diff --git a/Misc/NEWS.d/next/Windows/2021-02-10-04-16-51.bpo-43155.O1tURk.rst b/Misc/NEWS.d/next/Windows/2021-02-10-04-16-51.bpo-43155.O1tURk.rst deleted file mode 100644 index 2eeef2b0ea27a6..00000000000000 --- a/Misc/NEWS.d/next/Windows/2021-02-10-04-16-51.bpo-43155.O1tURk.rst +++ /dev/null @@ -1 +0,0 @@ -:c:func:`PyCMethod_New` is now present in ``python3.lib``. diff --git a/README.rst b/README.rst index a2d2b831806870..0a36bc16a958b8 100644 --- a/README.rst +++ b/README.rst @@ -1,5 +1,5 @@ -This is Python version 3.9.2rc1 -=============================== +This is Python version 3.9.2 +============================ .. image:: https://travis-ci.org/python/cpython.svg?branch=3.9 :alt: CPython build status on Travis CI From 8cc6e27bd61c51daad56a98c1c75b1fd3345feb1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Langa?= Date: Fri, 19 Feb 2021 13:32:44 +0100 Subject: [PATCH 0948/1314] Post 3.9.2 --- Include/patchlevel.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Include/patchlevel.h b/Include/patchlevel.h index a23b2f15f79f93..92d004e3858efd 100644 --- a/Include/patchlevel.h +++ b/Include/patchlevel.h @@ -23,7 +23,7 @@ #define PY_RELEASE_SERIAL 0 /* Version as a string */ -#define PY_VERSION "3.9.2" +#define PY_VERSION "3.9.2+" /*--end constants--*/ /* Version as a single 4-byte hex number, e.g. 0x010502B2 == 1.5.2b2. From 1cfed3d5b0ec1419c8a1d5cf8bff1a6e1483771a Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 19 Feb 2021 07:55:44 -0800 Subject: [PATCH 0949/1314] closes bpo-43266: Improve array formatting. (GH-24573) (cherry picked from commit 2d3e463e4a5aa109d1c15c86f9631580f5ef7a7e) Co-authored-by: Erlend Egeberg Aasland --- Doc/c-api/conversion.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Doc/c-api/conversion.rst b/Doc/c-api/conversion.rst index ee76accae62b8d..0cc836b70a018f 100644 --- a/Doc/c-api/conversion.rst +++ b/Doc/c-api/conversion.rst @@ -25,7 +25,7 @@ functions :c:func:`snprintf` and :c:func:`vsnprintf`. Their purpose is to guarantee consistent behavior in corner cases, which the Standard C functions do not. -The wrappers ensure that *str*[*size*-1] is always ``'\0'`` upon return. They +The wrappers ensure that ``str[size-1]`` is always ``'\0'`` upon return. They never write more than *size* bytes (including the trailing ``'\0'``) into str. Both functions require that ``str != NULL``, ``size > 0`` and ``format != NULL``. @@ -38,13 +38,13 @@ The return value (*rv*) for these functions should be interpreted as follows: * When ``0 <= rv < size``, the output conversion was successful and *rv* characters were written to *str* (excluding the trailing ``'\0'`` byte at - *str*[*rv*]). + ``str[rv]``). * When ``rv >= size``, the output conversion was truncated and a buffer with - ``rv + 1`` bytes would have been needed to succeed. *str*[*size*-1] is ``'\0'`` + ``rv + 1`` bytes would have been needed to succeed. ``str[size-1]`` is ``'\0'`` in this case. -* When ``rv < 0``, "something bad happened." *str*[*size*-1] is ``'\0'`` in +* When ``rv < 0``, "something bad happened." ``str[size-1]`` is ``'\0'`` in this case too, but the rest of *str* is undefined. The exact cause of the error depends on the underlying platform. From a67fd011eadfae7103ca9e0a0b0f8312e4f00b0f Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 19 Feb 2021 16:46:57 -0800 Subject: [PATCH 0950/1314] bpo-43042: Augment tutorial sentence (GH-24514) Calling same function also gets new local namespace. (cherry picked from commit b30fcba3a8abaabd1087f2392ae8aec4c1b1f210) Co-authored-by: Terry Jan Reedy --- Doc/tutorial/controlflow.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Doc/tutorial/controlflow.rst b/Doc/tutorial/controlflow.rst index 3af288a17b270d..97b4c6363a239c 100644 --- a/Doc/tutorial/controlflow.rst +++ b/Doc/tutorial/controlflow.rst @@ -294,7 +294,8 @@ referenced. The actual parameters (arguments) to a function call are introduced in the local symbol table of the called function when it is called; thus, arguments are passed using *call by value* (where the *value* is always an object *reference*, -not the value of the object). [#]_ When a function calls another function, a new +not the value of the object). [#]_ When a function calls another function, +or calls itself recursively, a new local symbol table is created for that call. A function definition associates the function name with the function object in From f9d1bf2de07131a8d80bc1e4914ee534bc5effa4 Mon Sep 17 00:00:00 2001 From: Pablo Galindo Date: Sat, 20 Feb 2021 01:36:15 +0000 Subject: [PATCH 0951/1314] [3.9] bpo-43272: Fix old parser test failures for backported grammar constructs (GH-24591) --- Lib/test/test_fstring.py | 8 +++--- Lib/test/test_named_expressions.py | 3 ++ Lib/test/test_unpack_ex.py | 45 +++++++++++++++++------------- 3 files changed, 33 insertions(+), 23 deletions(-) diff --git a/Lib/test/test_fstring.py b/Lib/test/test_fstring.py index 2f08d35f26dc3b..05e7102d624f3e 100644 --- a/Lib/test/test_fstring.py +++ b/Lib/test/test_fstring.py @@ -374,10 +374,10 @@ def test_ast_line_numbers_with_parentheses(self): # check the call call = middle.value self.assertEqual(type(call), ast.Call) - self.assertEqual(call.lineno, 5) - self.assertEqual(call.end_lineno, 5) - self.assertEqual(call.col_offset, 27) - self.assertEqual(call.end_col_offset, 31) + self.assertEqual(call.lineno, 4 if use_old_parser() else 5) + self.assertEqual(call.end_lineno, 4 if use_old_parser() else 5) + self.assertEqual(call.col_offset, 13 if use_old_parser() else 27) + self.assertEqual(call.end_col_offset, 17 if use_old_parser() else 31) # check the second wat self.assertEqual(type(wat2), ast.Constant) self.assertEqual(wat2.lineno, 4) diff --git a/Lib/test/test_named_expressions.py b/Lib/test/test_named_expressions.py index 2adcd4b5d64666..55c003888d478b 100644 --- a/Lib/test/test_named_expressions.py +++ b/Lib/test/test_named_expressions.py @@ -1,4 +1,5 @@ import unittest +from test.support import use_old_parser GLOBAL_VAR = None @@ -167,6 +168,7 @@ def test_named_expression_invalid_list_comprehension_iterable_expression(self): with self.assertRaisesRegex(SyntaxError, msg): exec(f"lambda: {code}", {}) # Function scope + @unittest.skipIf(use_old_parser(), "Old parser does not support walruses in set comprehensions") def test_named_expression_invalid_rebinding_set_comprehension_iteration_variable(self): cases = [ ("Local reuse", 'i', "{i := 0 for i in range(5)}"), @@ -199,6 +201,7 @@ def test_named_expression_invalid_rebinding_set_comprehension_inner_loop(self): with self.assertRaisesRegex(SyntaxError, msg): exec(f"lambda: {code}", {}) # Function scope + @unittest.skipIf(use_old_parser(), "Old parser does not support walruses in set comprehensions") def test_named_expression_invalid_set_comprehension_iterable_expression(self): cases = [ ("Top level", "{i for i in (i := range(5))}"), diff --git a/Lib/test/test_unpack_ex.py b/Lib/test/test_unpack_ex.py index 049e48b13fa1f9..2dff57c268f072 100644 --- a/Lib/test/test_unpack_ex.py +++ b/Lib/test/test_unpack_ex.py @@ -1,5 +1,7 @@ # Tests for extended unpacking, starred expressions. +from test.support import use_old_parser + doctests = """ Unpack tuple @@ -346,6 +348,26 @@ ... SyntaxError: can't use starred expression here +Some size constraints (all fail.) + + >>> s = ", ".join("a%d" % i for i in range(1<<8)) + ", *rest = range(1<<8 + 1)" + >>> compile(s, 'test', 'exec') # doctest:+ELLIPSIS + Traceback (most recent call last): + ... + SyntaxError: too many expressions in star-unpacking assignment + + >>> s = ", ".join("a%d" % i for i in range(1<<8 + 1)) + ", *rest = range(1<<8 + 2)" + >>> compile(s, 'test', 'exec') # doctest:+ELLIPSIS + Traceback (most recent call last): + ... + SyntaxError: too many expressions in star-unpacking assignment + +(there is an additional limit, on the number of expressions after the +'*rest', but it's 1<<24 and testing it takes too much memory.) + +""" + +new_parser_doctests = """\ >>> (*x),y = 1, 2 # doctest:+ELLIPSIS Traceback (most recent call last): ... @@ -370,27 +392,12 @@ Traceback (most recent call last): ... SyntaxError: can't use starred expression here - -Some size constraints (all fail.) - - >>> s = ", ".join("a%d" % i for i in range(1<<8)) + ", *rest = range(1<<8 + 1)" - >>> compile(s, 'test', 'exec') # doctest:+ELLIPSIS - Traceback (most recent call last): - ... - SyntaxError: too many expressions in star-unpacking assignment - - >>> s = ", ".join("a%d" % i for i in range(1<<8 + 1)) + ", *rest = range(1<<8 + 2)" - >>> compile(s, 'test', 'exec') # doctest:+ELLIPSIS - Traceback (most recent call last): - ... - SyntaxError: too many expressions in star-unpacking assignment - -(there is an additional limit, on the number of expressions after the -'*rest', but it's 1<<24 and testing it takes too much memory.) - """ -__test__ = {'doctests' : doctests} +if use_old_parser(): + __test__ = {'doctests' : doctests} +else: + __test__ = {'doctests' : doctests + new_parser_doctests} def test_main(verbose=False): from test import support From 216cb1469f566ba5493bf53a73da9ccdac05ccfc Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 19 Feb 2021 20:46:34 -0800 Subject: [PATCH 0952/1314] Fix typo in dis module doc (GH-24509) (cherry picked from commit 292f23186c6573bc1c3fa4f6e91116e8ee444cf4) Co-authored-by: Irit Katriel --- Doc/library/dis.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/dis.rst b/Doc/library/dis.rst index c1e72d1d1633b5..08730c4d993517 100644 --- a/Doc/library/dis.rst +++ b/Doc/library/dis.rst @@ -346,7 +346,7 @@ The Python compiler currently generates the following bytecode instructions. .. opcode:: ROT_FOUR - Lifts second, third and forth stack items one position up, moves top down + Lifts second, third and fourth stack items one position up, moves top down to position four. .. versionadded:: 3.8 From 7cc58890b3c16c28360a9abe030258426e89fec1 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 20 Feb 2021 18:55:49 -0800 Subject: [PATCH 0953/1314] bpo-27646: Say that 'yield from' expression can be any iterable (GH-24595) Previously, the doc at least strongly implied that it had to be an iterator. (cherry picked from commit 2f9ef514fb24b6a95bd3272885f197752810c107) Co-authored-by: Terry Jan Reedy --- Doc/reference/expressions.rst | 4 ++-- .../Documentation/2021-02-20-00-09-13.bpo-27646.HRsmo-.rst | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Documentation/2021-02-20-00-09-13.bpo-27646.HRsmo-.rst diff --git a/Doc/reference/expressions.rst b/Doc/reference/expressions.rst index 512aa5af956198..9b1a395b724d92 100644 --- a/Doc/reference/expressions.rst +++ b/Doc/reference/expressions.rst @@ -476,8 +476,8 @@ allowing any pending :keyword:`finally` clauses to execute. .. index:: single: from; yield from expression -When ``yield from `` is used, it treats the supplied expression as -a subiterator. All values produced by that subiterator are passed directly +When ``yield from `` is used, the supplied expression must be an +iterable. The values produced by iterating that iterable are passed directly to the caller of the current generator's methods. Any values passed in with :meth:`~generator.send` and any exceptions passed in with :meth:`~generator.throw` are passed to the underlying iterator if it has the diff --git a/Misc/NEWS.d/next/Documentation/2021-02-20-00-09-13.bpo-27646.HRsmo-.rst b/Misc/NEWS.d/next/Documentation/2021-02-20-00-09-13.bpo-27646.HRsmo-.rst new file mode 100644 index 00000000000000..8ba398adf61826 --- /dev/null +++ b/Misc/NEWS.d/next/Documentation/2021-02-20-00-09-13.bpo-27646.HRsmo-.rst @@ -0,0 +1,2 @@ +Clarify that 'yield from ' works with any iterable, not just +iterators. From 693aeacf8851d1e9995073e27e50644a505dc49c Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 21 Feb 2021 00:07:33 -0800 Subject: [PATCH 0954/1314] bpo-43283: Rearrange some IDLE doc paragraphs. (GH-24604) In the Running User Code section, gather together paragraphs about two processes and the sys.stdstream replacements, preparing to add another. (cherry picked from commit 4cf7bb8e22bf37e6d65bf4cb5618d09c4a8ad612) Co-authored-by: Terry Jan Reedy --- Doc/library/idle.rst | 29 ++++++++++++++-------------- Lib/idlelib/help.html | 44 +++++++++++++++++++++---------------------- 2 files changed, 37 insertions(+), 36 deletions(-) diff --git a/Doc/library/idle.rst b/Doc/library/idle.rst index e7eaabd8bfa25a..fc45e3161bc6d5 100644 --- a/Doc/library/idle.rst +++ b/Doc/library/idle.rst @@ -726,28 +726,29 @@ with objects that get input from and send output to the Shell window. The original values stored in ``sys.__stdin__``, ``sys.__stdout__``, and ``sys.__stderr__`` are not touched, but may be ``None``. -When Shell has the focus, it controls the keyboard and screen. This is -normally transparent, but functions that directly access the keyboard -and screen will not work. These include system-specific functions that -determine whether a key has been pressed and if so, which. - IDLE's standard stream replacements are not inherited by subprocesses -created in the execution process, whether directly by user code or by modules -such as multiprocessing. If such subprocess use ``input`` from sys.stdin -or ``print`` or ``write`` to sys.stdout or sys.stderr, +created in the execution process, whether directly by user code or by +modules such as multiprocessing. If such subprocess use ``input`` from +sys.stdin or ``print`` or ``write`` to sys.stdout or sys.stderr, IDLE should be started in a command line window. The secondary subprocess will then be attached to that window for input and output. -The IDLE code running in the execution process adds frames to the call stack -that would not be there otherwise. IDLE wraps ``sys.getrecursionlimit`` and -``sys.setrecursionlimit`` to reduce the effect of the additional stack frames. - If ``sys`` is reset by user code, such as with ``importlib.reload(sys)``, IDLE's changes are lost and input from the keyboard and output to the screen will not work correctly. -When user code raises SystemExit either directly or by calling sys.exit, IDLE -returns to a Shell prompt instead of exiting. +When Shell has the focus, it controls the keyboard and screen. This is +normally transparent, but functions that directly access the keyboard +and screen will not work. These include system-specific functions that +determine whether a key has been pressed and if so, which. + +The IDLE code running in the execution process adds frames to the call stack +that would not be there otherwise. IDLE wraps ``sys.getrecursionlimit`` and +``sys.setrecursionlimit`` to reduce the effect of the additional stack +frames. + +When user code raises SystemExit either directly or by calling sys.exit, +IDLE returns to a Shell prompt instead of exiting. User output in Shell ^^^^^^^^^^^^^^^^^^^^ diff --git a/Lib/idlelib/help.html b/Lib/idlelib/help.html index 170999e1280173..1eefa506e2c8d9 100644 --- a/Lib/idlelib/help.html +++ b/Lib/idlelib/help.html @@ -5,7 +5,7 @@ - IDLE — Python 3.10.0a1 documentation + IDLE — Python 3.10.0a5 documentation @@ -18,7 +18,7 @@ @@ -32,7 +32,6 @@ -