Compare commits

..

98 Commits

Author SHA1 Message Date
Cheryl Sabella e40e2a2cc9
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 <tjreedy@udel.edu>
2021-01-05 02:26:43 -05:00
Serhiy Storchaka 59f9b4e450
bpo-42681: Fix test_curses failures related to color pairs (GH-24089)
On ncurses 6.1 pair numbers are limited by SHORT_MAX-1, even
with extended color support.

Improve error reporting and tests for color functions.
2021-01-05 09:13:15 +02:00
Brandt Bucher 27f9dafc2b
bpo-40636: Remove overly-strict zip pickling tests (GH-24109) 2021-01-04 23:05:29 -08:00
Brandt Bucher cde988e893
Fix broken NEWS markup (GH-24110) 2021-01-04 22:55:14 -08:00
Erlend Egeberg Aasland f7f0ed59bc
bpo-40810: Fix CheckTraceCallbackContent for SQLite pre 3.7.15 (GH-20530)
Ref. [SQLite 3.7.15 changelog](https://sqlite.org/changes.html#version_3_7_15):
_"Avoid invoking the sqlite3_trace() callback multiple times when a statement is automatically reprepared due to SQLITE_SCHEMA errors."_
2021-01-04 15:16:43 -08:00
Erlend Egeberg Aasland 0b858cdd5d
bpo-1635741: Convert _multibytecodec to multi-phase init (GH-24095)
Convert the _multibytecodec extension module (CJK codecs) to multi-phase
initialization (PEP 489).
2021-01-04 22:33:45 +01:00
Pablo Galindo 958acd2da0
Post 3.10.0a4 2021-01-04 21:17:03 +00:00
Pablo Galindo ef2d371dee Python 3.10.0a4
-----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCAAdFiEEz9yiRbEEPPKl+Xhl/+h0BBaL2EcFAl/zT6kACgkQ/+h0BBaL
 2EeKVhAAxHzHdp1zZyDgqx0yBoHrB/N7aA5aL8dsrRPPIp+vd6CVanCymd2I2W59
 N8ouYoXFDUbDoWW/E26ggnMtbDtN7HUmMV48v9KIeDHVIR+CcSePcT9cWldmZr+m
 9J7aVoU/MswsLbUpLh5XnXYFbPziv2lsaMWz/j/6EX6VpzVuvmS0sg+xYea6/Kg0
 GyE2Le7p5WZ+5He1OJJOPFJ9/yOzj9fix2DDhRP7ZP8Oi+vPlRsDGMO1E3YKQzP1
 4bWhhoSCTDGIW6l0j41xGZYyW7Ror6FqpJqOGygYsA9LwryPdhqQVIVR7sqoK0sC
 xmLF1XrZhipNi+in7XxtmStor9MGVu5oR4Ieawhd70LEOrfdux2I7vTCEz4YqW0K
 7evxZ4fjfKALkAoJZ6WhUHcJf97n08+lyGo5Ng4miBi0VXYaj45l6pdpEPOZKfx1
 flXYThu4VOfZ7ggi4Y/Mxi4U2sQVbNtXD19KhrxsKe+wdfRQ2I/fkYrz/nCA/bJe
 qt7HO9AuyiqbBWQ88ZrnHsZLiuidXiBEQ5Evxb2aDNx+gOTeoa+W02BflRZ2wQN5
 d9+/THh0LE12OARa8DZvYYWRj/IiKLx5YbVkuhMxwBbWpSO4nlq2OKhX5Cdc3hxd
 Pp4j5oZX0Wg283vIwgfZYa3E0TfjSs+bu2euCMsWe/7oFw4ZNKc=
 =3nPI
 -----END PGP SIGNATURE-----
gpgsig -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCAAdFiEEz9yiRbEEPPKl+Xhl/+h0BBaL2EcFAl/zhaAACgkQ/+h0BBaL
 2Ecvow//bxy+jIPxR7IDlnTOxUMBXU/97ed9AozzPUzfov09S5OYP04S1UDC8dqt
 DqLzCBPJrc/+t8t6q2oksfOJGHrPJOQIBDKEST7yxa0k7TbZodJ3QVqHAe2dYF48
 QbACiOphBCXwUBR+Gk6kJxZAPUZelyUxL4ZgZMhFvJD5ONVl3VWeMzodCejYluYM
 Zs6MRMOHvbcaZgrB4M7fn2TS+ZAaFqORsMx/FSzNLmJf+42iTI/ZGICwRFMaiB6V
 Z1A9ajvcm8W37RL1GLAe7fE43WUzmE1QhwGnVv2kRoz5Q5tHJy8Rcp//ZIAUCTXq
 4jCX24T0H7ze/vPEkdX4TYc/3Xzd5vR2WqIyVnNjdM/Ye6ouuHmyf701Ql17qBRU
 fJ3aINJkOnXzmlPMsClrA9VxsBnX7raJHuj3YkCkUZv+jM6oap8IwGCO3uTkGVpa
 SiIuZ/2SmSujT6b67CZrBgmJB30uGzUKiqPZKT2rYgLS8C7PnGg0gaPfrcVIvwxZ
 XRAkDBzlY0mhmj8ss66UJc83faLYI+3ralSoRhR/5F3JLd7bIC/0TUBBTbZP9Jec
 +sxO+RQHG2TbN89mULDqbfsPRTuNIF83s9Zcg2OQG09ClVNEfdUKZ1UgMo+X/nST
 ZShaM3oQ720VN9ZzMJrzglMESs2QT37ERKtehInR1YDBytydD3c=
 =UiJ+
 -----END PGP SIGNATURE-----

Merge tag 'v3.10.0a4'

Python 3.10.0a4
2021-01-04 21:16:13 +00:00
Steve Dower af4cd16479
Do not remove x bit from published directories (GH-24101) 2021-01-04 20:56:32 +00:00
Mark Shannon 127dde5916
bpo-42810: Mark jumps at end of if and try statements as artificial. (GH-24091)
* Mark jumps at end of if and try statements as artificial.

* Update importlib

* Add comment explaining the purpose of ADDOP_JUMP_NOLINE.
2021-01-04 18:06:55 +00:00
Pablo Galindo 445f7f54b1
Python 3.10.0a4 2021-01-04 17:26:00 +00:00
Pablo Galindo de833b6013
Fix 'make suspicious' for the itertools module (GH-24097) 2021-01-04 17:24:22 +00:00
Mohamed Koubaa c8a87addb1
bpo-1635741: Port pyexpat to multi-phase init (PEP 489) (GH-22222) 2021-01-04 15:34:26 +01:00
Mark Shannon bf06b209da
Delete the now unused c_do_not_emit_bytecode field. (#24094) 2021-01-04 13:51:17 +00:00
Joshua Root df21f502fd
bpo-42692: fix __builtin_available check on older compilers (GH-23873)
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
2021-01-04 02:36:58 -08:00
Serhiy Storchaka b6fc0c406e
bpo-42789: Enable using /dev/tty in test_curses. (GH-24085)
It was temporary disabled for debugging.
2021-01-04 12:30:20 +02:00
Ned Deily 0f3b96b368
Update Sphinx version for macOS installer build. (GH-24082) 2021-01-04 04:43:53 -05:00
Ned Deily a38e04b566
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.
2021-01-04 04:43:11 -05:00
Ned Deily 14097a2785
bpo-41837: Update macOS installer build to use OpenSSL 1.1.1i. (GH-24080) 2021-01-04 04:39:47 -05:00
Erlend Egeberg Aasland c94ee13ad5
bpo-42584: Update macOS installer to use SQLite 3.34.0 (GH-23674) 2021-01-03 23:48:19 -05:00
Serhiy Storchaka 1470edd613
bpo-42681: Fix range checks for color and pair numbers in curses (GH-23874) 2021-01-03 22:51:11 +02:00
Hai Shi 7c83eaa536
bpo-41798: pyexpat: Allocate the expat_CAPI on the heap memory (GH-24061) 2021-01-03 16:47:44 +01:00
Erlend Egeberg Aasland b8eb376590
bpo-40077: Add traverse/clear/free to arraymodule (GH-24066) 2021-01-03 14:11:15 +01:00
Zackery Spytz 6613676861
bpo-38308: Fix the "versionchanged" for the *weights* of harmonic_mean() (GH-23919) 2021-01-03 14:35:26 +02:00
Zackery Spytz 5d3553b0a8
bpo-42814: Fix undefined behavior in Objects/genericaliasobject.c (GH-24073)
In is_typing_name(), va_end() is not always called before the
function returns.  It is undefined behavior to call va_start()
without also calling va_end().
2021-01-03 13:18:25 +01:00
Pablo Galindo 9e8fe1986c
bpo-42093: Tweak the what's new message about the new LOAD_ATTR opcode cache (GH-24070) 2021-01-03 04:37:46 +00:00
Pablo Galindo bd2728b1e8
bpo-42806: Fix ast locations of f-strings inside parentheses (GH-24067) 2021-01-03 01:11:41 +00:00
Lysandros Nikolaou 2ea320dddd
bpo-40631: Disallow single parenthesized star target (GH-24027) 2021-01-03 01:14:21 +02:00
Raymond Hettinger 8f8de7380c
No need to test "istep==1" twice. (GH-24064) 2021-01-02 12:09:56 -08:00
Raymond Hettinger 768fa145cf
bpo-42772: Step argument ignored when stop is None. (GH-24018) 2021-01-02 10:24:51 -08:00
Serhiy Storchaka 607501abb4
bpo-42789: Don't skip curses tests on non-tty. (GH-24009)
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.
2021-01-02 19:35:15 +02:00
Serhiy Storchaka a25011be8c
bpo-42809: Improve pickle tests for recursive data. (GH-24060) 2021-01-02 19:32:47 +02:00
Erlend Egeberg Aasland 75bf107c62
bpo-40077: Convert arraymodule to use heap types and establish module state (GH-23124) 2021-01-02 17:38:47 +01:00
Ken Jin 49cd68fb1e
bpo-42195: Disallow isinstance/issubclass for subclasses of genericaliases in Union (GH-24059)
Previously this didn't raise an error. Now it will:
```python
from collections.abc import Callable
isinstance(int, list | Callable[..., str])
```
Also added tests in Union since there were previously none for stuff like ``isinstance(list, list | list[int])`` either.

Backport to 3.9 not required.

Automerge-Triggered-By: GH:gvanrossum
2021-01-02 08:19:15 -08:00
Kurochan d9142831ba
handle empty string in variable executable in platform.libc_ver() (#23140) 2021-01-02 17:03:53 +01:00
Ken Jin 11276cd9c4
bpo-41559: Documentation for PEP 612 (GH-24000) 2021-01-01 16:45:50 -08:00
Ross 3bf05327c2
bpo-42756: Configure LMTP Unix-domain socket to use global default timeout when timeout not provided (GH-23969) 2021-01-02 02:20:25 +09:00
Dong-hee Na de6f20a6de
Bring Python into the new year. (GH-24036) 2021-01-02 00:37:23 +09:00
Dong-hee Na ec3165320e
bpo-42794: Update test_nntplib to use offical group name for testing (GH-24037) 2021-01-01 23:20:33 +09:00
Raymond Hettinger c8a7b8fa1b
bpo-42781: Document the mechanics of cached_property from a user viewpoint (GH-24031) 2020-12-31 17:05:58 -08:00
Jason R. Coombs b5711c940f
bpo-37193: Remove thread objects which finished process its request (GH-23127)
This reverts commit aca67da4fe.
2020-12-31 20:19:30 +00:00
Tao He 3631d6deab
Fixes a typo in importlib.metadata. (#23921)
Signed-off-by: Tao He <sighingnow@gmail.com>
2020-12-31 11:37:53 -08:00
Jason R. Coombs a6fd0f414c
bpo-42163, bpo-42189, bpo-42659: Support uname_tuple._replace (for all but processor) (#23010)
* 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 <storchaka@gmail.com>

* import pickle

* Fix equality test after pickling.

* Simply rely on __reduce__ for pickling.

Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
2020-12-31 14:08:03 -05:00
Jason R. Coombs dfdca85dfa
bpo-42382: In importlib.metadata, `EntryPoint` objects now expose `dist` (#23758)
* bpo-42382: In importlib.metadata, `EntryPoint` objects now expose a `.dist` object referencing the `Distribution` when constructed from a `Distribution`.

Also, sync importlib_metadata 3.3:

- Add support for package discovery under package normalization rules.
- The object returned by `metadata()` now has a formally-defined protocol called `PackageMetadata` with declared support for the `.get_all()` method.

* Add blurb

* Remove latent footnote.
2020-12-31 12:56:43 -05:00
Erlend Egeberg Aasland f4936ad1c4
bpo-42393: Raise OverflowError iso. DeprecationWarning on overflow in socket.ntohs and socket.htons (GH-23980) 2020-12-31 15:16:50 +02:00
Brandon Stansbury 9655434cca
bpo-39068: Fix race condition in base64 (GH-17627)
There was a race condition in base64 in lazy initialization of multiple globals.
2020-12-31 11:44:46 +02:00
Raymond Hettinger f421bfce80
Minor improvements to the convolve() recipe (GH-24012)
* Minor improvement to speed and space efficiency for the convolve() recipe
* Don't require convolve's kernel to be a sequence.
2020-12-30 12:51:19 -08:00
Filipe Laíns 4ac923f275
bpo-42773: fix tests not being run on pushes (GH-24004)
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 <lains@riseup.net>
2020-12-30 06:53:58 -08:00
pxinwr 277ce3060b
bpo-27640: Add --disable-test-modules configure option (GH-23886)
Added --disable-test-modules option to the configure script:
don't build nor install test modules.

Patch by Xavier de Gaye, Thomas Petazzoni and Peixing Xin.

Co-Authored-By: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
Co-Authored-By: Xavier de Gaye <xdegaye@gmail.com>
2020-12-30 13:50:39 +01:00
Yurii Karabas c56387f80c
bpo-27794: Add `name` attribute to `property` class (GH-23967) 2020-12-30 01:51:24 -08:00
Victor Stinner ba0e49a464
bpo-40137: Fix refleak in _functools_exec() (GH-24006) 2020-12-30 02:24:43 +01:00
Petr Viktorin 056c08211b
bpo-40052: Fix alignment issue in PyVectorcall_Function() (GH-23999)
```
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: Andreas Schneider <asn@cryptomilk.org>
Co-Authored-By: Antoine Pitrou <antoine@python.org>
2020-12-29 15:32:07 -08:00
Andre Delfino 2edfc86f69
bpo-41224: Add versionadded for Symbol.is_annotated (GH-23861) 2020-12-29 15:32:10 +02:00
Erlend Egeberg Aasland 84d79cfda9
bpo-40956: Convert _sqlite3.Row to Argument Clinic (GH-23964) 2020-12-29 15:22:55 +02:00
Jakub Kulík 0159e5efee
bpo-42655: Fix subprocess extra_groups gid conversion (GH-23762) 2020-12-29 14:58:27 +02:00
Hai Shi dd39123970
bpo-40137: Convert _functools module to use PyType_FromModuleAndSpec. (GH-23405) 2020-12-29 04:45:07 -08:00
Michael Wayne Goodman 84402eb110
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.
2020-12-29 14:33:15 +02:00
Jero Bado a4258e8cd7
Fix minor typo in comments in readline.c (GH-23911) 2020-12-29 14:26:57 +02:00
Senthil Kumaran 030a713183
Allow / character in username,password fields in _PROXY envvars. (#23973) 2020-12-29 04:18:42 -08:00
Ross c1af128f5a
bpo-41781: Fix typo in internal function name in typing (GH-23957) 2020-12-29 13:55:28 +02:00
Zackery Spytz 40c2c83899
Fix typo in NEWS (GH23958) 2020-12-29 13:50:22 +02:00
Serhiy Storchaka 1df56bc059
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.
2020-12-29 12:56:55 +02:00
Serhiy Storchaka 156b7f7052
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.
2020-12-29 12:55:55 +02:00
Zackery Spytz c56988b88f
bpo-42770: Fix a typo in the email.headerregistry docs (GH-23982)
Automerge-Triggered-By: GH:zware
2020-12-28 20:12:37 -08:00
Ken Jin efb1f0918f
bpo-42740: Support PEP 604, 612 for typing.py get_args and get_origin (GH-23942) 2020-12-28 18:26:19 -08:00
Pablo Galindo a6d63a20df
Fix compiler warnings regarding loss of data (GH-23983) 2020-12-29 00:28:09 +00:00
Pablo Galindo 290f5ae997
Use Py_NewRef in Modules/_struct.c (GH-23981) 2020-12-28 23:59:16 +00:00
Ken Jin 4140f10a16
bpo-42740: Fix get_args for PEP 585 collections.abc.Callable (GH-23963)
PR 1/2. Needs backport to 3.9.
2020-12-28 12:06:19 -08:00
Raymond Hettinger a9621bb301
bpo-42222: Modernize integer test/conversion in randrange() (#23064) 2020-12-28 11:10:34 -08:00
Ammar Askar 1031f23fc3
[workflow] Use MSVC problem matcher for Windows action build (GH-18532)
This makes warnings and errors from the compiler very prominent so this should help prevent warnings from sneaking into the code base and catch them in review. See https://discuss.python.org/t/using-github-problem-matchers-to-catch-warnings-early/4254 for more details

You can see a demo of this in action here: https://github.com/ammaraskar/cpython/pull/15/files#diff-9ba2eeca0f254ece0a9df4d7cb68e870

GCC and Sphinx matchers have previously been added in GH-18567 and GH-20325, respectively.
2020-12-28 12:28:40 -06:00
Erlend Egeberg Aasland bf108bb21e
bpo-40077: Fix typo in simplequeue_get_state_by_type() (GH-23975)
The typo did no damage, but it looks suspicious and confusing.
Introduced by GH-23136.

Skip news.

Automerge-Triggered-By: GH:pitrou
2020-12-28 09:47:16 -08:00
Erlend Egeberg Aasland 897387d2c8
bpo-1635741: sqlite3: Fix ref leak introduced by commit bf64d90 (GH-23972) 2020-12-28 03:09:26 +01:00
Erlend Egeberg Aasland abba83b4b9
bpo-42755: Fix sqlite3.Connection.backup docs (GH-23965)
The `pages` argument default value now reflects the implementation.
2020-12-27 22:35:17 +00:00
Erlend Egeberg Aasland bf64d9064a
bpo-1635741: sqlite3 uses Py_NewRef/Py_XNewRef (GH-23170) 2020-12-27 12:05:33 +01:00
Erlend Egeberg Aasland 3ccef1ca47
bpo-40956: Convert _sqlite3.Connection to Argument Clinic, part 2 (GH-23838) 2020-12-27 17:32:18 +09:00
Serhiy Storchaka b02ad2458b
bpo-42749: Fix testing bignum if Tkinter is compiled with Tk 8.4 and dynamic linked with Tk >= 8.5 (GH-23955) 2020-12-27 10:13:30 +02:00
Victor Stinner f4507231e3
bpo-42745: finalize_interp_types() calls _PyType_Fini() (GH-23953)
Call _PyType_Fini() in subinterpreters.

Fix reference leaks in subinterpreters.
2020-12-26 20:26:08 +01:00
Pablo Galindo 3bcc4ead3f
Add small validator utility for PEG grammars (GH-23519) 2020-12-26 19:11:29 +00:00
Shantanu 7865f516f3
bpo-16396: fix BPO number in changelog (GH-23951)
Automerge-Triggered-By: GH:jaraco
2020-12-26 07:36:56 -08:00
Dong-hee Na 0b281f94b9
bpo-42748: test_asdl_parser now uses exec_module instead of load_module (#23954) 2020-12-26 16:25:21 +03:00
Victor Stinner ea251806b8
bpo-40521: Per-interpreter interned strings (GH-20085)
Make the Unicode dictionary of interned strings compatible with
subinterpreters.

Remove the INTERN_NAME_STRINGS macro in typeobject.c: names are
always now interned (even if EXPERIMENTAL_ISOLATED_SUBINTERPRETERS
macro is defined).

_PyUnicode_ClearInterned() now uses PyDict_Next() to no longer
allocate memory, to ensure that the interned dictionary is cleared.
2020-12-26 02:58:33 +01:00
Victor Stinner 993e88cf08
bpo-42694: Prevent creating _curses_panel.panel (GH-23948)
Fix regression introduced in
commit 1baf030a902392fe92d934ed0fb6a385cf7d8869: restore removed code
to prevent creating a _curses_panel.panel instance directly.
2020-12-26 02:17:46 +01:00
Victor Stinner 4101018488
bpo-42745: Make the type cache per-interpreter (GH-23947)
Make the type attribute lookup cache per-interpreter.

Add private _PyType_InitCache() function, called by PyInterpreterState_New().

Continue to share next_version_tag between interpreters, since static
types are still shared by interpreters.

Remove MCACHE macro: the cache is no longer disabled if the
EXPERIMENTAL_ISOLATED_SUBINTERPRETERS macro is defined.
2020-12-26 01:45:43 +01:00
Raymond Hettinger 77fde8dc16
Add convolve() to the itertools recipes (GH-23928) 2020-12-25 16:43:20 -08:00
Victor Stinner ba3d67c2fb
bpo-39465: Fix _PyUnicode_FromId() for subinterpreters (GH-20058)
Make _PyUnicode_FromId() function compatible with subinterpreters.
Each interpreter now has an array of identifier objects (interned
strings decoded from UTF-8).

* Add PyInterpreterState.unicode.identifiers: array of identifiers
  objects.
* Add _PyRuntimeState.unicode_ids used to allocate unique indexes
  to _Py_Identifier.
* Rewrite the _Py_Identifier structure.

Microbenchmark on _PyUnicode_FromId(&PyId_a) with _Py_IDENTIFIER(a):

[ref] 2.42 ns +- 0.00 ns -> [atomic] 3.39 ns +- 0.00 ns: 1.40x slower

This change adds 1 ns per _PyUnicode_FromId() call in average.
2020-12-26 00:41:46 +01:00
Ken Jin f0853bcedf
Sync what's new in 3.9 with 3.9 branch (GH-23943) 2020-12-25 23:08:17 +00:00
Eric Snow 5ae9be68d9
bpo-36876: [c-analyzer tool] Additional CLI updates for "capi" command. (gh-23929)
https://bugs.python.org/issue36876
2020-12-25 15:57:30 -07:00
Serhiy Storchaka c1ae21c965
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.
2020-12-26 00:10:29 +02:00
Desmond Cheong 36a779e64c
bpo-35728: Add root parameter to tkinter.font.nametofont() (GH-23885) 2020-12-25 23:18:06 +02:00
Serhiy Storchaka 675c97eb6c
bpo-42721: Improve using simple dialogs without root window (GH-23897)
When simple query dialogs (tkinter.simpledialog), message boxes
(tkinter.messagebox) or color choose dialog (tkinter.colorchooser)
are created without arguments master and parent, and the default
root window is not yet created, a new temporary hidden root window
will be created automatically. It will not be set as the default root
window and will be destroyed right after closing the dialog window.
It will help to use these simple dialog windows in programs which do
not need other GUI.

Previously, message boxes and color chooser created the blank root
window and left it after closing the dialog window, and query dialogs
just raised an exception.

Co-authored-by: Terry Jan Reedy <tjreedy@udel.edu>
2020-12-25 20:19:20 +02:00
Irit Katriel 586f3dbe15
bpo-28964: add line number of node (if available) to ast.literal_eval error messages (GH-23677) 2020-12-25 20:04:31 +03:00
Serhiy Storchaka bb70b2afe3
bpo-15303: Support widgets with boolean value False in Tkinter (GH-23904)
Use `widget is None` instead of checking the boolean value of a widget.
2020-12-25 17:04:26 +02:00
Serhiy Storchaka 954a7427ba
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).
2020-12-25 17:03:37 +02:00
Erlend Egeberg Aasland 7f162e867c
bpo-29076: Add fish support to macOS installer (GH-23302) 2020-12-25 03:01:30 -08:00
Gregory P. Smith 64abf37344
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 <izbyshev@ispras.ru>
2020-12-24 20:57:21 -08:00
Gregory P. Smith 8badadec53
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
```
2020-12-24 20:31:18 -08:00
Ethan Furman 786d97a66c
bpo-42727: [Enum] use super() and include **kwds (GH-23927)
for multiple inheritance support:

use super().new
pass **kwds to super().new
2020-12-24 19:31:10 -08:00
Serhiy Storchaka c6c43b2874
bpo-42685: Improve placing of simple query windows. (GH-23856)
* If parent is specified and mapped, the query widget is
  centered at the center of parent. Its position and size
  can be corrected so that it fits in the virtual root window.
* Otherwise it is centered at the center of the screen.
2020-12-24 20:26:28 +02:00
221 changed files with 9064 additions and 5475 deletions

19
.github/problem-matchers/msvc.json vendored Normal file
View File

@ -0,0 +1,19 @@
{
"__comment": "Taken from vscode's vs/workbench/contrib/tasks/common/problemMatcher.ts msCompile rule",
"problemMatcher": [
{
"owner": "msvc-problem-matcher",
"pattern": [
{
"regexp": "^(?:\\s+\\d+\\>)?([^\\s].*)\\((\\d+),?(\\d+)?(?:,\\d+,\\d+)?\\)\\s*:\\s+(error|warning|info)\\s+(\\w{1,2}\\d+)\\s*:\\s*(.*)$",
"file": 1,
"line": 2,
"column": 3,
"severity": 4,
"code": 5,
"message": 6
}
]
}
]
}

View File

@ -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
@ -99,6 +99,8 @@ jobs:
if: needs.check_source.outputs.run_tests == 'true'
steps:
- uses: actions/checkout@v2
- name: Register MSVC problem matcher
run: echo "::add-matcher::.github/problem-matchers/msvc.json"
- name: Build CPython
run: .\PCbuild\build.bat -e -p x64
- name: Display build info

View File

@ -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.

View File

@ -934,32 +934,42 @@ here is a pure Python equivalent:
if doc is None and fget is not None:
doc = fget.__doc__
self.__doc__ = doc
self._name = ''
def __set_name__(self, owner, name):
self._name = name
def __get__(self, obj, objtype=None):
if obj is None:
return self
if self.fget is None:
raise AttributeError("unreadable attribute")
raise AttributeError(f'unreadable attribute {self._name}')
return self.fget(obj)
def __set__(self, obj, value):
if self.fset is None:
raise AttributeError("can't set attribute")
raise AttributeError(f"can't set attribute {self._name}")
self.fset(obj, value)
def __delete__(self, obj):
if self.fdel is None:
raise AttributeError("can't delete attribute")
raise AttributeError(f"can't delete attribute {self._name}")
self.fdel(obj)
def getter(self, fget):
return type(self)(fget, self.fset, self.fdel, self.__doc__)
prop = type(self)(fget, self.fset, self.fdel, self.__doc__)
prop._name = self._name
return prop
def setter(self, fset):
return type(self)(self.fget, fset, self.fdel, self.__doc__)
prop = type(self)(self.fget, fset, self.fdel, self.__doc__)
prop._name = self._name
return prop
def deleter(self, fdel):
return type(self)(self.fget, self.fset, fdel, self.__doc__)
prop = type(self)(self.fget, self.fset, fdel, self.__doc__)
prop._name = self._name
return prop
.. testcode::
:hide:

View File

@ -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.
@ -287,7 +288,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``.
@ -300,7 +301,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.
@ -450,7 +452,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)

View File

@ -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.

View File

@ -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

View File

@ -115,8 +115,9 @@ Every distribution includes some metadata, which you can extract using the
>>> wheel_metadata = metadata('wheel') # doctest: +SKIP
The keys of the returned data structure [#f1]_ name the metadata keywords, and
their values are returned unparsed from the distribution metadata::
The keys of the returned data structure, a ``PackageMetadata``,
name the metadata keywords, and
the values are returned unparsed from the distribution metadata::
>>> wheel_metadata['Requires-Python'] # doctest: +SKIP
'>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*'
@ -206,9 +207,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`
@ -259,9 +260,3 @@ a custom finder, return instances of this derived ``Distribution`` in the
.. rubric:: Footnotes
.. [#f1] Technically, the returned distribution metadata object is an
:class:`email.message.EmailMessage`
instance, but this is an implementation detail, and not part of the
stable API. You should only use dictionary-like methods and syntax
to access the metadata contents.

View File

@ -786,6 +786,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 = tuple(kernel)[::-1]
n = len(kernel)
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))
def flatten(list_of_lists):
"Flatten one level of nesting"
return chain.from_iterable(list_of_lists)

View File

@ -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

View File

@ -135,6 +135,15 @@ Functions for integers
values. Formerly it used a style like ``int(random()*n)`` which could produce
slightly uneven distributions.
.. deprecated:: 3.10
The automatic conversion of non-integer types to equivalent integers is
deprecated. Currently ``randrange(10.0)`` is losslessly converted to
``randrange(10)``. In the future, this will raise a :exc:`TypeError`.
.. deprecated:: 3.10
The exception raised for non-integral values such as ``range(10.5)``
will be changed from :exc:`ValueError` to :exc:`TypeError`.
.. function:: randint(a, b)
Return a random integer *N* such that ``a <= N <= b``. Alias for

View File

@ -907,11 +907,9 @@ The :mod:`socket` module also offers various network-related services:
where the host byte order is the same as network byte order, this is a no-op;
otherwise, it performs a 2-byte swap operation.
.. deprecated:: 3.7
In case *x* does not fit in 16-bit unsigned integer, but does fit in a
positive C int, it is silently truncated to 16-bit unsigned integer.
This silent truncation feature is deprecated, and will raise an
exception in future versions of Python.
.. versionchanged:: 3.10
Raises :exc:`OverflowError` if *x* does not fit in a 16-bit unsigned
integer.
.. function:: htonl(x)
@ -927,11 +925,9 @@ The :mod:`socket` module also offers various network-related services:
where the host byte order is the same as network byte order, this is a no-op;
otherwise, it performs a 2-byte swap operation.
.. deprecated:: 3.7
In case *x* does not fit in 16-bit unsigned integer, but does fit in a
positive C int, it is silently truncated to 16-bit unsigned integer.
This silent truncation feature is deprecated, and will raise an
exception in future versions of Python.
.. versionchanged:: 3.10
Raises :exc:`OverflowError` if *x* does not fit in a 16-bit unsigned
integer.
.. function:: inet_aton(ip_string)

View File

@ -546,7 +546,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

View File

@ -198,7 +198,7 @@ However, for reading convenience, most of the examples show sorted sequences.
.. versionadded:: 3.6
.. versionchanged:: 3.8
.. versionchanged:: 3.10
Added support for *weights*.
.. function:: median(data)

View File

@ -4959,6 +4959,11 @@ All parameterized generics implement special read-only attributes.
(~T,)
.. note::
A ``GenericAlias`` object with :class:`typing.ParamSpec` parameters may not
have correct ``__parameters__`` after substitution because
:class:`typing.ParamSpec` is intended primarily for static type checking.
.. seealso::
* :pep:`585` -- "Type Hinting Generics In Standard Collections"

View File

@ -1187,8 +1187,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

View File

@ -160,6 +160,8 @@ Examining Symbol Tables
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

View File

@ -91,6 +91,9 @@ The different font weights and slants are:
Return the names of defined fonts.
.. function:: nametofont(name)
.. function:: nametofont(name, root=None)
Return a :class:`Font` representation of a tk named font.
Return a :class:`Font` representation of a tk named font.
.. versionchanged:: 3.10
The *root* parameter was added.

View File

@ -18,7 +18,8 @@
--------------
This module provides runtime support for type hints as specified by
:pep:`484`, :pep:`526`, :pep:`544`, :pep:`586`, :pep:`589`, :pep:`591`, and :pep:`613`.
:pep:`484`, :pep:`526`, :pep:`544`, :pep:`586`, :pep:`589`, :pep:`591`,
:pep:`612` and :pep:`613`.
The most fundamental support consists of the types :data:`Any`, :data:`Union`,
:data:`Tuple`, :data:`Callable`, :class:`TypeVar`, and
:class:`Generic`. For full specification please see :pep:`484`. For
@ -171,6 +172,22 @@ It is possible to declare the return type of a callable without specifying
the call signature by substituting a literal ellipsis
for the list of arguments in the type hint: ``Callable[..., ReturnType]``.
Callables which take other callables as arguments may indicate that their
parameter types are dependent on each other using :class:`ParamSpec`.
Additionally, if that callable adds or removes arguments from other
callables, the :data:`Concatenate` operator may be used. They
take the form ``Callable[ParamSpecVariable, ReturnType]`` and
``Callable[Concatenate[Arg1Type, Arg2Type, ..., ParamSpecVariable], ReturnType]``
respectively.
.. versionchanged:: 3.10
``Callable`` now supports :class:`ParamSpec` and :data:`Concatenate`.
See :pep:`612` for more information.
.. seealso::
The documentation for :class:`ParamSpec` and :class:`Concatenate` provide
examples of usage in ``Callable``.
.. _generics:
Generics
@ -316,6 +333,43 @@ User defined generic type aliases are also supported. Examples::
.. versionchanged:: 3.7
:class:`Generic` no longer has a custom metaclass.
User-defined generics for parameter expressions are also supported via parameter
specification variables in the form ``Generic[P]``. The behavior is consistent
with type variables' described above as parameter specification variables are
treated by the typing module as a specialized type variable. The one exception
to this is that a list of types can be used to substitute a :class:`ParamSpec`::
>>> from typing import Generic, ParamSpec, TypeVar
>>> T = TypeVar('T')
>>> P = ParamSpec('P')
>>> class Z(Generic[T, P]): ...
...
>>> Z[int, [dict, float]]
__main__.Z[int, (<class 'dict'>, <class 'float'>)]
Furthermore, a generic with only one parameter specification variable will accept
parameter lists in the forms ``X[[Type1, Type2, ...]]`` and also
``X[Type1, Type2, ...]`` for aesthetic reasons. Internally, the latter is converted
to the former and are thus equivalent::
>>> class X(Generic[P]): ...
...
>>> X[int, str]
__main__.X[(<class 'int'>, <class 'str'>)]
>>> X[[int, str]]
__main__.X[(<class 'int'>, <class 'str'>)]
Do note that generics with :class:`ParamSpec` may not have correct
``__parameters__`` after substitution in some cases because they
are intended primarily for static type checking.
.. versionchanged:: 3.10
:class:`Generic` can now be parameterized over parameter expressions.
See :class:`ParamSpec` and :pep:`612` for more details.
A user-defined generic class can have ABCs as base classes without a metaclass
conflict. Generic metaclasses are not supported. The outcome of parameterizing
generics is cached, and most types in the typing module are hashable and
@ -602,10 +656,80 @@ These can be used as types in annotations using ``[]``, each having a unique syn
``Callable[..., Any]``, and in turn to
:class:`collections.abc.Callable`.
Callables which take other callables as arguments may indicate that their
parameter types are dependent on each other using :class:`ParamSpec`.
Additionally, if that callable adds or removes arguments from other
callables, the :data:`Concatenate` operator may be used. They
take the form ``Callable[ParamSpecVariable, ReturnType]`` and
``Callable[Concatenate[Arg1Type, Arg2Type, ..., ParamSpecVariable], ReturnType]``
respectively.
.. deprecated:: 3.9
:class:`collections.abc.Callable` now supports ``[]``. See :pep:`585` and
:ref:`types-genericalias`.
.. versionchanged:: 3.10
``Callable`` now supports :class:`ParamSpec` and :data:`Concatenate`.
See :pep:`612` for more information.
.. seealso::
The documentation for :class:`ParamSpec` and :class:`Concatenate` provide
examples of usage with ``Callable``.
.. data:: Concatenate
Used with :data:`Callable` and :class:`ParamSpec` to type annotate a higher
order callable which adds, removes, or transforms parameters of another
callable. Usage is in the form
``Concatenate[Arg1Type, Arg2Type, ..., ParamSpecVariable]``. ``Concatenate``
is currently only valid when used as the first argument to a :data:`Callable`.
The last parameter to ``Concatenate`` must be a :class:`ParamSpec`.
For example, to annotate a decorator ``with_lock`` which provides a
:class:`threading.Lock` to the decorated function, ``Concatenate`` can be
used to indicate that ``with_lock`` expects a callable which takes in a
``Lock`` as the first argument, and returns a callable with a different type
signature. In this case, the :class:`ParamSpec` indicates that the returned
callable's parameter types are dependent on the parameter types of the
callable being passed in::
from collections.abc import Callable
from threading import Lock
from typing import Any, Concatenate, ParamSpec
P = ParamSpec('P')
R = ParamSpec('R')
# Use this lock to ensure that only one thread is executing a function
# at any time.
my_lock = Lock()
def with_lock(f: Callable[Concatenate[Lock, P], R]) -> Callable[P, R]:
'''A type-safe decorator which provides a lock.'''
global my_lock
def inner(*args: P.args, **kwargs: P.kwargs) -> T:
# Provide the lock as the first argument.
return f(my_lock, *args, **kwargs)
return inner
@with_lock
def sum_threadsafe(lock: Lock, numbers: list[float]) -> float:
'''Add a list of numbers together in a thread-safe manner.'''
with lock:
return sum(numbers)
# We don't need to pass in the lock ourselves thanks to the decorator.
sum_threadsafe([1.1, 2.2, 3.3])
.. versionadded:: 3.10
.. seealso::
* :pep:`612` -- Parameter Specification Variables (the PEP which introduced
``ParamSpec`` and ``Concatenate``).
* :class:`ParamSpec` and :class:`Callable`.
.. class:: Type(Generic[CT_co])
A variable annotated with ``C`` may accept a value of type ``C``. In
@ -876,6 +1000,84 @@ These are not used in annotations. They are building blocks for creating generic
for the type variable must be a subclass of the boundary type,
see :pep:`484`.
.. class:: ParamSpec(name, *, bound=None, covariant=False, contravariant=False)
Parameter specification variable. A specialized version of
:class:`type variables <TypeVar>`.
Usage::
P = ParamSpec('P')
Parameter specification variables exist primarily for the benefit of static
type checkers. They are used to forward the parameter types of one
callable to another callable -- a pattern commonly found in higher order
functions and decorators. They are only valid when used in ``Concatenate``,
or as the first argument to ``Callable``, or as parameters for user-defined
Generics. See :class:`Generic` for more information on generic types.
For example, to add basic logging to a function, one can create a decorator
``add_logging`` to log function calls. The parameter specification variable
tells the type checker that the callable passed into the decorator and the
new callable returned by it have inter-dependent type parameters::
from collections.abc import Callable
from typing import TypeVar, ParamSpec
import logging
T = TypeVar('T')
P = ParamSpec('P')
def add_logging(f: Callable[P, T]) -> Callable[P, T]:
'''A type-safe decorator to add logging to a function.'''
def inner(*args: P.args, **kwargs: P.kwargs) -> T:
logging.info(f'{f.__name__} was called')
return f(*args, **kwargs)
return inner
@add_logging
def add_two(x: float, y: float) -> float:
'''Add two numbers together.'''
return x + y
Without ``ParamSpec``, the simplest way to annotate this previously was to
use a :class:`TypeVar` with bound ``Callable[..., Any]``. However this
causes two problems:
1. The type checker can't type check the ``inner`` function because
``*args`` and ``**kwargs`` have to be typed :data:`Any`.
2. :func:`~cast` may be required in the body of the ``add_logging``
decorator when returning the ``inner`` function, or the static type
checker must be told to ignore the ``return inner``.
.. attribute:: args
.. attribute:: kwargs
Since ``ParamSpec`` captures both positional and keyword parameters,
``P.args`` and ``P.kwargs`` can be used to split a ``ParamSpec`` into its
components. ``P.args`` represents the tuple of positional parameters in a
given call and should only be used to annotate ``*args``. ``P.kwargs``
represents the mapping of keyword parameters to their values in a given call,
and should be only be used to annotate ``**kwargs`` or ``**kwds``. Both
attributes require the annotated parameter to be in scope.
Parameter specification variables created with ``covariant=True`` or
``contravariant=True`` can be used to declare covariant or contravariant
generic types. The ``bound`` argument is also accepted, similar to
:class:`TypeVar`. However the actual semantics of these keywords are yet to
be decided.
.. versionadded:: 3.10
.. note::
Only parameter specification variables defined in global scope can
be pickled.
.. seealso::
* :pep:`612` -- Parameter Specification Variables (the PEP which introduced
``ParamSpec`` and ``Concatenate``).
* :class:`Callable` and :class:`Concatenate`.
.. data:: AnyStr
``AnyStr`` is a type variable defined as

View File

@ -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.

View File

@ -168,6 +168,7 @@ library/ipaddress,,::,2001:db00::0/24
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,,::,kernel = tuple(kernel)[::-1]
library/itertools,,:stop,elements from seq[start:stop:step]
library/logging.handlers,,:port,host:port
library/mmap,,:i2,obj[i1:i2]

1 c-api/arg :ref PyArg_ParseTuple(args, "O|O:ref", &object, &callback)
168 library/ipaddress :db00 2001:db00::0/ffff:ff00::
169 library/ipaddress :: 2001:db00::0/ffff:ff00::
170 library/itertools :step elements from seq[start:stop:step]
171 library/itertools :: kernel = tuple(kernel)[::-1]
172 library/itertools :stop elements from seq[start:stop:step]
173 library/logging.handlers :port host:port
174 library/mmap :i2 obj[i1:i2]

View File

@ -144,6 +144,28 @@ See :pep:`604` for more details.
(Contributed by Maggie Moss and Philippe Prados in :issue:`41428`.)
PEP 612: Parameter Specification Variables
------------------------------------------
Two new options to improve the information provided to static type checkers for
:pep:`484`\ 's ``Callable`` have been added to the :mod:`typing` module.
The first is the parameter specification variable. They are used to forward the
parameter types of one callable to another callable -- a pattern commonly
found in higher order functions and decorators. Examples of usage can be found
in :class:`typing.ParamSpec`. Previously, there was no easy way to type annotate
dependency of parameter types in such a precise manner.
The second option is the new ``Concatenate`` operator. It's used in conjunction
with parameter specification variables to type annotate a higher order callable
which adds or removes parameters of another callable. Examples of usage can
be found in :class:`typing.Concatenate`.
See :class:`typing.Callable`, :class:`typing.ParamSpec`,
:class:`typing.Concatenate` and :pep:`612` for more details.
(Contributed by Ken Jin in :issue:`41559`.)
Other Language Changes
======================
@ -404,9 +426,11 @@ Optimizations
average.
(Contributed by Victor Stinner in :issue:`41006`.)
* The ``LOAD_ATTR`` instruction now uses new "per opcode cache" mechanism.
It is about 36% faster now. (Contributed by Pablo Galindo and Yury Selivanov
in :issue:`42093`, based on ideas implemented originally in PyPy and MicroPython.)
* The ``LOAD_ATTR`` instruction now uses new "per opcode cache" mechanism. It
is about 36% faster now. This makes optimized ``LOAD_ATTR`` instructions the
current most performance attribute access method (faster than slots).
(Contributed by Pablo Galindo and Yury Selivanov in :issue:`42093`, based on
ideas implemented originally in PyPy and MicroPython.)
* When building Python with ``--enable-optimizations`` now
``-fno-semantic-interposition`` is added to both the compile and link line.
@ -537,6 +561,12 @@ Changes in the Python API
silently in Python 3.9.
(Contributed by Ken Jin in :issue:`42195`.)
* :meth:`socket.htons` and :meth:`socket.ntohs` now raise :exc:`OverflowError`
instead of :exc:`DeprecationWarning` if the given parameter will not fit in
a 16-bit unsigned integer.
(Contributed by Erlend E. Aasland in :issue:`42393`.)
CPython bytecode changes
========================
@ -558,6 +588,10 @@ Build Changes
* The :mod:`atexit` module must now always be built as a built-in module.
(Contributed by Victor Stinner in :issue:`42639`.)
* Added ``--disable-test-modules`` option to the ``configure`` script:
don't build nor install test modules.
(Contributed by Xavier de Gaye, Thomas Petazzoni and Peixing Xin in :issue:`27640`.)
C API Changes
=============

View File

@ -1482,4 +1482,37 @@ and to match the behavior of static type checkers specified in the PEP.
File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'set'
(Contributed by Yurii Karabas in :issue:`42345`.)
(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`.)
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`.)

View File

@ -580,18 +580,23 @@ star_targets[expr_ty]:
| a=star_target !',' { a }
| a=star_target b=(',' c=star_target { c })* [','] {
_Py_Tuple(CHECK(asdl_expr_seq*, _PyPegen_seq_insert_in_front(p, a, b)), Store, EXTRA) }
star_targets_seq[asdl_expr_seq*]: a[asdl_expr_seq*]=','.star_target+ [','] { a }
star_targets_list_seq[asdl_expr_seq*]: a[asdl_expr_seq*]=','.star_target+ [','] { a }
star_targets_tuple_seq[asdl_expr_seq*]:
| a=star_target b=(',' c=star_target { c })+ [','] { (asdl_expr_seq*) _PyPegen_seq_insert_in_front(p, a, b) }
| a=star_target ',' { (asdl_expr_seq*) _PyPegen_singleton_seq(p, a) }
star_target[expr_ty] (memo):
| '*' a=(!'*' star_target) {
_Py_Starred(CHECK(expr_ty, _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

View File

@ -63,7 +63,7 @@ PyVectorcall_Function(PyObject *callable)
{
PyTypeObject *tp;
Py_ssize_t offset;
vectorcallfunc *ptr;
vectorcallfunc ptr;
assert(callable != NULL);
tp = Py_TYPE(callable);
@ -73,8 +73,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

View File

@ -35,12 +35,13 @@ PyAPI_FUNC(Py_ssize_t) _Py_GetRefTotal(void);
_PyObject_{Get,Set,Has}AttrId are __getattr__ versions using _Py_Identifier*.
*/
typedef struct _Py_Identifier {
struct _Py_Identifier *next;
const char* string;
PyObject *object;
// Index in PyInterpreterState.unicode.ids.array. It is process-wide
// unique and must be initialized to -1.
Py_ssize_t index;
} _Py_Identifier;
#define _Py_static_string_init(value) { .next = NULL, .string = value, .object = NULL }
#define _Py_static_string_init(value) { .string = value, .index = -1 }
#define _Py_static_string(varname, value) static _Py_Identifier varname = _Py_static_string_init(value)
#define _Py_IDENTIFIER(varname) _Py_static_string(PyId_##varname, #varname)

View File

@ -64,6 +64,11 @@ struct _Py_bytes_state {
PyBytesObject *characters[256];
};
struct _Py_unicode_ids {
Py_ssize_t size;
PyObject **array;
};
struct _Py_unicode_state {
// The empty Unicode object is a singleton to improve performance.
PyObject *empty_string;
@ -71,6 +76,19 @@ struct _Py_unicode_state {
shared as well. */
PyObject *latin1[256];
struct _Py_unicode_fs_codec fs_codec;
/* This dictionary holds all interned unicode strings. Note that references
to strings in this dictionary are *not* counted in the string's ob_refcnt.
When the interned string reaches a refcnt of 0 the string deallocation
function will delete the reference from this dictionary.
Another way to look at this is that to say that the actual reference
count of a string is: s->ob_refcnt + (s->state ? 2 : 0)
*/
PyObject *interned;
// Unicode identifiers (_Py_Identifier): see _PyUnicode_FromId()
struct _Py_unicode_ids ids;
};
struct _Py_float_state {
@ -173,6 +191,27 @@ struct atexit_state {
};
// Type attribute lookup cache: speed up attribute and method lookups,
// see _PyType_Lookup().
struct type_cache_entry {
unsigned int version; // initialized from type->tp_version_tag
PyObject *name; // reference to exactly a str or None
PyObject *value; // borrowed reference or NULL
};
#define MCACHE_SIZE_EXP 12
#define MCACHE_STATS 0
struct type_cache {
struct type_cache_entry hashtable[1 << MCACHE_SIZE_EXP];
#if MCACHE_STATS
size_t hits;
size_t misses;
size_t collisions;
#endif
};
/* interpreter state */
#define _PY_NSMALLPOSINTS 257
@ -277,6 +316,7 @@ struct _is {
struct _Py_exc_state exc_state;
struct ast_state ast;
struct type_cache type_cache;
};
extern void _PyInterpreterState_ClearModules(PyInterpreterState *interp);

View File

@ -27,6 +27,9 @@ _PyType_HasFeature(PyTypeObject *type, unsigned long feature) {
return ((type->tp_flags & feature) != 0);
}
extern void _PyType_InitCache(PyInterpreterState *interp);
/* Inline functions trading binary compatibility for speed:
_PyObject_Init() is the fast version of PyObject_Init(), and
_PyObject_InitVar() is the fast version of PyObject_InitVar().

View File

@ -76,7 +76,7 @@ extern void _PyExc_Fini(PyThreadState *tstate);
extern void _PyImport_Fini(void);
extern void _PyImport_Fini2(void);
extern void _PyGC_Fini(PyThreadState *tstate);
extern void _PyType_Fini(void);
extern void _PyType_Fini(PyThreadState *tstate);
extern void _Py_HashRandomization_Fini(void);
extern void _PyUnicode_Fini(PyThreadState *tstate);
extern void _PyUnicode_ClearInterned(PyThreadState *tstate);

View File

@ -49,6 +49,11 @@ typedef struct _Py_AuditHookEntry {
void *userData;
} _Py_AuditHookEntry;
struct _Py_unicode_runtime_ids {
PyThread_type_lock lock;
Py_ssize_t next_index;
};
/* Full Python runtime state */
typedef struct pyruntimestate {
@ -106,6 +111,8 @@ typedef struct pyruntimestate {
void *open_code_userdata;
_Py_AuditHookEntry *audit_hook_head;
struct _Py_unicode_runtime_ids unicode_ids;
// XXX Consolidate globals found via the check-c-globals script.
} _PyRuntimeState;

View File

@ -20,10 +20,10 @@
#define PY_MINOR_VERSION 10
#define PY_MICRO_VERSION 0
#define PY_RELEASE_LEVEL PY_RELEASE_LEVEL_ALPHA
#define PY_RELEASE_SERIAL 3
#define PY_RELEASE_SERIAL 4
/* Version as a string */
#define PY_VERSION "3.10.0a3+"
#define PY_VERSION "3.10.0a4+"
/*--end constants--*/
/* Version as a single 4-byte hex number, e.g. 0x010502B2 == 1.5.2b2.

View File

@ -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.

View File

@ -63,7 +63,10 @@ def literal_eval(node_or_string):
if isinstance(node_or_string, Expression):
node_or_string = node_or_string.body
def _raise_malformed_node(node):
raise ValueError(f'malformed node or string: {node!r}')
msg = "malformed node or string"
if lno := getattr(node, 'lineno', None):
msg += f' on line {lno}'
raise ValueError(msg + f': {node!r}')
def _convert_num(node):
if not isinstance(node, Constant) or type(node.value) not in (int, float, complex):
_raise_malformed_node(node)

View File

@ -344,7 +344,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]
@ -452,7 +452,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)

View File

@ -178,7 +178,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
@ -235,10 +235,10 @@ class EnumMeta(type):
# 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:

View File

@ -3,6 +3,9 @@ Released on 2021-10-04?
======================================
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.

View File

@ -2316,7 +2316,15 @@ display when Code Context is turned on for an editor window.
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.
''',
}

View File

@ -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. <<zoom-height>>, and
corresponding methods, e.g. zoom_height_event(). The virtual events will be
Rather, it must define one or more virtual events, e.g. <<z-in>>, 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', '<<zoom-height>>'),
])
('format', [
('Z in', '<<z-in>>'),
('Z out', '<<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

View File

@ -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)

View File

@ -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
ztext = idleConf.GetOption('extensions', 'ZzDummy', 'z-text')
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'
return apply
class ZzDummy:
"""Prepend or remove initial text from selected lines."""
## menudefs = [
## ('format', [
## ('Z in', '<<z-in>>'),
## ('Z out', '<<z-out>>'),
## ] )
## ]
# Extend the format menu.
menudefs = [
('format', [
('Z in', '<<z-in>>'),
('Z out', '<<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):
"""
"""
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"
@format_selection
def z_in_event(self, line):
"""Insert text at the beginning of each selected line.
This is bound to the <<z-in>> 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 <<z-out>> virtual event when the extensions
are loaded.
"""
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)

View File

@ -1,4 +1,3 @@
import io
import os
import re
import abc
@ -18,6 +17,7 @@ from contextlib import suppress
from importlib import import_module
from importlib.abc import MetaPathFinder
from itertools import starmap
from typing import Any, List, Optional, Protocol, TypeVar, Union
__all__ = [
@ -31,7 +31,7 @@ __all__ = [
'metadata',
'requires',
'version',
]
]
class PackageNotFoundError(ModuleNotFoundError):
@ -43,7 +43,7 @@ class PackageNotFoundError(ModuleNotFoundError):
@property
def name(self):
name, = self.args
(name,) = self.args
return name
@ -60,7 +60,7 @@ class EntryPoint(
r'(?P<module>[\w.]+)\s*'
r'(:\s*(?P<attr>[\w.]+))?\s*'
r'(?P<extras>\[.*\])?\s*$'
)
)
"""
A regular expression describing the syntax for an entry point,
which might look like:
@ -77,6 +77,8 @@ class EntryPoint(
following the attr, and following any extras.
"""
dist: Optional['Distribution'] = None
def load(self):
"""Load the entry point from its definition. If only a module
is indicated by the value, return that module. Otherwise,
@ -104,23 +106,27 @@ class EntryPoint(
@classmethod
def _from_config(cls, config):
return [
return (
cls(name, value, group)
for group in config.sections()
for name, value in config.items(group)
]
)
@classmethod
def _from_text(cls, text):
config = ConfigParser(delimiters='=')
# case sensitive: https://stackoverflow.com/q/1611799/812183
config.optionxform = str
try:
config.read_string(text)
except AttributeError: # pragma: nocover
# Python 2 has no read_string
config.readfp(io.StringIO(text))
return EntryPoint._from_config(config)
config.read_string(text)
return cls._from_config(config)
@classmethod
def _from_text_for(cls, text, dist):
return (ep._for(dist) for ep in cls._from_text(text))
def _for(self, dist):
self.dist = dist
return self
def __iter__(self):
"""
@ -132,7 +138,7 @@ class EntryPoint(
return (
self.__class__,
(self.name, self.value, self.group),
)
)
class PackagePath(pathlib.PurePosixPath):
@ -159,6 +165,25 @@ class FileHash:
return '<FileHash mode: {} value: {}>'.format(self.mode, self.value)
_T = TypeVar("_T")
class PackageMetadata(Protocol):
def __len__(self) -> int:
... # pragma: no cover
def __contains__(self, item: str) -> bool:
... # pragma: no cover
def __getitem__(self, key: str) -> str:
... # pragma: no cover
def get_all(self, name: str, failobj: _T = ...) -> Union[List[Any], _T]:
"""
Return all values associated with a possibly multi-valued key.
"""
class Distribution:
"""A Python distribution package."""
@ -210,9 +235,8 @@ class Distribution:
raise ValueError("cannot accept context and kwargs")
context = context or DistributionFinder.Context(**kwargs)
return itertools.chain.from_iterable(
resolver(context)
for resolver in cls._discover_resolvers()
)
resolver(context) for resolver in cls._discover_resolvers()
)
@staticmethod
def at(path):
@ -227,24 +251,24 @@ class Distribution:
def _discover_resolvers():
"""Search the meta_path for resolvers."""
declared = (
getattr(finder, 'find_distributions', None)
for finder in sys.meta_path
)
getattr(finder, 'find_distributions', None) for finder in sys.meta_path
)
return filter(None, declared)
@classmethod
def _local(cls, root='.'):
from pep517 import build, meta
system = build.compat_system(root)
builder = functools.partial(
meta.build,
source_dir=root,
system=system,
)
)
return PathDistribution(zipfile.Path(meta.build_as_zip(builder)))
@property
def metadata(self):
def metadata(self) -> PackageMetadata:
"""Return the parsed metadata for this Distribution.
The returned object will have keys that name the various bits of
@ -257,9 +281,14 @@ class Distribution:
# effect is to just end up using the PathDistribution's self._path
# (which points to the egg-info file) attribute unchanged.
or self.read_text('')
)
)
return email.message_from_string(text)
@property
def name(self):
"""Return the 'Name' metadata for the distribution package."""
return self.metadata['Name']
@property
def version(self):
"""Return the 'Version' metadata for the distribution package."""
@ -267,7 +296,7 @@ class Distribution:
@property
def entry_points(self):
return EntryPoint._from_text(self.read_text('entry_points.txt'))
return list(EntryPoint._from_text_for(self.read_text('entry_points.txt'), self))
@property
def files(self):
@ -324,9 +353,10 @@ class Distribution:
section_pairs = cls._read_sections(source.splitlines())
sections = {
section: list(map(operator.itemgetter('line'), results))
for section, results in
itertools.groupby(section_pairs, operator.itemgetter('section'))
}
for section, results in itertools.groupby(
section_pairs, operator.itemgetter('section')
)
}
return cls._convert_egg_info_reqs_to_simple_reqs(sections)
@staticmethod
@ -350,6 +380,7 @@ class Distribution:
requirement. This method converts the former to the
latter. See _test_deps_from_requires_text for an example.
"""
def make_condition(name):
return name and 'extra == "{name}"'.format(name=name)
@ -438,48 +469,69 @@ class FastPath:
names = zip_path.root.namelist()
self.joinpath = zip_path.joinpath
return dict.fromkeys(
child.split(posixpath.sep, 1)[0]
for child in names
)
def is_egg(self, search):
base = self.base
return (
base == search.versionless_egg_name
or base.startswith(search.prefix)
and base.endswith('.egg'))
return dict.fromkeys(child.split(posixpath.sep, 1)[0] for child in names)
def search(self, name):
for child in self.children():
n_low = child.lower()
if (n_low in name.exact_matches
or n_low.startswith(name.prefix)
and n_low.endswith(name.suffixes)
# legacy case:
or self.is_egg(name) and n_low == 'egg-info'):
yield self.joinpath(child)
return (
self.joinpath(child)
for child in self.children()
if name.matches(child, self.base)
)
class Prepared:
"""
A prepared search for metadata on a possibly-named package.
"""
normalized = ''
prefix = ''
normalized = None
suffixes = '.dist-info', '.egg-info'
exact_matches = [''][:0]
versionless_egg_name = ''
def __init__(self, name):
self.name = name
if name is None:
return
self.normalized = name.lower().replace('-', '_')
self.prefix = self.normalized + '-'
self.exact_matches = [
self.normalized + suffix for suffix in self.suffixes]
self.versionless_egg_name = self.normalized + '.egg'
self.normalized = self.normalize(name)
self.exact_matches = [self.normalized + suffix for suffix in self.suffixes]
@staticmethod
def normalize(name):
"""
PEP 503 normalization plus dashes as underscores.
"""
return re.sub(r"[-_.]+", "-", name).lower().replace('-', '_')
@staticmethod
def legacy_normalize(name):
"""
Normalize the package name as found in the convention in
older packaging tools versions and specs.
"""
return name.lower().replace('-', '_')
def matches(self, cand, base):
low = cand.lower()
pre, ext = os.path.splitext(low)
name, sep, rest = pre.partition('-')
return (
low in self.exact_matches
or ext in self.suffixes
and (not self.normalized or name.replace('.', '_') == self.normalized)
# legacy case:
or self.is_egg(base)
and low == 'egg-info'
)
def is_egg(self, base):
normalized = self.legacy_normalize(self.name or '')
prefix = normalized + '-' if normalized else ''
versionless_egg_name = normalized + '.egg' if self.name else ''
return (
base == versionless_egg_name
or base.startswith(prefix)
and base.endswith('.egg')
)
class MetadataPathFinder(DistributionFinder):
@ -500,9 +552,8 @@ class MetadataPathFinder(DistributionFinder):
def _search_paths(cls, name, paths):
"""Find metadata directories in paths heuristically."""
return itertools.chain.from_iterable(
path.search(Prepared(name))
for path in map(FastPath, paths)
)
path.search(Prepared(name)) for path in map(FastPath, paths)
)
class PathDistribution(Distribution):
@ -515,9 +566,15 @@ class PathDistribution(Distribution):
self._path = path
def read_text(self, filename):
with suppress(FileNotFoundError, IsADirectoryError, KeyError,
NotADirectoryError, PermissionError):
with suppress(
FileNotFoundError,
IsADirectoryError,
KeyError,
NotADirectoryError,
PermissionError,
):
return self._path.joinpath(filename).read_text(encoding='utf-8')
read_text.__doc__ = Distribution.read_text.__doc__
def locate_file(self, path):
@ -541,11 +598,11 @@ def distributions(**kwargs):
return Distribution.discover(**kwargs)
def metadata(distribution_name):
def metadata(distribution_name) -> PackageMetadata:
"""Get the metadata for the named package.
:param distribution_name: The name of the distribution package to query.
:return: An email.Message containing the parsed metadata.
:return: A PackageMetadata containing the parsed metadata.
"""
return Distribution.from_name(distribution_name).metadata
@ -565,15 +622,11 @@ def entry_points():
:return: EntryPoint objects for all installed packages.
"""
eps = itertools.chain.from_iterable(
dist.entry_points for dist in distributions())
eps = itertools.chain.from_iterable(dist.entry_points for dist in distributions())
by_group = operator.attrgetter('group')
ordered = sorted(eps, key=by_group)
grouped = itertools.groupby(ordered, by_group)
return {
group: tuple(eps)
for group, eps in grouped
}
return {group: tuple(eps) for group, eps in grouped}
def files(distribution_name):

View File

@ -174,7 +174,7 @@ def libc_ver(executable=None, lib='', version='', chunksize=16384):
The file is read and scanned in chunks of chunksize bytes.
"""
if executable is None:
if not executable:
try:
ver = os.confstr('CS_GNU_LIBC_VERSION')
# parse 'glibc 2.28' as ('glibc', '2.28')
@ -769,7 +769,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.
"""
@ -784,12 +784,25 @@ class uname_result(
(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

View File

@ -1,5 +1,5 @@
# -*- coding: utf-8 -*-
# Autogenerated by Sphinx on Mon Dec 7 19:34:00 2020
# Autogenerated by Sphinx on Mon Jan 4 17:25:50 2021
topics = {'assert': 'The "assert" statement\n'
'**********************\n'
'\n'
@ -461,13 +461,12 @@ topics = {'assert': 'The "assert" statement\n'
'\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'
@ -2383,8 +2382,9 @@ topics = {'assert': 'The "assert" statement\n'
'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'
@ -2451,11 +2451,32 @@ topics = {'assert': 'The "assert" statement\n'
'(see\n'
'section The standard type hierarchy) identifying the point in '
'the\n'
'program where the exception occurred. "sys.exc_info()" values '
'are\n'
'restored to their previous values (before the call) when '
'returning\n'
'from a function that handled an exception.\n'
'program where the exception occurred. The details about the '
'exception\n'
'accessed via "sys.exc_info()" are restored to their previous '
'values\n'
'when leaving an exception handler:\n'
'\n'
' >>> print(sys.exc_info())\n'
' (None, None, None)\n'
' >>> try:\n'
' ... raise TypeError\n'
' ... except:\n'
' ... print(sys.exc_info())\n'
' ... try:\n'
' ... raise ValueError\n'
' ... except:\n'
' ... print(sys.exc_info())\n'
' ... print(sys.exc_info())\n'
' ...\n'
" (<class 'TypeError'>, TypeError(), <traceback object at "
'0x10efad080>)\n'
" (<class 'ValueError'>, ValueError(), <traceback object at "
'0x10efad040>)\n'
" (<class 'TypeError'>, TypeError(), <traceback object at "
'0x10efad080>)\n'
' >>> print(sys.exc_info())\n'
' (None, None, None)\n'
'\n'
'The optional "else" clause is executed if the control flow '
'leaves the\n'
@ -2985,13 +3006,12 @@ topics = {'assert': 'The "assert" statement\n'
'\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'
@ -5524,44 +5544,51 @@ topics = {'assert': 'The "assert" statement\n'
' | | 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 '
@ -5586,19 +5613,24 @@ topics = {'assert': 'The "assert" statement\n'
'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'
@ -5972,8 +6004,10 @@ topics = {'assert': 'The "assert" statement\n'
'\n'
'Names listed in a "global" statement must not be defined as '
'formal\n'
'parameters or in a "for" loop control target, "class" definition,\n'
'function definition, "import" statement, or variable annotation.\n'
'parameters, or as targets in "with" statements or "except" '
'clauses, or\n'
'in a "for" target list, "class" definition, function definition,\n'
'"import" statement, or variable annotation.\n'
'\n'
'**CPython implementation detail:** The current implementation does '
'not\n'
@ -7925,7 +7959,7 @@ topics = {'assert': 'The "assert" statement\n'
'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'
" [<class 'bool'>]\n"
@ -11224,7 +11258,8 @@ topics = {'assert': 'The "assert" statement\n'
'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'
@ -11279,9 +11314,31 @@ topics = {'assert': 'The "assert" statement\n'
'the\n'
'exception class, the exception instance and a traceback object (see\n'
'section The standard type hierarchy) identifying the point in the\n'
'program where the exception occurred. "sys.exc_info()" values are\n'
'restored to their previous values (before the call) when returning\n'
'from a function that handled an exception.\n'
'program where the exception occurred. The details about the '
'exception\n'
'accessed via "sys.exc_info()" are restored to their previous values\n'
'when leaving an exception handler:\n'
'\n'
' >>> print(sys.exc_info())\n'
' (None, None, None)\n'
' >>> try:\n'
' ... raise TypeError\n'
' ... except:\n'
' ... print(sys.exc_info())\n'
' ... try:\n'
' ... raise ValueError\n'
' ... except:\n'
' ... print(sys.exc_info())\n'
' ... print(sys.exc_info())\n'
' ...\n'
" (<class 'TypeError'>, TypeError(), <traceback object at "
'0x10efad080>)\n'
" (<class 'ValueError'>, ValueError(), <traceback object at "
'0x10efad040>)\n'
" (<class 'TypeError'>, TypeError(), <traceback object at "
'0x10efad080>)\n'
' >>> print(sys.exc_info())\n'
' (None, None, None)\n'
'\n'
'The optional "else" clause is executed if the control flow leaves '
'the\n'
@ -11445,7 +11502,6 @@ topics = {'assert': 'The "assert" statement\n'
' 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'

View File

@ -51,6 +51,7 @@ from math import sqrt as _sqrt, acos as _acos, cos as _cos, sin as _sin
from math import tau as TWOPI, floor as _floor, isfinite as _isfinite
from os import urandom as _urandom
from _collections_abc import Set as _Set, Sequence as _Sequence
from operator import index as _index
from itertools import accumulate as _accumulate, repeat as _repeat
from bisect import bisect as _bisect
import os as _os
@ -95,6 +96,7 @@ LOG4 = _log(4.0)
SG_MAGICCONST = 1.0 + _log(4.5)
BPF = 53 # Number of bits in a float
RECIP_BPF = 2 ** -BPF
_ONE = 1
class Random(_random.Random):
@ -287,7 +289,7 @@ class Random(_random.Random):
## -------------------- integer methods -------------------
def randrange(self, start, stop=None, step=1):
def randrange(self, start, stop=None, step=_ONE):
"""Choose a random item from range(start, stop[, step]).
This fixes the problem with randint() which includes the
@ -297,38 +299,72 @@ class Random(_random.Random):
# This code is a bit messy to make it fast for the
# common case while still doing adequate error checking.
istart = int(start)
if istart != start:
raise ValueError("non-integer arg 1 for randrange()")
try:
istart = _index(start)
except TypeError:
if int(start) == start:
istart = int(start)
_warn('Float arguments to randrange() have been deprecated\n'
'since Python 3.10 and will be removed in a subsequent '
'version.',
DeprecationWarning, 2)
else:
_warn('randrange() will raise TypeError in the future',
DeprecationWarning, 2)
raise ValueError("non-integer arg 1 for randrange()")
if stop is None:
# We don't check for "step != 1" because it hasn't been
# type checked and converted to an integer yet.
if step is not _ONE:
raise TypeError('Missing a non-None stop argument')
if istart > 0:
return self._randbelow(istart)
raise ValueError("empty range for randrange()")
# stop argument supplied.
istop = int(stop)
if istop != stop:
raise ValueError("non-integer stop for randrange()")
try:
istop = _index(stop)
except TypeError:
if int(stop) == stop:
istop = int(stop)
_warn('Float arguments to randrange() have been deprecated\n'
'since Python 3.10 and will be removed in a subsequent '
'version.',
DeprecationWarning, 2)
else:
_warn('randrange() will raise TypeError in the future',
DeprecationWarning, 2)
raise ValueError("non-integer stop for randrange()")
try:
istep = _index(step)
except TypeError:
if int(step) == step:
istep = int(step)
_warn('Float arguments to randrange() have been deprecated\n'
'since Python 3.10 and will be removed in a subsequent '
'version.',
DeprecationWarning, 2)
else:
_warn('randrange() will raise TypeError in the future',
DeprecationWarning, 2)
raise ValueError("non-integer step for randrange()")
width = istop - istart
if step == 1 and width > 0:
return istart + self._randbelow(width)
if step == 1:
if istep == 1:
if width > 0:
return istart + self._randbelow(width)
raise ValueError("empty range for randrange() (%d, %d, %d)" % (istart, istop, width))
# Non-unit step argument supplied.
istep = int(step)
if istep != step:
raise ValueError("non-integer step for randrange()")
if istep > 0:
n = (width + istep - 1) // istep
elif istep < 0:
n = (width + istep + 1) // istep
else:
raise ValueError("zero step for randrange()")
if n <= 0:
raise ValueError("empty range for randrange()")
return istart + istep * self._randbelow(n)
def randint(self, a, b):

View File

@ -1082,7 +1082,8 @@ class LMTP(SMTP):
# 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:

View File

@ -628,6 +628,39 @@ if hasattr(os, "fork"):
self.collect_children(blocking=self.block_on_close)
class _Threads(list):
"""
Joinable list of all non-daemon threads.
"""
def append(self, thread):
self.reap()
if thread.daemon:
return
super().append(thread)
def pop_all(self):
self[:], result = [], self[:]
return result
def join(self):
for thread in self.pop_all():
thread.join()
def reap(self):
self[:] = (thread for thread in self if thread.is_alive())
class _NoThreads:
"""
Degenerate version of _Threads.
"""
def append(self, thread):
pass
def join(self):
pass
class ThreadingMixIn:
"""Mix-in class to handle each request in a new thread."""
@ -636,9 +669,9 @@ class ThreadingMixIn:
daemon_threads = False
# If true, server_close() waits until all non-daemonic threads terminate.
block_on_close = True
# For non-daemonic threads, list of threading.Threading objects
# Threads object
# used by server_close() to wait for all threads completion.
_threads = None
_threads = _NoThreads()
def process_request_thread(self, request, client_address):
"""Same as in BaseServer but as a thread.
@ -655,23 +688,17 @@ class ThreadingMixIn:
def process_request(self, request, client_address):
"""Start a new thread to process the request."""
if self.block_on_close:
vars(self).setdefault('_threads', _Threads())
t = threading.Thread(target = self.process_request_thread,
args = (request, client_address))
t.daemon = self.daemon_threads
if not t.daemon and self.block_on_close:
if self._threads is None:
self._threads = []
self._threads.append(t)
self._threads.append(t)
t.start()
def server_close(self):
super().server_close()
if self.block_on_close:
threads = self._threads
self._threads = None
if threads:
for thread in threads:
thread.join()
self._threads.join()
if hasattr(os, "fork"):

View File

@ -260,6 +260,14 @@ class TraceCallbackTests(unittest.TestCase):
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)

View File

@ -420,7 +420,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

View File

@ -14,6 +14,6 @@ the user build or load random bytecodes anyway. Otherwise, this is a
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)

View File

@ -107,6 +107,9 @@ class MockSocket:
def close(self):
pass
def connect(self, host):
pass
def socket(family=None, type=None, proto=None):
return MockSocket(family)
@ -152,8 +155,12 @@ error = socket_module.error
# 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

View File

@ -69,6 +69,10 @@ def count_opcode(code, pickle):
return n
def identity(x):
return x
class UnseekableIO(io.BytesIO):
def peek(self, *args):
raise NotImplementedError
@ -138,11 +142,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
@ -157,10 +162,6 @@ __main__.D = D
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):
@ -1496,54 +1497,182 @@ class AbstractPickleTests(unittest.TestCase):
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_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 range(minprotocol, pickle.HIGHEST_PROTOCOL + 1):
s = self.dumps(d, proto)
x = self.loads(s)
self.assertIsInstance(x, cls)
y = asdict(x)
self.assertEqual(list(y.keys()), [1])
self.assertIs(y[1], x)
def test_recursive_dict(self):
d = {}
d[1] = d
for proto in protocols:
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(list(x.keys()), [1])
self.assertIs(x[1], 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):
d = {}
k = K(d)
d[k] = 1
for proto in protocols:
s = self.dumps(d, proto)
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, 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, 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)
@ -1552,52 +1681,31 @@ class AbstractPickleTests(unittest.TestCase):
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:
@ -1607,49 +1715,94 @@ class AbstractPickleTests(unittest.TestCase):
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)
self.assertIs(x[0].attr[1], x)
def check_recursive_collection_and_inst(self, factory):
h = H()
y = factory([h])
h.attr = y
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>',
@ -3062,6 +3215,19 @@ class REX_seven(object):
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

View File

@ -1,6 +1,7 @@
"""Tests for the asdl parser in Parser/asdl.py"""
import importlib.machinery
import importlib.util
import os
from os.path import dirname
import sys
@ -26,7 +27,10 @@ class TestAsdlParser(unittest.TestCase):
sys.path.insert(0, parser_dir)
loader = importlib.machinery.SourceFileLoader(
'asdl', os.path.join(parser_dir, 'asdl.py'))
cls.asdl = loader.load_module()
spec = importlib.util.spec_from_loader('asdl', loader)
module = importlib.util.module_from_spec(spec)
loader.exec_module(module)
cls.asdl = module
cls.mod = cls.asdl.parse(os.path.join(parser_dir, 'Python.asdl'))
cls.assertTrue(cls.asdl.check(cls.mod), 'Module validation failed')

View File

@ -1011,6 +1011,18 @@ Module(
self.assertEqual(ast.literal_eval(" \t -1"), -1)
self.assertRaises(IndentationError, ast.literal_eval, "\n -1")
def test_literal_eval_malformed_lineno(self):
msg = r'malformed node or string on line 3:'
with self.assertRaisesRegex(ValueError, msg):
ast.literal_eval("{'a': 1,\n'b':2,\n'c':++3,\n'd':4}")
node = ast.UnaryOp(
ast.UAdd(), ast.UnaryOp(ast.UAdd(), ast.Constant(6)))
self.assertIsNone(getattr(node, 'lineno', None))
msg = r'malformed node or string:'
with self.assertRaisesRegex(ValueError, msg):
ast.literal_eval(node)
def test_bad_integer(self):
# issue13436: Bad error message with invalid numeric values
body = [ast.ImportFrom(module='time',

View File

@ -1621,48 +1621,6 @@ class BuiltinTest(unittest.TestCase):
self.assertEqual(self.iter_error(z1, ValueError), t)
self.assertEqual(self.iter_error(z2, ValueError), t)
def test_zip_pickle_stability(self):
# Pickles of zip((1, 2, 3), (4, 5, 6)) dumped from 3.9:
pickles = [
b'citertools\nizip\np0\n(c__builtin__\niter\np1\n((I1\nI2\nI3\ntp2\ntp3\nRp4\nI0\nbg1\n((I4\nI5\nI6\ntp5\ntp6\nRp7\nI0\nbtp8\nRp9\n.',
b'citertools\nizip\nq\x00(c__builtin__\niter\nq\x01((K\x01K\x02K\x03tq\x02tq\x03Rq\x04K\x00bh\x01((K\x04K\x05K\x06tq\x05tq\x06Rq\x07K\x00btq\x08Rq\t.',
b'\x80\x02citertools\nizip\nq\x00c__builtin__\niter\nq\x01K\x01K\x02K\x03\x87q\x02\x85q\x03Rq\x04K\x00bh\x01K\x04K\x05K\x06\x87q\x05\x85q\x06Rq\x07K\x00b\x86q\x08Rq\t.',
b'\x80\x03cbuiltins\nzip\nq\x00cbuiltins\niter\nq\x01K\x01K\x02K\x03\x87q\x02\x85q\x03Rq\x04K\x00bh\x01K\x04K\x05K\x06\x87q\x05\x85q\x06Rq\x07K\x00b\x86q\x08Rq\t.',
b'\x80\x04\x95L\x00\x00\x00\x00\x00\x00\x00\x8c\x08builtins\x94\x8c\x03zip\x94\x93\x94\x8c\x08builtins\x94\x8c\x04iter\x94\x93\x94K\x01K\x02K\x03\x87\x94\x85\x94R\x94K\x00bh\x05K\x04K\x05K\x06\x87\x94\x85\x94R\x94K\x00b\x86\x94R\x94.',
b'\x80\x05\x95L\x00\x00\x00\x00\x00\x00\x00\x8c\x08builtins\x94\x8c\x03zip\x94\x93\x94\x8c\x08builtins\x94\x8c\x04iter\x94\x93\x94K\x01K\x02K\x03\x87\x94\x85\x94R\x94K\x00bh\x05K\x04K\x05K\x06\x87\x94\x85\x94R\x94K\x00b\x86\x94R\x94.',
]
for protocol, dump in enumerate(pickles):
z1 = zip((1, 2, 3), (4, 5, 6))
z2 = zip((1, 2, 3), (4, 5, 6), strict=False)
z3 = pickle.loads(dump)
l3 = list(z3)
self.assertEqual(type(z3), zip)
self.assertEqual(pickle.dumps(z1, protocol), dump)
self.assertEqual(pickle.dumps(z2, protocol), dump)
self.assertEqual(list(z1), l3)
self.assertEqual(list(z2), l3)
def test_zip_pickle_strict_stability(self):
# Pickles of zip((1, 2, 3), (4, 5), strict=True) dumped from 3.10:
pickles = [
b'citertools\nizip\np0\n(c__builtin__\niter\np1\n((I1\nI2\nI3\ntp2\ntp3\nRp4\nI0\nbg1\n((I4\nI5\ntp5\ntp6\nRp7\nI0\nbtp8\nRp9\nI01\nb.',
b'citertools\nizip\nq\x00(c__builtin__\niter\nq\x01((K\x01K\x02K\x03tq\x02tq\x03Rq\x04K\x00bh\x01((K\x04K\x05tq\x05tq\x06Rq\x07K\x00btq\x08Rq\tI01\nb.',
b'\x80\x02citertools\nizip\nq\x00c__builtin__\niter\nq\x01K\x01K\x02K\x03\x87q\x02\x85q\x03Rq\x04K\x00bh\x01K\x04K\x05\x86q\x05\x85q\x06Rq\x07K\x00b\x86q\x08Rq\t\x88b.',
b'\x80\x03cbuiltins\nzip\nq\x00cbuiltins\niter\nq\x01K\x01K\x02K\x03\x87q\x02\x85q\x03Rq\x04K\x00bh\x01K\x04K\x05\x86q\x05\x85q\x06Rq\x07K\x00b\x86q\x08Rq\t\x88b.',
b'\x80\x04\x95L\x00\x00\x00\x00\x00\x00\x00\x8c\x08builtins\x94\x8c\x03zip\x94\x93\x94\x8c\x08builtins\x94\x8c\x04iter\x94\x93\x94K\x01K\x02K\x03\x87\x94\x85\x94R\x94K\x00bh\x05K\x04K\x05\x86\x94\x85\x94R\x94K\x00b\x86\x94R\x94\x88b.',
b'\x80\x05\x95L\x00\x00\x00\x00\x00\x00\x00\x8c\x08builtins\x94\x8c\x03zip\x94\x93\x94\x8c\x08builtins\x94\x8c\x04iter\x94\x93\x94K\x01K\x02K\x03\x87\x94\x85\x94R\x94K\x00bh\x05K\x04K\x05\x86\x94\x85\x94R\x94K\x00b\x86\x94R\x94\x88b.',
]
a = (1, 2, 3)
b = (4, 5)
t = [(1, 4), (2, 5)]
for protocol, dump in enumerate(pickles):
z1 = zip(a, b, strict=True)
z2 = pickle.loads(dump)
self.assertEqual(pickle.dumps(z1, protocol), dump)
self.assertEqual(type(z2), zip)
self.assertEqual(self.iter_error(z1, ValueError), t)
self.assertEqual(self.iter_error(z2, ValueError), t)
def test_zip_bad_iterable(self):
exception = TypeError()

View File

@ -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 os
import string
import sys
import tempfile
import functools
import unittest
from test.support import requires, verbose, SaveSignals
@ -37,7 +37,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',
@ -48,37 +58,59 @@ 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()
if verbose:
print(f'TERM={term}', file=sys.stderr, flush=True)
# 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"
@ -96,7 +128,7 @@ class TestCurses(unittest.TestCase):
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,
@ -207,6 +239,11 @@ class TestCurses(unittest.TestCase):
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)
@ -225,17 +262,20 @@ class TestCurses(unittest.TestCase):
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,
curses.has_extended_color_support]:
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'):
@ -247,13 +287,9 @@ class TestCurses(unittest.TestCase):
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)
@ -262,7 +298,8 @@ class TestCurses(unittest.TestCase):
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)
@ -281,31 +318,127 @@ class TestCurses(unittest.TestCase):
curses.use_env(1)
# Functions only available on a few platforms
def test_colors_funcs(self):
def bad_colors(self):
return (-1, curses.COLORS, -2**31 - 1, 2**31, -2**63 - 1, 2**63, 2**64)
def bad_colors2(self):
return (curses.COLORS, 2**31, 2**63, 2**64)
def bad_pairs(self):
return (-1, -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()
curses.init_pair(2, 1,1)
curses.color_content(1)
curses.color_pair(2)
curses.pair_content(curses.COLOR_PAIRS - 1)
curses.pair_number(0)
if verbose:
print(f'COLORS = {curses.COLORS}', file=sys.stderr)
print(f'COLOR_PAIRS = {curses.COLOR_PAIRS}', file=sys.stderr)
if hasattr(curses, 'use_default_colors'):
curses.use_default_colors()
@requires_colors
def test_color_content(self):
self.assertEqual(curses.color_content(curses.COLOR_BLACK), (0, 0, 0))
curses.color_content(0)
maxcolor = curses.COLORS - 1
curses.color_content(maxcolor)
self.assertRaises(ValueError, curses.color_content, -1)
self.assertRaises(ValueError, curses.color_content, curses.COLORS + 1)
self.assertRaises(ValueError, curses.color_content, -2**31 - 1)
self.assertRaises(ValueError, curses.color_content, 2**31)
self.assertRaises(ValueError, curses.color_content, -2**63 - 1)
self.assertRaises(ValueError, curses.color_content, 2**63 - 1)
self.assertRaises(ValueError, curses.pair_content, -1)
self.assertRaises(ValueError, curses.pair_content, curses.COLOR_PAIRS)
self.assertRaises(ValueError, curses.pair_content, -2**31 - 1)
self.assertRaises(ValueError, curses.pair_content, 2**31)
self.assertRaises(ValueError, curses.pair_content, -2**63 - 1)
self.assertRaises(ValueError, curses.pair_content, 2**63 - 1)
for color in self.bad_colors():
self.assertRaises(ValueError, curses.color_content, color)
@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 = curses.COLORS - 1
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(ValueError, curses.init_color, color, 0, 0, 0)
for comp in (-1, 1001):
self.assertRaises(ValueError, curses.init_color, 0, comp, 0, 0)
self.assertRaises(ValueError, curses.init_color, 0, 0, comp, 0)
self.assertRaises(ValueError, curses.init_color, 0, 0, 0, comp)
def get_pair_limit(self):
pair_limit = curses.COLOR_PAIRS
if hasattr(curses, 'ncurses_version'):
if curses.has_extended_color_support():
pair_limit += 2*curses.COLORS + 1
if (not curses.has_extended_color_support()
or (6, 1) <= curses.ncurses_version < (6, 2)):
pair_limit = min(pair_limit, SHORT_MAX)
return pair_limit
@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)
maxpair = self.get_pair_limit() - 1
if maxpair > 0:
curses.pair_content(maxpair)
for pair in self.bad_pairs():
self.assertRaises(ValueError, curses.pair_content, pair)
@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 = curses.COLORS - 1
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(ValueError, curses.init_pair, pair, 0, 0)
for color in self.bad_colors2():
self.assertRaises(ValueError, curses.init_pair, 1, color, 0)
self.assertRaises(ValueError, curses.init_pair, 1, 0, color)
@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):
@ -373,7 +506,6 @@ class TestCurses(unittest.TestCase):
@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
@ -477,6 +609,8 @@ class MiscTests(unittest.TestCase):
@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)

View File

@ -2119,7 +2119,7 @@ class TestEnum(unittest.TestCase):
one = '1'
two = b'2', 'ascii', 9
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)
@ -2155,6 +2155,16 @@ class TestEnum(unittest.TestCase):
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)
@unittest.skipUnless(
sys.version_info[:2] == (3, 9),

View File

@ -332,6 +332,59 @@ non-important content
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'''

View File

@ -27,8 +27,7 @@ import functools
py_functools = import_helper.import_fresh_module('functools',
blocked=['_functools'])
c_functools = import_helper.import_fresh_module('functools',
fresh=['_functools'])
c_functools = import_helper.import_fresh_module('functools')
decimal = import_helper.import_fresh_module('decimal', fresh=['_decimal'])

View File

@ -7,6 +7,7 @@ import textwrap
import contextlib
from test.support.os_helper import FS_NONASCII
from typing import Dict, Union
@contextlib.contextmanager
@ -71,8 +72,13 @@ class OnSysPath(Fixtures):
self.fixtures.enter_context(self.add_sys_path(self.site_dir))
# Except for python/mypy#731, prefer to define
# FilesDef = Dict[str, Union['FilesDef', str]]
FilesDef = Dict[str, Union[Dict[str, Union[Dict[str, str], str]], str]]
class DistInfoPkg(OnSysPath, SiteDir):
files = {
files: FilesDef = {
"distinfo_pkg-1.0.0.dist-info": {
"METADATA": """
Name: distinfo-pkg
@ -86,19 +92,55 @@ class DistInfoPkg(OnSysPath, SiteDir):
[entries]
main = mod:main
ns:sub = mod:main
"""
},
""",
},
"mod.py": """
def main():
print("hello world")
""",
}
}
def setUp(self):
super(DistInfoPkg, self).setUp()
build_files(DistInfoPkg.files, self.site_dir)
class DistInfoPkgWithDot(OnSysPath, SiteDir):
files: FilesDef = {
"pkg_dot-1.0.0.dist-info": {
"METADATA": """
Name: pkg.dot
Version: 1.0.0
""",
},
}
def setUp(self):
super(DistInfoPkgWithDot, self).setUp()
build_files(DistInfoPkgWithDot.files, self.site_dir)
class DistInfoPkgWithDotLegacy(OnSysPath, SiteDir):
files: FilesDef = {
"pkg.dot-1.0.0.dist-info": {
"METADATA": """
Name: pkg.dot
Version: 1.0.0
""",
},
"pkg.lot.egg-info": {
"METADATA": """
Name: pkg.lot
Version: 1.0.0
""",
},
}
def setUp(self):
super(DistInfoPkgWithDotLegacy, self).setUp()
build_files(DistInfoPkgWithDotLegacy.files, self.site_dir)
class DistInfoPkgOffPath(SiteDir):
def setUp(self):
super(DistInfoPkgOffPath, self).setUp()
@ -106,7 +148,7 @@ class DistInfoPkgOffPath(SiteDir):
class EggInfoPkg(OnSysPath, SiteDir):
files = {
files: FilesDef = {
"egginfo_pkg.egg-info": {
"PKG-INFO": """
Name: egginfo-pkg
@ -129,13 +171,13 @@ class EggInfoPkg(OnSysPath, SiteDir):
[test]
pytest
""",
"top_level.txt": "mod\n"
},
"top_level.txt": "mod\n",
},
"mod.py": """
def main():
print("hello world")
""",
}
}
def setUp(self):
super(EggInfoPkg, self).setUp()
@ -143,7 +185,7 @@ class EggInfoPkg(OnSysPath, SiteDir):
class EggInfoFile(OnSysPath, SiteDir):
files = {
files: FilesDef = {
"egginfo_file.egg-info": """
Metadata-Version: 1.0
Name: egginfo_file
@ -156,7 +198,7 @@ class EggInfoFile(OnSysPath, SiteDir):
Description: UNKNOWN
Platform: UNKNOWN
""",
}
}
def setUp(self):
super(EggInfoFile, self).setUp()
@ -164,12 +206,12 @@ class EggInfoFile(OnSysPath, SiteDir):
class LocalPackage:
files = {
files: FilesDef = {
"setup.py": """
import setuptools
setuptools.setup(name="local-pkg", version="2.0.1")
""",
}
}
def setUp(self):
self.fixtures = contextlib.ExitStack()
@ -214,8 +256,7 @@ def build_files(file_defs, prefix=pathlib.Path()):
class FileBuilder:
def unicode_filename(self):
return FS_NONASCII or \
self.skip("File system does not support non-ascii.")
return FS_NONASCII or self.skip("File system does not support non-ascii.")
def DALS(str):

View File

@ -1,5 +1,3 @@
# coding: utf-8
import re
import json
import pickle
@ -14,10 +12,14 @@ except ImportError:
from . import fixtures
from importlib.metadata import (
Distribution, EntryPoint,
PackageNotFoundError, distributions,
entry_points, metadata, version,
)
Distribution,
EntryPoint,
PackageNotFoundError,
distributions,
entry_points,
metadata,
version,
)
class BasicTests(fixtures.DistInfoPkg, unittest.TestCase):
@ -70,12 +72,11 @@ class ImportTests(fixtures.DistInfoPkg, unittest.TestCase):
name='ep',
value='importlib.metadata',
group='grp',
)
)
assert ep.load() is importlib.metadata
class NameNormalizationTests(
fixtures.OnSysPath, fixtures.SiteDir, unittest.TestCase):
class NameNormalizationTests(fixtures.OnSysPath, fixtures.SiteDir, unittest.TestCase):
@staticmethod
def pkg_with_dashes(site_dir):
"""
@ -144,11 +145,15 @@ class NonASCIITests(fixtures.OnSysPath, fixtures.SiteDir, unittest.TestCase):
metadata_dir.mkdir()
metadata = metadata_dir / 'METADATA'
with metadata.open('w', encoding='utf-8') as fp:
fp.write(textwrap.dedent("""
fp.write(
textwrap.dedent(
"""
Name: portend
pôrˈtend
""").lstrip())
"""
).lstrip()
)
return 'portend'
def test_metadata_loads(self):
@ -162,24 +167,12 @@ class NonASCIITests(fixtures.OnSysPath, fixtures.SiteDir, unittest.TestCase):
assert meta.get_payload() == 'pôrˈtend\n'
class DiscoveryTests(fixtures.EggInfoPkg,
fixtures.DistInfoPkg,
unittest.TestCase):
class DiscoveryTests(fixtures.EggInfoPkg, fixtures.DistInfoPkg, unittest.TestCase):
def test_package_discovery(self):
dists = list(distributions())
assert all(
isinstance(dist, Distribution)
for dist in dists
)
assert any(
dist.metadata['Name'] == 'egginfo-pkg'
for dist in dists
)
assert any(
dist.metadata['Name'] == 'distinfo-pkg'
for dist in dists
)
assert all(isinstance(dist, Distribution) for dist in dists)
assert any(dist.metadata['Name'] == 'egginfo-pkg' for dist in dists)
assert any(dist.metadata['Name'] == 'distinfo-pkg' for dist in dists)
def test_invalid_usage(self):
with self.assertRaises(ValueError):
@ -265,10 +258,21 @@ class TestEntryPoints(unittest.TestCase):
def test_attr(self):
assert self.ep.attr is None
def test_sortable(self):
"""
EntryPoint objects are sortable, but result is undefined.
"""
sorted(
[
EntryPoint('b', 'val', 'group'),
EntryPoint('a', 'val', 'group'),
]
)
class FileSystem(
fixtures.OnSysPath, fixtures.SiteDir, fixtures.FileBuilder,
unittest.TestCase):
fixtures.OnSysPath, fixtures.SiteDir, fixtures.FileBuilder, unittest.TestCase
):
def test_unicode_dir_on_sys_path(self):
"""
Ensure a Unicode subdirectory of a directory on sys.path
@ -277,5 +281,5 @@ class FileSystem(
fixtures.build_files(
{self.unicode_filename(): {}},
prefix=self.site_dir,
)
)
list(distributions())

View File

@ -2,20 +2,26 @@ import re
import textwrap
import unittest
from collections.abc import Iterator
from . import fixtures
from importlib.metadata import (
Distribution, PackageNotFoundError, distribution,
entry_points, files, metadata, requires, version,
)
Distribution,
PackageNotFoundError,
distribution,
entry_points,
files,
metadata,
requires,
version,
)
class APITests(
fixtures.EggInfoPkg,
fixtures.DistInfoPkg,
fixtures.EggInfoFile,
unittest.TestCase):
fixtures.EggInfoPkg,
fixtures.DistInfoPkg,
fixtures.DistInfoPkgWithDot,
fixtures.EggInfoFile,
unittest.TestCase,
):
version_pattern = r'\d+\.\d+(\.\d)?'
@ -33,16 +39,28 @@ class APITests(
with self.assertRaises(PackageNotFoundError):
distribution('does-not-exist')
def test_name_normalization(self):
names = 'pkg.dot', 'pkg_dot', 'pkg-dot', 'pkg..dot', 'Pkg.Dot'
for name in names:
with self.subTest(name):
assert distribution(name).metadata['Name'] == 'pkg.dot'
def test_prefix_not_matched(self):
prefixes = 'p', 'pkg', 'pkg.'
for prefix in prefixes:
with self.subTest(prefix):
with self.assertRaises(PackageNotFoundError):
distribution(prefix)
def test_for_top_level(self):
self.assertEqual(
distribution('egginfo-pkg').read_text('top_level.txt').strip(),
'mod')
distribution('egginfo-pkg').read_text('top_level.txt').strip(), 'mod'
)
def test_read_text(self):
top_level = [
path for path in files('egginfo-pkg')
if path.name == 'top_level.txt'
][0]
path for path in files('egginfo-pkg') if path.name == 'top_level.txt'
][0]
self.assertEqual(top_level.read_text(), 'mod\n')
def test_entry_points(self):
@ -51,6 +69,13 @@ class APITests(
self.assertEqual(ep.value, 'mod:main')
self.assertEqual(ep.extras, [])
def test_entry_points_distribution(self):
entries = dict(entry_points()['entries'])
for entry in ("main", "ns:sub"):
ep = entries[entry]
self.assertIn(ep.dist.name, ('distinfo-pkg', 'egginfo-pkg'))
self.assertEqual(ep.dist.version, "1.0.0")
def test_metadata_for_this_package(self):
md = metadata('egginfo-pkg')
assert md['author'] == 'Steven Ma'
@ -75,13 +100,8 @@ class APITests(
def test_file_hash_repr(self):
assertRegex = self.assertRegex
util = [
p for p in files('distinfo-pkg')
if p.name == 'mod.py'
][0]
assertRegex(
repr(util.hash),
'<FileHash mode: sha256 value: .*>')
util = [p for p in files('distinfo-pkg') if p.name == 'mod.py'][0]
assertRegex(repr(util.hash), '<FileHash mode: sha256 value: .*>')
def test_files_dist_info(self):
self._test_files(files('distinfo-pkg'))
@ -99,10 +119,7 @@ class APITests(
def test_requires_egg_info(self):
deps = requires('egginfo-pkg')
assert len(deps) == 2
assert any(
dep == 'wheel >= 1.0; python_version >= "2.7"'
for dep in deps
)
assert any(dep == 'wheel >= 1.0; python_version >= "2.7"' for dep in deps)
def test_requires_dist_info(self):
deps = requires('distinfo-pkg')
@ -112,7 +129,8 @@ class APITests(
assert "pytest; extra == 'test'" in deps
def test_more_complex_deps_requires_text(self):
requires = textwrap.dedent("""
requires = textwrap.dedent(
"""
dep1
dep2
@ -124,7 +142,8 @@ class APITests(
[extra2:python_version < "3"]
dep5
""")
"""
)
deps = sorted(Distribution._deps_from_requires_text(requires))
expected = [
'dep1',
@ -132,7 +151,7 @@ class APITests(
'dep3; python_version < "3"',
'dep4; extra == "extra1"',
'dep5; (python_version < "3") and extra == "extra2"',
]
]
# It's important that the environment marker expression be
# wrapped in parentheses to avoid the following 'and' binding more
# tightly than some other part of the environment expression.
@ -140,17 +159,27 @@ class APITests(
assert deps == expected
class LegacyDots(fixtures.DistInfoPkgWithDotLegacy, unittest.TestCase):
def test_name_normalization(self):
names = 'pkg.dot', 'pkg_dot', 'pkg-dot', 'pkg..dot', 'Pkg.Dot'
for name in names:
with self.subTest(name):
assert distribution(name).metadata['Name'] == 'pkg.dot'
def test_name_normalization_versionless_egg_info(self):
names = 'pkg.lot', 'pkg_lot', 'pkg-lot', 'pkg..lot', 'Pkg.Lot'
for name in names:
with self.subTest(name):
assert distribution(name).metadata['Name'] == 'pkg.lot'
class OffSysPathTests(fixtures.DistInfoPkgOffPath, unittest.TestCase):
def test_find_distributions_specified_path(self):
dists = Distribution.discover(path=[str(self.site_dir)])
assert any(
dist.metadata['Name'] == 'distinfo-pkg'
for dist in dists
)
assert any(dist.metadata['Name'] == 'distinfo-pkg' for dist in dists)
def test_distribution_at_pathlib(self):
"""Demonstrate how to load metadata direct from a directory.
"""
"""Demonstrate how to load metadata direct from a directory."""
dist_info_path = self.site_dir / 'distinfo_pkg-1.0.0.dist-info'
dist = Distribution.at(dist_info_path)
assert dist.version == '1.0.0'

View File

@ -3,8 +3,12 @@ import unittest
from contextlib import ExitStack
from importlib.metadata import (
distribution, entry_points, files, PackageNotFoundError,
version, distributions,
PackageNotFoundError,
distribution,
distributions,
entry_points,
files,
version,
)
from importlib import resources

View File

@ -82,7 +82,7 @@ class NetworkedNNTPTestsMixin:
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)

View File

@ -0,0 +1,51 @@
import unittest
from test import test_tools
test_tools.skip_if_missing('peg_generator')
with test_tools.imports_under_tool('peg_generator'):
from pegen.grammar_parser import GeneratedParser as GrammarParser
from pegen.validator import SubRuleValidator, ValidationError
from pegen.testutil import parse_string
from pegen.grammar import Grammar
class TestPegen(unittest.TestCase):
def test_rule_with_no_collision(self) -> None:
grammar_source = """
start: bad_rule
sum:
| NAME '-' NAME
| NAME '+' NAME
"""
grammar: Grammar = parse_string(grammar_source, GrammarParser)
validator = SubRuleValidator(grammar)
for rule_name, rule in grammar.rules.items():
validator.validate_rule(rule_name, rule)
def test_rule_with_simple_collision(self) -> None:
grammar_source = """
start: bad_rule
sum:
| NAME '+' NAME
| NAME '+' NAME ';'
"""
grammar: Grammar = parse_string(grammar_source, GrammarParser)
validator = SubRuleValidator(grammar)
with self.assertRaises(ValidationError):
for rule_name, rule in grammar.rules.items():
validator.validate_rule(rule_name, rule)
def test_rule_with_collision_after_some_other_rules(self) -> None:
grammar_source = """
start: bad_rule
sum:
| NAME '+' NAME
| NAME '*' NAME ';'
| NAME '-' NAME
| NAME '+' NAME ';'
"""
grammar: Grammar = parse_string(grammar_source, GrammarParser)
validator = SubRuleValidator(grammar)
with self.assertRaises(ValidationError):
for rule_name, rule in grammar.rules.items():
validator.validate_rule(rule_name, rule)

View File

@ -1,4 +1,6 @@
import os
import copy
import pickle
import platform
import subprocess
import sys
@ -234,6 +236,38 @@ class PlatformTest(unittest.TestCase):
)
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):
"""

View File

@ -204,6 +204,16 @@ class PropertyTests(unittest.TestCase):
return 'Second'
self.assertEqual(A.__doc__, 'Second')
def test_property_set_name_incorrect_args(self):
p = property()
for i in (0, 1, 3):
with self.assertRaisesRegex(
TypeError,
fr'^__set_name__\(\) takes 2 positional arguments but {i} were given$'
):
p.__set_name__(*([0] * i))
# Issue 5890: subclasses of property do not preserve method __doc__ strings
class PropertySub(property):
@ -299,6 +309,46 @@ class PropertySubclassTests(unittest.TestCase):
self.assertEqual(Foo.spam.__doc__, "a new docstring")
class _PropertyUnreachableAttribute:
msg_format = None
obj = None
cls = None
def _format_exc_msg(self, msg):
return self.msg_format.format(msg)
@classmethod
def setUpClass(cls):
cls.obj = cls.cls()
def test_get_property(self):
with self.assertRaisesRegex(AttributeError, self._format_exc_msg("unreadable attribute")):
self.obj.foo
def test_set_property(self):
with self.assertRaisesRegex(AttributeError, self._format_exc_msg("can't set attribute")):
self.obj.foo = None
def test_del_property(self):
with self.assertRaisesRegex(AttributeError, self._format_exc_msg("can't delete attribute")):
del self.obj.foo
class PropertyUnreachableAttributeWithName(_PropertyUnreachableAttribute, unittest.TestCase):
msg_format = "^{} 'foo'$"
class cls:
foo = property()
class PropertyUnreachableAttributeNoName(_PropertyUnreachableAttribute, unittest.TestCase):
msg_format = "^{}$"
class cls:
pass
cls.foo = property()
if __name__ == '__main__':
unittest.main()

View File

@ -542,6 +542,34 @@ class SystemRandom_TestBasicOps(TestBasicOps, unittest.TestCase):
raises(0, 42, 0)
raises(0, 42, 3.14159)
def test_randrange_argument_handling(self):
randrange = self.gen.randrange
with self.assertWarns(DeprecationWarning):
randrange(10.0, 20, 2)
with self.assertWarns(DeprecationWarning):
randrange(10, 20.0, 2)
with self.assertWarns(DeprecationWarning):
randrange(10, 20, 1.0)
with self.assertWarns(DeprecationWarning):
randrange(10, 20, 2.0)
with self.assertWarns(DeprecationWarning):
with self.assertRaises(ValueError):
randrange(10.5)
with self.assertWarns(DeprecationWarning):
with self.assertRaises(ValueError):
randrange(10, 20.5)
with self.assertWarns(DeprecationWarning):
with self.assertRaises(ValueError):
randrange(10, 20, 1.5)
def test_randrange_step(self):
# bpo-42772: When stop is None, the step argument was being ignored.
randrange = self.gen.randrange
with self.assertRaises(TypeError):
randrange(1000, step=100)
with self.assertRaises(TypeError):
randrange(1000, None, step=100)
def test_randbelow_logic(self, _log=log, int=int):
# check bitcount transition points: 2**i and 2**(i+1)-1
# show that: k = int(1.001 + _log(n, 2))

View File

@ -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'

View File

@ -1121,9 +1121,11 @@ class GeneralModuleTests(unittest.TestCase):
s_good_values = [0, 1, 2, 0xffff]
l_good_values = s_good_values + [0xffffffff]
l_bad_values = [-1, -2, 1<<32, 1<<1000]
s_bad_values = l_bad_values + [_testcapi.INT_MIN - 1,
_testcapi.INT_MAX + 1]
s_deprecated_values = [1<<16, _testcapi.INT_MAX]
s_bad_values = (
l_bad_values +
[_testcapi.INT_MIN-1, _testcapi.INT_MAX+1] +
[1 << 16, _testcapi.INT_MAX]
)
for k in s_good_values:
socket.ntohs(k)
socket.htons(k)
@ -1136,9 +1138,6 @@ class GeneralModuleTests(unittest.TestCase):
for k in l_bad_values:
self.assertRaises(OverflowError, socket.ntohl, k)
self.assertRaises(OverflowError, socket.htonl, k)
for k in s_deprecated_values:
self.assertWarns(DeprecationWarning, socket.ntohs, k)
self.assertWarns(DeprecationWarning, socket.htons, k)
def testGetServBy(self):
eq = self.assertEqual

View File

@ -277,6 +277,13 @@ class SocketServerTest(unittest.TestCase):
t.join()
s.server_close()
def test_close_immediately(self):
class MyServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
pass
server = MyServer((HOST, 0), lambda: None)
server.server_close()
def test_tcpserver_bind_leak(self):
# Issue #22435: the server socket wouldn't be closed if bind()/listen()
# failed.
@ -491,6 +498,22 @@ class MiscTestCase(unittest.TestCase):
self.assertEqual(server.shutdown_called, 1)
server.server_close()
def test_threads_reaped(self):
"""
In #37193, users reported a memory leak
due to the saving of every request thread. Ensure that
not all threads are kept forever.
"""
class MyServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
pass
server = MyServer((HOST, 0), socketserver.StreamRequestHandler)
for n in range(10):
with socket.create_connection(server.server_address):
server.handle_request()
self.assertLess(len(server._threads), 10)
server.server_close()
if __name__ == "__main__":
unittest.main()

View File

@ -204,6 +204,28 @@ class ProcessTestCase(BaseTestCase):
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:

View File

@ -1329,7 +1329,7 @@ class SizeofTest(unittest.TestCase):
def setx(self, value): self.__x = value
def delx(self): del self.__x
x = property(getx, setx, delx, "")
check(x, size('4Pi'))
check(x, size('5Pi'))
# PyCapsule
# XXX
# rangeiterator

View File

@ -874,6 +874,48 @@ class TraceTestCase(unittest.TestCase):
(5, 'line'),
(5, 'return')])
def test_nested_ifs(self):
def func():
a = b = 1
if a == 1:
if b == 1:
x = 4
else:
y = 6
else:
z = 8
self.run_and_compare(func,
[(0, 'call'),
(1, 'line'),
(2, 'line'),
(3, 'line'),
(4, 'line'),
(4, 'return')])
def test_nested_try_if(self):
def func():
x = "hello"
try:
3/0
except ZeroDivisionError:
if x == 'raise':
raise ValueError() # line 6
f = 7
self.run_and_compare(func,
[(0, 'call'),
(1, 'line'),
(2, 'line'),
(3, 'line'),
(3, 'exception'),
(4, 'line'),
(5, 'line'),
(7, 'line'),
(7, 'return')])
class SkipLineEventsTraceTestCase(TraceTestCase):
"""Repeat the trace tests, but with per-line events skipped"""

View File

@ -138,10 +138,14 @@ class TclTest(unittest.TestCase):
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):
@ -445,7 +449,7 @@ class TclTest(unittest.TestCase):
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):

View File

@ -737,6 +737,16 @@ class TypesTests(unittest.TestCase):
with self.assertRaises(ZeroDivisionError):
list[int] | list[bt]
union_ga = (int | list[str], int | collections.abc.Callable[..., str],
int | d)
# Raise error when isinstance(type, type | genericalias)
for type_ in union_ga:
with self.subTest(f"check isinstance/issubclass is invalid for {type_}"):
with self.assertRaises(TypeError):
isinstance(list, type_)
with self.assertRaises(TypeError):
issubclass(list, type_)
def test_ellipsis_type(self):
self.assertIsInstance(Ellipsis, types.EllipsisType)

View File

@ -3021,6 +3021,7 @@ class GetUtilitiesTestCase(TestCase):
self.assertIs(get_origin(Callable), collections.abc.Callable)
self.assertIs(get_origin(list[int]), list)
self.assertIs(get_origin(list), None)
self.assertIs(get_origin(list | str), types.Union)
def test_get_args(self):
T = TypeVar('T')
@ -3048,6 +3049,16 @@ class GetUtilitiesTestCase(TestCase):
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]))
P = ParamSpec('P')
self.assertEqual(get_args(Callable[P, int]), (P, int))
self.assertEqual(get_args(Callable[Concatenate[int, P], int]),
(Concatenate[int, P], int))
self.assertEqual(get_args(list | str), (list, str))
class CollectionsAbcTests(BaseTestCase):

View File

@ -346,6 +346,31 @@ Now some general starred expressions (all fail).
...
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)"

View File

@ -1851,9 +1851,17 @@ class MiscTests(unittest.TestCase):
('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)

View File

@ -292,7 +292,7 @@ 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 _default_root is None:
if what:
raise RuntimeError(f"Too early to {what}: no default root window")
root = Tk()
@ -300,6 +300,31 @@ def _get_default_root(what=None):
return _default_root
def _get_temp_root():
global _support_default_root
if not _support_default_root:
raise RuntimeError("No master specified and tkinter is "
"configured to not support default root")
root = _default_root
if root is None:
assert _support_default_root
_support_default_root = False
root = Tk()
_support_default_root = True
assert _default_root is None
root.withdraw()
root._temporary = True
return root
def _destroy_temp_root(master):
if getattr(master, '_temporary', False):
try:
master.destroy()
except TclError:
pass
def _tkerror(err):
"""Internal function."""
pass
@ -342,7 +367,7 @@ class Variable:
if name is not None and not isinstance(name, str):
raise TypeError("name must be a string")
global _varnum
if not master:
if master is None:
master = _get_default_root('create variable')
self._root = master._root()
self._tk = master.tk
@ -491,15 +516,11 @@ class Variable:
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):
@ -808,7 +829,7 @@ class Misc:
function which shall be called. Additional parameters
are given as parameters to the function call. Return
identifier to cancel scheduling with after_cancel."""
if not func:
if func is None:
# I'd rather use time.sleep(ms*0.001)
self.tk.call('after', ms)
return None
@ -1542,7 +1563,7 @@ class Misc:
def _root(self):
"""Internal function."""
w = self
while w.master: w = w.master
while w.master is not None: w = w.master
return w
_subst_format = ('%#', '%b', '%f', '%h', '%k',
'%s', '%t', '%w', '%x', '%y',
@ -2306,7 +2327,7 @@ class Tk(Misc, Wm):
self.tk.createcommand('exit', _exit)
self._tclCommands.append('tkerror')
self._tclCommands.append('exit')
if _support_default_root and not _default_root:
if _support_default_root and _default_root is None:
_default_root = self
self.protocol("WM_DELETE_WINDOW", self.destroy)
@ -2534,7 +2555,7 @@ class BaseWidget(Misc):
def _setup(self, master, cnf):
"""Internal function. Sets up information about children."""
if not master:
if master is None:
master = _get_default_root()
self.master = master
self.tk = master.tk
@ -3949,7 +3970,7 @@ class _setit:
def __call__(self, *args):
self.__var.set(self.__value)
if self.__callback:
if self.__callback is not None:
self.__callback(self.__value, *args)
@ -3998,7 +4019,7 @@ class Image:
def __init__(self, imgtype, name=None, cnf={}, master=None, **kw):
self.name = None
if not master:
if master is None:
master = _get_default_root('create image')
self.tk = getattr(master, 'tk', master)
if not name:

View File

@ -10,7 +10,7 @@
__all__ = ["Dialog"]
from tkinter import Frame
from tkinter import Frame, _get_temp_root, _destroy_temp_root
class Dialog:
@ -18,7 +18,7 @@ class Dialog:
command = None
def __init__(self, master=None, **options):
if not master:
if master is None:
master = options.get('parent')
self.master = master
self.options = options
@ -37,22 +37,17 @@ class Dialog:
self._fixoptions()
# we need a dummy widget to properly process the options
# (at least as long as we use Tkinter 1.63)
w = Frame(self.master)
master = self.master
if master is None:
master = _get_temp_root()
try:
s = w.tk.call(self.command, *w._options(self.options))
s = self._fixresult(w, s)
self._test_callback(master) # The function below is replaced for some tests.
s = master.tk.call(self.command, *master._options(self.options))
s = self._fixresult(master, s)
finally:
try:
# get rid of the widget
w.destroy()
except:
pass
_destroy_temp_root(master)
return s
def _test_callback(self, master):
pass

View File

@ -108,7 +108,7 @@ __all__ = ["dnd_start", "DndHandler"]
def dnd_start(source, event):
h = DndHandler(source, event)
if h.root:
if h.root is not None:
return h
else:
return None
@ -143,7 +143,7 @@ class DndHandler:
def __del__(self):
root = self.root
self.root = None
if root:
if root is not None:
try:
del root.__dnd
except AttributeError:
@ -154,25 +154,25 @@ class DndHandler:
target_widget = self.initial_widget.winfo_containing(x, y)
source = self.source
new_target = None
while target_widget:
while target_widget is not None:
try:
attr = target_widget.dnd_accept
except AttributeError:
pass
else:
new_target = attr(source, event)
if new_target:
if new_target is not None:
break
target_widget = target_widget.master
old_target = self.target
if old_target is new_target:
if old_target:
if old_target is not None:
old_target.dnd_motion(source, event)
else:
if old_target:
if old_target is not None:
self.target = None
old_target.dnd_leave(source, event)
if new_target:
if new_target is not None:
new_target.dnd_enter(source, event)
self.target = new_target
@ -193,7 +193,7 @@ class DndHandler:
self.initial_widget.unbind("<Motion>")
widget['cursor'] = self.save_cursor
self.target = self.source = self.initial_widget = self.root = None
if target:
if target is not None:
if commit:
target.dnd_commit(source, event)
else:
@ -215,9 +215,9 @@ class Icon:
if canvas is self.canvas:
self.canvas.coords(self.id, x, y)
return
if self.canvas:
if self.canvas is not None:
self.detach()
if not canvas:
if canvas is None:
return
label = tkinter.Label(canvas, text=self.name,
borderwidth=2, relief="raised")
@ -229,7 +229,7 @@ class Icon:
def detach(self):
canvas = self.canvas
if not canvas:
if canvas is None:
return
id = self.id
label = self.label

View File

@ -17,10 +17,10 @@ BOLD = "bold"
ITALIC = "italic"
def nametofont(name):
def nametofont(name, root=None):
"""Given the name of a tk named font, returns a Font representation.
"""
return Font(name=name, exists=True)
return Font(name=name, exists=True, root=root)
class Font:
@ -68,7 +68,7 @@ class Font:
def __init__(self, root=None, font=None, name=None, exists=False,
**options):
if not root:
if root is None:
root = tkinter._get_default_root('use font')
tk = getattr(root, 'tk', root)
if font:
@ -107,7 +107,7 @@ class Font:
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)
@ -183,7 +183,7 @@ class Font:
def families(root=None, displayof=None):
"Get font families (as a tuple)"
if not root:
if root is None:
root = tkinter._get_default_root('use font.families()')
args = ()
if displayof:
@ -193,7 +193,7 @@ def families(root=None, displayof=None):
def names(root=None):
"Get names of defined fonts (as a tuple)"
if not root:
if root is None:
root = tkinter._get_default_root('use font.names()')
return root.tk.splitlist(root.tk.call("font", "names"))

View File

@ -24,7 +24,8 @@ askstring -- get a string from the user
"""
from tkinter import *
from tkinter import messagebox, _get_default_root
from tkinter import _get_temp_root, _destroy_temp_root
from tkinter import messagebox
class SimpleDialog:
@ -55,36 +56,8 @@ class SimpleDialog:
b.config(relief=RIDGE, borderwidth=8)
b.pack(side=LEFT, fill=BOTH, expand=1)
self.root.protocol('WM_DELETE_WINDOW', self.wm_delete_window)
self._set_transient(master)
def _set_transient(self, master, relx=0.5, rely=0.3):
widget = self.root
widget.withdraw() # Remain invisible while we figure out the geometry
widget.transient(master)
widget.update_idletasks() # Actualize geometry information
if master.winfo_ismapped():
m_width = master.winfo_width()
m_height = master.winfo_height()
m_x = master.winfo_rootx()
m_y = master.winfo_rooty()
else:
m_width = master.winfo_screenwidth()
m_height = master.winfo_screenheight()
m_x = m_y = 0
w_width = widget.winfo_reqwidth()
w_height = widget.winfo_reqheight()
x = m_x + (m_width - w_width) * relx
y = m_y + (m_height - w_height) * rely
if x+w_width > master.winfo_screenwidth():
x = master.winfo_screenwidth() - w_width
elif x < 0:
x = 0
if y+w_height > master.winfo_screenheight():
y = master.winfo_screenheight() - w_height
elif y < 0:
y = 0
widget.geometry("+%d+%d" % (x, y))
widget.deiconify() # Become visible at the desired location
self.root.transient(master)
_place_window(self.root, master)
def go(self):
self.root.wait_visibility()
@ -127,8 +100,8 @@ class Dialog(Toplevel):
title -- the dialog title
'''
master = parent
if not master:
master = _get_default_root('create dialog window')
if master is None:
master = _get_temp_root()
Toplevel.__init__(self, master)
@ -152,16 +125,12 @@ class Dialog(Toplevel):
self.buttonbox()
if not self.initial_focus:
if self.initial_focus is None:
self.initial_focus = self
self.protocol("WM_DELETE_WINDOW", self.cancel)
if parent is not None:
self.geometry("+%d+%d" % (parent.winfo_rootx()+50,
parent.winfo_rooty()+50))
self.deiconify() # become visible now
_place_window(self, parent)
self.initial_focus.focus_set()
@ -174,6 +143,7 @@ class Dialog(Toplevel):
'''Destroy the window'''
self.initial_focus = None
Toplevel.destroy(self)
_destroy_temp_root(self.master)
#
# construction hooks
@ -251,6 +221,37 @@ class Dialog(Toplevel):
pass # override
# Place a toplevel window at the center of parent or screen
# It is a Python implementation of ::tk::PlaceWindow.
def _place_window(w, parent=None):
w.wm_withdraw() # Remain invisible while we figure out the geometry
w.update_idletasks() # Actualize geometry information
minwidth = w.winfo_reqwidth()
minheight = w.winfo_reqheight()
maxwidth = w.winfo_vrootwidth()
maxheight = w.winfo_vrootheight()
if parent is not None and parent.winfo_ismapped():
x = parent.winfo_rootx() + (parent.winfo_width() - minwidth) // 2
y = parent.winfo_rooty() + (parent.winfo_height() - minheight) // 2
vrootx = w.winfo_vrootx()
vrooty = w.winfo_vrooty()
x = min(x, vrootx + maxwidth - minwidth)
x = max(x, vrootx)
y = min(y, vrooty + maxheight - minheight)
y = max(y, vrooty)
if w._windowingsystem == 'aqua':
# Avoid the native menu bar which sits on top of everything.
y = max(y, 22)
else:
x = (w.winfo_screenwidth() - minwidth) // 2
y = (w.winfo_screenheight() - minheight) // 2
w.wm_maxsize(maxwidth, maxheight)
w.wm_geometry('+%d+%d' % (x, y))
w.wm_deiconify() # Become visible at the desired location
# --------------------------------------------------------------------
# convenience dialogues

View File

@ -0,0 +1,39 @@
import unittest
import tkinter
from test.support import requires, run_unittest, swap_attr
from tkinter.test.support import AbstractDefaultRootTest
from tkinter.commondialog import Dialog
from tkinter.colorchooser import askcolor
requires('gui')
class DefaultRootTest(AbstractDefaultRootTest, unittest.TestCase):
def test_askcolor(self):
def test_callback(dialog, master):
nonlocal ismapped
master.update()
ismapped = master.winfo_ismapped()
raise ZeroDivisionError
with swap_attr(Dialog, '_test_callback', test_callback):
ismapped = None
self.assertRaises(ZeroDivisionError, askcolor)
#askcolor()
self.assertEqual(ismapped, False)
root = tkinter.Tk()
ismapped = None
self.assertRaises(ZeroDivisionError, askcolor)
self.assertEqual(ismapped, True)
root.destroy()
tkinter.NoDefaultRoot()
self.assertRaises(RuntimeError, askcolor)
tests_gui = (DefaultRootTest,)
if __name__ == "__main__":
run_unittest(*tests_gui)

View File

@ -63,15 +63,22 @@ class FontTest(AbstractTkTest, unittest.TestCase):
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)
@ -101,6 +108,11 @@ class FontTest(AbstractTkTest, unittest.TestCase):
self.assertTrue(name)
self.assertIn(fontname, names)
def test_nametofont(self):
testfont = font.nametofont(fontname, root=self.root)
self.assertIsInstance(testfont, font.Font)
self.assertEqual(testfont.name, fontname)
def test_repr(self):
self.assertEqual(
repr(self.font), f'<tkinter.font.Font object {fontname!r}>'
@ -136,6 +148,16 @@ class DefaultRootTest(AbstractDefaultRootTest, unittest.TestCase):
tkinter.NoDefaultRoot()
self.assertRaises(RuntimeError, font.names)
def test_nametofont(self):
self.assertRaises(RuntimeError, font.nametofont, fontname)
root = tkinter.Tk()
testfont = font.nametofont(fontname)
self.assertIsInstance(testfont, font.Font)
self.assertEqual(testfont.name, fontname)
root.destroy()
tkinter.NoDefaultRoot()
self.assertRaises(RuntimeError, font.nametofont, fontname)
tests_gui = (FontTest, DefaultRootTest)

View File

@ -0,0 +1,38 @@
import unittest
import tkinter
from test.support import requires, run_unittest, swap_attr
from tkinter.test.support import AbstractDefaultRootTest
from tkinter.commondialog import Dialog
from tkinter.messagebox import showinfo
requires('gui')
class DefaultRootTest(AbstractDefaultRootTest, unittest.TestCase):
def test_showinfo(self):
def test_callback(dialog, master):
nonlocal ismapped
master.update()
ismapped = master.winfo_ismapped()
raise ZeroDivisionError
with swap_attr(Dialog, '_test_callback', test_callback):
ismapped = None
self.assertRaises(ZeroDivisionError, showinfo, "Spam", "Egg Information")
self.assertEqual(ismapped, False)
root = tkinter.Tk()
ismapped = None
self.assertRaises(ZeroDivisionError, showinfo, "Spam", "Egg Information")
self.assertEqual(ismapped, True)
root.destroy()
tkinter.NoDefaultRoot()
self.assertRaises(RuntimeError, showinfo, "Spam", "Egg Information")
tests_gui = (DefaultRootTest,)
if __name__ == "__main__":
run_unittest(*tests_gui)

View File

@ -10,13 +10,25 @@ 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()):
@staticmethod
def mock_wait_window(w):
nonlocal ismapped
ismapped = w.master.winfo_ismapped()
w.destroy()
with swap_attr(Dialog, 'wait_window', mock_wait_window):
ismapped = None
askinteger("Go To Line", "Line number")
root.destroy()
tkinter.NoDefaultRoot()
self.assertRaises(RuntimeError, askinteger, "Go To Line", "Line number")
self.assertEqual(ismapped, False)
root = tkinter.Tk()
ismapped = None
askinteger("Go To Line", "Line number")
self.assertEqual(ismapped, True)
root.destroy()
tkinter.NoDefaultRoot()
self.assertRaises(RuntimeError, askinteger, "Go To Line", "Line number")
tests_gui = (DefaultRootTest,)

View File

@ -58,22 +58,32 @@ class TestVariable(TestBase):
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)

View File

@ -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 @@ class AbstractToplevelTest(AbstractWidgetTest, PixelSizeTests):
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 @@ class AbstractToplevelTest(AbstractWidgetTest, PixelSizeTests):
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 @@ class AbstractToplevelTest(AbstractWidgetTest, PixelSizeTests):
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 @@ class ToplevelTest(AbstractToplevelTest, unittest.TestCase):
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 @@ class LabelFrameTest(AbstractToplevelTest, unittest.TestCase):
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 @@ class CheckbuttonTest(AbstractLabelTest, unittest.TestCase):
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 @@ class MenubuttonTest(AbstractLabelTest, unittest.TestCase):
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 @@ class EntryTest(AbstractWidgetTest, unittest.TestCase):
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 @@ class SpinboxTest(EntryTest, unittest.TestCase):
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 @@ class SpinboxTest(EntryTest, unittest.TestCase):
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 @@ class TextTest(AbstractWidgetTest, unittest.TestCase):
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 @@ class TextTest(AbstractWidgetTest, unittest.TestCase):
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 @@ class TextTest(AbstractWidgetTest, unittest.TestCase):
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 @@ class CanvasTest(AbstractWidgetTest, unittest.TestCase):
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 @@ class CanvasTest(AbstractWidgetTest, unittest.TestCase):
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)

View File

@ -16,7 +16,7 @@ requires('gui')
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 @@ class StandardTtkOptionsTests(StandardOptionsTests):
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 @@ class StandardTtkOptionsTests(StandardOptionsTests):
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 @@ class AbstractLabelTest(AbstractWidgetTest):
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 @@ class EntryTest(AbstractWidgetTest, unittest.TestCase):
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 @@ class ComboboxTest(EntryTest, unittest.TestCase):
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 @@ class ComboboxTest(EntryTest, unittest.TestCase):
self.assertTrue(success)
def test_postcommand(self):
def test_configure_postcommand(self):
success = []
self.combo['postcommand'] = lambda: success.append(True)
@ -475,7 +475,7 @@ class ComboboxTest(EntryTest, unittest.TestCase):
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 @@ class PanedWindowTest(AbstractWidgetTest, unittest.TestCase):
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 @@ class MenubuttonTest(AbstractLabelTest, unittest.TestCase):
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 @@ class ScaleTest(AbstractWidgetTest, unittest.TestCase):
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 @@ class NotebookTest(AbstractWidgetTest, unittest.TestCase):
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 @@ class SpinboxTest(EntryTest, unittest.TestCase):
self.spin.event_generate('<ButtonRelease-1>', 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 @@ class SpinboxTest(EntryTest, unittest.TestCase):
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 @@ class SpinboxTest(EntryTest, unittest.TestCase):
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 @@ class SpinboxTest(EntryTest, unittest.TestCase):
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 @@ class SpinboxTest(EntryTest, unittest.TestCase):
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 @@ class SpinboxTest(EntryTest, unittest.TestCase):
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 @@ class SpinboxTest(EntryTest, unittest.TestCase):
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 @@ class TreeviewTest(AbstractWidgetTest, unittest.TestCase):
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 @@ class TreeviewTest(AbstractWidgetTest, unittest.TestCase):
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'))

View File

@ -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 @@ class StandardOptionsTests:
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 @@ class StandardOptionsTests:
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):

View File

@ -386,7 +386,7 @@ class TixWidget(tkinter.Widget):
self.tk.call(name, 'configure', '-' + option, value)
# These are missing from Tkinter
def image_create(self, imgtype, cnf={}, master=None, **kw):
if not master:
if master is None:
master = self
if kw and cnf: cnf = _cnfmerge((cnf, kw))
elif kw: cnf = kw
@ -467,7 +467,7 @@ class DisplayStyle:
(multiple) Display Items"""
def __init__(self, itemtype, cnf={}, *, master=None, **kw):
if not master:
if master is None:
if 'refwindow' in kw:
master = kw['refwindow']
elif 'refwindow' in cnf:
@ -862,7 +862,7 @@ class HList(TixWidget, XView, YView):
return self.tk.call(self._w, 'add', entry, *self._options(cnf, kw))
def add_child(self, parent=None, cnf={}, **kw):
if not parent:
if parent is None:
parent = ''
return self.tk.call(
self._w, 'addchild', parent, *self._options(cnf, kw))

View File

@ -569,7 +569,7 @@ class Widget(tkinter.Widget):
matches statespec. statespec is expected to be a sequence."""
ret = self.tk.getboolean(
self.tk.call(self._w, "instate", ' '.join(statespec)))
if ret and callback:
if ret and callback is not None:
return callback(*args, **kw)
return ret

View File

@ -544,8 +544,9 @@ def TypeAlias(self, parameters):
@_SpecialForm
def Concatenate(self, parameters):
"""Used in conjunction with ParamSpec and Callable to represent a higher
order function which adds, removes or transforms parameters of a Callable.
"""Used in conjunction with ``ParamSpec`` and ``Callable`` to represent a
higher order function which adds, removes or transforms parameters of a
callable.
For example::
@ -735,11 +736,11 @@ class ParamSpec(_Final, _Immutable, _TypeVarLike, _root=True):
Parameter specification variables exist primarily for the benefit of static
type checkers. They are used to forward the parameter types of one
Callable to another Callable, a pattern commonly found in higher order
functions and decorators. They are only valid when used in Concatenate, or
as the first argument to Callable, or as parameters for user-defined Generics.
See class Generic for more information on generic types. An example for
annotating a decorator::
callable to another callable, a pattern commonly found in higher order
functions and decorators. They are only valid when used in ``Concatenate``,
or s the first argument to ``Callable``, or as parameters for user-defined
Generics. See class Generic for more information on generic types. An
example for annotating a decorator::
T = TypeVar('T')
P = ParamSpec('P')
@ -1249,7 +1250,7 @@ def _no_init(self, *args, **kwargs):
raise TypeError('Protocols cannot be instantiated')
def _allow_reckless_class_cheks():
def _allow_reckless_class_checks():
"""Allow instance and class checks for special stdlib modules.
The abc and functools modules indiscriminately call isinstance() and
@ -1338,12 +1339,12 @@ class Protocol(Generic, metaclass=_ProtocolMeta):
# First, perform various sanity checks.
if not getattr(cls, '_is_runtime_protocol', False):
if _allow_reckless_class_cheks():
if _allow_reckless_class_checks():
return NotImplemented
raise TypeError("Instance and class checks can only be used with"
" @runtime_checkable protocols")
if not _is_callable_members_only(cls):
if _allow_reckless_class_cheks():
if _allow_reckless_class_checks():
return NotImplemented
raise TypeError("Protocols with non-method members"
" don't support issubclass()")
@ -1668,6 +1669,8 @@ def get_origin(tp):
return tp.__origin__
if tp is Generic:
return Generic
if isinstance(tp, types.Union):
return types.Union
return None
@ -1684,12 +1687,14 @@ 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:
if (tp.__origin__ is collections.abc.Callable
and not (res[0] is Ellipsis
or isinstance(res[0], (ParamSpec, _ConcatenateGenericAlias)))):
res = (list(res[:-1]), res[-1])
return res
if isinstance(tp, GenericAlias):
if isinstance(tp, types.Union):
return tp.__args__
return ()

View File

@ -773,7 +773,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]

View File

@ -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",
],
),
])
@ -263,10 +260,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 = [ ]
@ -357,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 '
@ -1138,7 +1135,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)
@ -1615,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

View File

@ -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"

View File

@ -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"
;;

View File

@ -36,7 +36,7 @@
<key>CFBundleExecutable</key>
<string>IDLE</string>
<key>CFBundleGetInfoString</key>
<string>%version%, © 2001-2020 Python Software Foundation</string>
<string>%version%, © 2001-2021 Python Software Foundation</string>
<key>CFBundleIconFile</key>
<string>IDLE.icns</string>
<key>CFBundleIdentifier</key>

View File

@ -40,7 +40,7 @@
<key>CFBundleExecutable</key>
<string>Python Launcher</string>
<key>CFBundleGetInfoString</key>
<string>%VERSION%, © 2001-2020 Python Software Foundation</string>
<string>%VERSION%, © 2001-2021 Python Software Foundation</string>
<key>CFBundleIconFile</key>
<string>PythonLauncher.icns</string>
<key>CFBundleIdentifier</key>

Some files were not shown because too many files have changed in this diff Show More