Compare commits

..

1 Commits

Author SHA1 Message Date
Ethan Furman 630d2e14c5 Revert "[Enum] EnumMeta.__prepare__ now accepts **kwds (#23917)"
This reverts commit 6ec0adefad.
2020-12-24 10:05:17 -08:00
221 changed files with 5509 additions and 9098 deletions

View File

@ -1,19 +0,0 @@
{
"__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,8 +99,6 @@ 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-2021 Python Software Foundation. All rights reserved.
Copyright © 2001-2020 Python Software Foundation. All rights reserved.
Copyright © 2000 BeOpen.com. All rights reserved.

View File

@ -934,42 +934,32 @@ 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(f'unreadable attribute {self._name}')
raise AttributeError("unreadable attribute")
return self.fget(obj)
def __set__(self, obj, value):
if self.fset is None:
raise AttributeError(f"can't set attribute {self._name}")
raise AttributeError("can't set attribute")
self.fset(obj, value)
def __delete__(self, obj):
if self.fdel is None:
raise AttributeError(f"can't delete attribute {self._name}")
raise AttributeError("can't delete attribute")
self.fdel(obj)
def getter(self, fget):
prop = type(self)(fget, self.fset, self.fdel, self.__doc__)
prop._name = self._name
return prop
return type(self)(fget, self.fset, self.fdel, self.__doc__)
def setter(self, fset):
prop = type(self)(self.fget, fset, self.fdel, self.__doc__)
prop._name = self._name
return prop
return type(self)(self.fget, fset, self.fdel, self.__doc__)
def deleter(self, fdel):
prop = type(self)(self.fget, self.fset, fdel, self.__doc__)
prop._name = self._name
return prop
return type(self)(self.fget, self.fset, fdel, self.__doc__)
.. testcode::
:hide:

View File

@ -112,15 +112,14 @@ 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 ``COLORS - 1``. Return a 3-tuple,
*color_number*, which must be between ``0`` and :const:`COLORS`. 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(pair_number)
.. function:: color_pair(color_number)
Return the attribute value for displaying text in the specified color pair.
Only the first 256 color pairs are supported. This
Return the attribute value for displaying text in the specified color. 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.
@ -288,7 +287,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
`COLORS - 1`. Each of *r*, *g*, *b*, must be a value between ``0`` and
:const:`COLORS`. 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``.
@ -301,8 +300,7 @@ 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
``COLORS - 1``, or, after calling :func:`use_default_colors`, ``-1``.
If the color-pair was previously initialized, the screen is
:const:`COLORS`. If the color-pair was previously initialized, the screen is
refreshed and all occurrences of that color-pair are changed to the new
definition.
@ -452,7 +450,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 ``0`` and ``COLOR_PAIRS - 1``.
The value of *pair_number* must be between ``1`` 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,26 +62,16 @@ The :mod:`functools` module defines the following functions:
Example::
class DataSet:
def __init__(self, sequence_of_numbers):
self._data = tuple(sequence_of_numbers)
self._data = sequence_of_numbers
@cached_property
def stdev(self):
return statistics.stdev(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.
@cached_property
def variance(self):
return statistics.variance(self._data)
Note, this decorator interferes with the operation of :pep:`412`
key-sharing dictionaries. This means that instance dictionaries

View File

@ -115,9 +115,8 @@ Every distribution includes some metadata, which you can extract using the
>>> wheel_metadata = metadata('wheel') # doctest: +SKIP
The keys of the returned data structure, a ``PackageMetadata``,
name the metadata keywords, and
the values are returned unparsed from the distribution metadata::
The keys of the returned data structure [#f1]_ name the metadata keywords, and
their values are returned unparsed from the distribution metadata::
>>> wheel_metadata['Requires-Python'] # doctest: +SKIP
'>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*'
@ -207,9 +206,9 @@ Thus, an alternative way to get the version number is through the
There are all kinds of additional metadata available on the ``Distribution``
instance::
>>> dist.metadata['Requires-Python'] # doctest: +SKIP
>>> d.metadata['Requires-Python'] # doctest: +SKIP
'>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*'
>>> dist.metadata['License'] # doctest: +SKIP
>>> d.metadata['License'] # doctest: +SKIP
'MIT'
The full set of available metadata is not described here. See :pep:`566`
@ -260,3 +259,9 @@ 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,18 +786,6 @@ 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 string descriptions to their error codes.
A dictionary mapping numeric error codes to their string descriptions.
.. versionadded:: 3.2
.. data:: messages
A dictionary mapping numeric error codes to their string descriptions.
A dictionary mapping string descriptions to their error codes.
.. versionadded:: 3.2

View File

@ -135,15 +135,6 @@ 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,9 +907,11 @@ 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.
.. versionchanged:: 3.10
Raises :exc:`OverflowError` if *x* does not fit in a 16-bit unsigned
integer.
.. 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.
.. function:: htonl(x)
@ -925,9 +927,11 @@ 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.
.. versionchanged:: 3.10
Raises :exc:`OverflowError` if *x* does not fit in a 16-bit unsigned
integer.
.. 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.
.. function:: inet_aton(ip_string)

View File

@ -546,7 +546,7 @@ Connection Objects
con.close()
.. method:: backup(target, *, pages=-1, progress=None, name="main", sleep=0.250)
.. method:: backup(target, *, pages=0, 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.10
.. versionchanged:: 3.8
Added support for *weights*.
.. function:: median(data)

View File

@ -4959,11 +4959,6 @@ 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,9 +1187,8 @@ 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.
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.
However, explicitly passing ``input=None`` to inherit the parent's
standard input file handle is not supported.
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,8 +160,6 @@ 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,9 +91,6 @@ The different font weights and slants are:
Return the names of defined fonts.
.. function:: nametofont(name, root=None)
.. function:: nametofont(name)
Return a :class:`Font` representation of a tk named font.
.. versionchanged:: 3.10
The *root* parameter was added.
Return a :class:`Font` representation of a tk named font.

View File

@ -18,8 +18,7 @@
--------------
This module provides runtime support for type hints as specified by
:pep:`484`, :pep:`526`, :pep:`544`, :pep:`586`, :pep:`589`, :pep:`591`,
:pep:`612` and :pep:`613`.
:pep:`484`, :pep:`526`, :pep:`544`, :pep:`586`, :pep:`589`, :pep:`591`, 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
@ -172,22 +171,6 @@ 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
@ -333,43 +316,6 @@ 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
@ -656,80 +602,10 @@ 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
@ -1000,84 +876,6 @@ 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-2021 Python Software Foundation; All Rights
copyright, i.e., "Copyright © 2001-2020 Python Software Foundation; All Rights
Reserved" are retained in Python |release| alone or in any derivative version
prepared by Licensee.

View File

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

View File

@ -144,28 +144,6 @@ 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
======================
@ -426,11 +404,9 @@ 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. 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.)
* 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.)
* When building Python with ``--enable-optimizations`` now
``-fno-semantic-interposition`` is added to both the compile and link line.
@ -561,12 +537,6 @@ 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
========================
@ -588,10 +558,6 @@ 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,37 +1482,4 @@ 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`.)
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`.)
(Contributed by Yurii Karabas in :issue:`42345`.)

View File

@ -580,23 +580,18 @@ 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_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_targets_seq[asdl_expr_seq*]: a[asdl_expr_seq*]=','.star_target+ [','] { 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=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) }
| '(' 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) }
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);
memcpy(&ptr, (char *) callable + offset, sizeof(ptr));
return ptr;
ptr = (vectorcallfunc *)(((char *)callable) + offset);
return *ptr;
}
/* Call the callable object 'callable' with the "vectorcall" calling

View File

@ -35,13 +35,12 @@ 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;
// Index in PyInterpreterState.unicode.ids.array. It is process-wide
// unique and must be initialized to -1.
Py_ssize_t index;
PyObject *object;
} _Py_Identifier;
#define _Py_static_string_init(value) { .string = value, .index = -1 }
#define _Py_static_string_init(value) { .next = NULL, .string = value, .object = NULL }
#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,11 +64,6 @@ 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;
@ -76,19 +71,6 @@ 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 {
@ -191,27 +173,6 @@ 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
@ -316,7 +277,6 @@ 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,9 +27,6 @@ _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(PyThreadState *tstate);
extern void _PyType_Fini(void);
extern void _Py_HashRandomization_Fini(void);
extern void _PyUnicode_Fini(PyThreadState *tstate);
extern void _PyUnicode_ClearInterned(PyThreadState *tstate);

View File

@ -49,11 +49,6 @@ 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 {
@ -111,8 +106,6 @@ 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 4
#define PY_RELEASE_SERIAL 3
/* Version as a string */
#define PY_VERSION "3.10.0a4+"
#define PY_VERSION "3.10.0a3+"
/*--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, 2021 Python Software Foundation;
2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020 Python Software Foundation;
All Rights Reserved" are retained in Python alone or in any derivative version
prepared by Licensee.

View File

@ -63,10 +63,7 @@ def literal_eval(node_or_string):
if isinstance(node_or_string, Expression):
node_or_string = node_or_string.body
def _raise_malformed_node(node):
msg = "malformed node or string"
if lno := getattr(node, 'lineno', None):
msg += f' on line {lno}'
raise ValueError(msg + f': {node!r}')
raise ValueError(f'malformed node or string: {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 _a85chars2 is None:
if _a85chars 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 _b85chars2 is None:
if _b85chars 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, **kwds):
def __prepare__(metacls, cls, bases):
# 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 = super().__new__(metacls, cls, bases, classdict, **kwds)
enum_class = type.__new__(metacls, cls, bases, classdict)
enum_class.__bases__ = enum_class.__bases__[1:] #or (object, )
else:
enum_class = super().__new__(metacls, cls, bases, classdict, **kwds)
enum_class = type.__new__(metacls, cls, bases, classdict)
old_init_subclass = getattr(enum_class, '__init_subclass__', None)
# and restore the new one (if there was one)
if new_init_subclass is not None:

View File

@ -3,9 +3,6 @@ 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,15 +2316,7 @@ 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. <<z-in>>, and
corresponding methods, e.g. z_in_event(). The virtual events will be
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
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 partial example from zzdummy.py:
Here is a complete example:
class ZzDummy:
class ZoomHeight:
menudefs = [
('format', [
('Z in', '<<z-in>>'),
('Z out', '<<z-out>>'),
] )
('edit', [
None, # Separator
('_Zoom Height', '<<zoom-height>>'),
])
]
def __init__(self, editwin):
self.editwin = editwin
def z_in_event(self, event=None):
def zoom_height_event(self, event):
"...Do what you want here..."
The final piece of the puzzle is the file "config-extensions.def", which is

View File

@ -1,152 +0,0 @@
"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,73 +1,42 @@
"""Example extension, also used for testing.
See extend.txt for more details on creating an extension.
See config-extension.def for configuring an extension.
"""
"Example extension, also used for testing."
from idlelib.config import idleConf
from functools import wraps
def format_selection(format_line):
"Apply a formatting function to all of the selected lines."
@wraps(format_line)
def apply(self, event=None):
head, tail, chars, lines = self.formatter.get_region()
for pos in range(len(lines) - 1):
line = lines[pos]
lines[pos] = format_line(self, line)
self.formatter.set_region(head, tail, chars, lines)
return 'break'
return apply
ztext = idleConf.GetOption('extensions', 'ZzDummy', 'z-text')
class ZzDummy:
"""Prepend or remove initial text from selected lines."""
# Extend the format menu.
menudefs = [
('format', [
('Z in', '<<z-in>>'),
('Z out', '<<z-out>>'),
] )
]
## 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
self.formatter = editwin.fregion
z_in = False
@classmethod
def reload(cls):
"Load class variables from config."
cls.ztext = idleConf.GetOption('extensions', 'ZzDummy', 'z-text')
@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.
def z_in_event(self, event):
"""
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:]
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"
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,3 +1,4 @@
import io
import os
import re
import abc
@ -17,7 +18,6 @@ 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,8 +77,6 @@ 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,
@ -106,27 +104,23 @@ 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
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
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)
def __iter__(self):
"""
@ -138,7 +132,7 @@ class EntryPoint(
return (
self.__class__,
(self.name, self.value, self.group),
)
)
class PackagePath(pathlib.PurePosixPath):
@ -165,25 +159,6 @@ 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."""
@ -235,8 +210,9 @@ 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):
@ -251,24 +227,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) -> PackageMetadata:
def metadata(self):
"""Return the parsed metadata for this Distribution.
The returned object will have keys that name the various bits of
@ -281,14 +257,9 @@ 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."""
@ -296,7 +267,7 @@ class Distribution:
@property
def entry_points(self):
return list(EntryPoint._from_text_for(self.read_text('entry_points.txt'), self))
return EntryPoint._from_text(self.read_text('entry_points.txt'))
@property
def files(self):
@ -353,10 +324,9 @@ 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
@ -380,7 +350,6 @@ 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)
@ -469,69 +438,48 @@ 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)
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'))
def search(self, name):
return (
self.joinpath(child)
for child in self.children()
if name.matches(child, self.base)
)
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)
class Prepared:
"""
A prepared search for metadata on a possibly-named package.
"""
normalized = None
normalized = ''
prefix = ''
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 = 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')
)
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'
class MetadataPathFinder(DistributionFinder):
@ -552,8 +500,9 @@ 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):
@ -566,15 +515,9 @@ 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):
@ -598,11 +541,11 @@ def distributions(**kwargs):
return Distribution.discover(**kwargs)
def metadata(distribution_name) -> PackageMetadata:
def metadata(distribution_name):
"""Get the metadata for the named package.
:param distribution_name: The name of the distribution package to query.
:return: A PackageMetadata containing the parsed metadata.
:return: An email.Message containing the parsed metadata.
"""
return Distribution.from_name(distribution_name).metadata
@ -622,11 +565,15 @@ 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 not executable:
if executable is None:
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 'processor' is
simple namedtuple except that 'platform' is
resolved late and cached to avoid calling "uname"
except when needed.
"""
@ -784,25 +784,12 @@ 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(self)[key]
return tuple(iter(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 Jan 4 17:25:50 2021
# Autogenerated by Sphinx on Mon Dec 7 19:34:00 2020
topics = {'assert': 'The "assert" statement\n'
'**********************\n'
'\n'
@ -461,12 +461,13 @@ topics = {'assert': 'The "assert" statement\n'
'\n'
' async_for_stmt ::= "async" for_stmt\n'
'\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'
'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'
'\n'
'The "async for" statement allows convenient iteration over\n'
'asynchronous iterables.\n'
'asynchronous iterators.\n'
'\n'
'The following code:\n'
'\n'
@ -2382,9 +2383,8 @@ 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 that is the class or a '
'base\n'
'class of the exception object.\n'
'object or a tuple containing an item compatible with the '
'exception.\n'
'\n'
'If no except clause matches the exception, the search for an '
'exception\n'
@ -2451,32 +2451,11 @@ topics = {'assert': 'The "assert" statement\n'
'(see\n'
'section The standard type hierarchy) identifying the point in '
'the\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'
'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'
'\n'
'The optional "else" clause is executed if the control flow '
'leaves the\n'
@ -3006,12 +2985,13 @@ topics = {'assert': 'The "assert" statement\n'
'\n'
' async_for_stmt ::= "async" for_stmt\n'
'\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'
'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'
'\n'
'The "async for" statement allows convenient iteration over\n'
'asynchronous iterables.\n'
'asynchronous iterators.\n'
'\n'
'The following code:\n'
'\n'
@ -5544,51 +5524,44 @@ topics = {'assert': 'The "assert" statement\n'
' | | formats the result in either fixed-point '
'format or in |\n'
' | | scientific notation, depending on its '
'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'
'magnitude. The |\n'
' | | precise rules are as follows: suppose that '
'the result |\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". 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'
' | | "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'
' '
'+-----------+------------------------------------------------------------+\n'
' | "\'G\'" | General format. Same as "\'g\'" except '
@ -5613,24 +5586,19 @@ topics = {'assert': 'The "assert" statement\n'
'percent sign. |\n'
' '
'+-----------+------------------------------------------------------------+\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'
' | 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'
' '
'+-----------+------------------------------------------------------------+\n'
'\n'
@ -6004,10 +5972,8 @@ topics = {'assert': 'The "assert" statement\n'
'\n'
'Names listed in a "global" statement must not be defined as '
'formal\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'
'parameters or in a "for" loop control target, "class" definition,\n'
'function definition, "import" statement, or variable annotation.\n'
'\n'
'**CPython implementation detail:** The current implementation does '
'not\n'
@ -7959,7 +7925,7 @@ topics = {'assert': 'The "assert" statement\n'
'immediate\n'
' subclasses. This method returns a list of all those '
'references\n'
' still alive. The list is in definition order. Example:\n'
' still alive. Example:\n'
'\n'
' >>> int.__subclasses__()\n'
" [<class 'bool'>]\n"
@ -11258,8 +11224,7 @@ 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 that is the class or a base\n'
'class of the exception object.\n'
'object or a tuple containing an item compatible with the exception.\n'
'\n'
'If no except clause matches the exception, the search for an '
'exception\n'
@ -11314,31 +11279,9 @@ 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. 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'
'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'
'\n'
'The optional "else" clause is executed if the control flow leaves '
'the\n'
@ -11502,6 +11445,7 @@ 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,7 +51,6 @@ 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
@ -96,7 +95,6 @@ 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):
@ -289,7 +287,7 @@ class Random(_random.Random):
## -------------------- integer methods -------------------
def randrange(self, start, stop=None, step=_ONE):
def randrange(self, start, stop=None, step=1):
"""Choose a random item from range(start, stop[, step]).
This fixes the problem with randint() which includes the
@ -299,72 +297,38 @@ class Random(_random.Random):
# This code is a bit messy to make it fast for the
# common case while still doing adequate error checking.
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()")
istart = int(start)
if istart != start:
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.
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()")
istop = int(stop)
if istop != stop:
raise ValueError("non-integer stop for randrange()")
width = istop - istart
if istep == 1:
if width > 0:
return istart + self._randbelow(width)
if step == 1 and width > 0:
return istart + self._randbelow(width)
if step == 1:
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,8 +1082,7 @@ class LMTP(SMTP):
# Handle Unix-domain sockets.
try:
self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
if self.timeout is not socket._GLOBAL_DEFAULT_TIMEOUT:
self.sock.settimeout(self.timeout)
self.sock.settimeout(self.timeout)
self.file = None
self.sock.connect(host)
except OSError:

View File

@ -628,39 +628,6 @@ 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."""
@ -669,9 +636,9 @@ class ThreadingMixIn:
daemon_threads = False
# If true, server_close() waits until all non-daemonic threads terminate.
block_on_close = True
# Threads object
# For non-daemonic threads, list of threading.Threading objects
# used by server_close() to wait for all threads completion.
_threads = _NoThreads()
_threads = None
def process_request_thread(self, request, client_address):
"""Same as in BaseServer but as a thread.
@ -688,17 +655,23 @@ 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
self._threads.append(t)
if not t.daemon and self.block_on_close:
if self._threads is None:
self._threads = []
self._threads.append(t)
t.start()
def server_close(self):
super().server_close()
self._threads.join()
if self.block_on_close:
threads = self._threads
self._threads = None
if threads:
for thread in threads:
thread.join()
if hasattr(os, "fork"):

View File

@ -260,14 +260,6 @@ 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,11 +420,7 @@ 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.
if kwargs.get('universal_newlines') or kwargs.get('text'):
empty = ''
else:
empty = b''
kwargs['input'] = empty
kwargs['input'] = '' if kwargs.get('universal_newlines', False) else b''
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, 0, b'\x04\x00\x71\x00',
co = types.CodeType(0, 0, 0, 0, 0, b'\x04\x71\x00\x00',
(), (), (), '', '', 1, b'')
exec(co)

View File

@ -107,9 +107,6 @@ class MockSocket:
def close(self):
pass
def connect(self, host):
pass
def socket(family=None, type=None, proto=None):
return MockSocket(family)
@ -155,12 +152,8 @@ 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,10 +69,6 @@ def count_opcode(code, pickle):
return n
def identity(x):
return x
class UnseekableIO(io.BytesIO):
def peek(self, *args):
raise NotImplementedError
@ -142,12 +138,11 @@ class E(C):
def __getinitargs__(self):
return ()
# Simple mutable object.
class Object:
class H(object):
pass
# Hashable immutable key object containing unheshable mutable data.
class K:
# Hashable mutable key
class K(object):
def __init__(self, value):
self.value = value
@ -162,6 +157,10 @@ __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):
@ -1497,182 +1496,54 @@ class AbstractPickleTests(unittest.TestCase):
got = filelike.getvalue()
self.assertEqual(expected, got)
def _test_recursive_list(self, cls, aslist=identity, minprotocol=0):
# List containing itself.
l = cls()
def test_recursive_list(self):
l = []
l.append(l)
for proto in range(minprotocol, pickle.HIGHEST_PROTOCOL + 1):
for proto in protocols:
s = self.dumps(l, proto)
x = self.loads(s)
self.assertIsInstance(x, cls)
y = aslist(x)
self.assertEqual(len(y), 1)
self.assertIs(y[0], x)
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 range(minprotocol, pickle.HIGHEST_PROTOCOL + 1):
s = self.dumps(t, proto)
x = self.loads(s)
self.assertIsInstance(x, tuple)
self.assertIsInstance(x, list)
self.assertEqual(len(x), 1)
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)
self.assertIs(x[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)
t = ([],)
t[0].append(t)
for proto in protocols:
s = self.dumps(t, proto)
x = self.loads(s)
self.assertIsInstance(x, cls)
y = asdict(x)
self.assertEqual(list(y.keys()), [1])
self.assertIs(y[1], x)
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)
def test_recursive_dict(self):
self._test_recursive_dict(dict)
def test_recursive_dict_subclass(self):
self._test_recursive_dict(MyDict, minprotocol=2)
def test_recursive_dict_like(self):
self._test_recursive_dict(REX_seven, asdict=lambda x: x.table)
def _test_recursive_tuple_and_dict(self, cls, asdict=identity, minprotocol=0):
# Tuple containing a dict containing the original tuple.
t = (cls(),)
t[0][1] = t
for proto in range(minprotocol, pickle.HIGHEST_PROTOCOL + 1):
s = self.dumps(t, proto)
x = self.loads(s)
self.assertIsInstance(x, tuple)
self.assertEqual(len(x), 1)
self.assertIsInstance(x[0], cls)
y = asdict(x[0])
self.assertEqual(list(y), [1])
self.assertIs(y[1], x)
# Dict containing a tuple containing the original dict.
t, = t
for proto in range(minprotocol, pickle.HIGHEST_PROTOCOL + 1):
s = self.dumps(t, proto)
x = self.loads(s)
self.assertIsInstance(x, cls)
y = asdict(x)
self.assertEqual(list(y), [1])
self.assertIsInstance(y[1], tuple)
self.assertEqual(len(y[1]), 1)
self.assertIs(y[1][0], x)
def test_recursive_tuple_and_dict(self):
self._test_recursive_tuple_and_dict(dict)
def test_recursive_tuple_and_dict_subclass(self):
self._test_recursive_tuple_and_dict(MyDict, minprotocol=2)
def test_recursive_tuple_and_dict_like(self):
self._test_recursive_tuple_and_dict(REX_seven, asdict=lambda x: x.table)
def _test_recursive_dict_key(self, cls, asdict=identity, minprotocol=0):
# Dict containing an immutable object (as key) containing the original
# dict.
d = cls()
d[K(d)] = 1
for proto in range(minprotocol, pickle.HIGHEST_PROTOCOL + 1):
d = {}
d[1] = d
for proto in protocols:
s = self.dumps(d, proto)
x = self.loads(s)
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)
self.assertIsInstance(x, dict)
self.assertEqual(list(x.keys()), [1])
self.assertIs(x[1], x)
def test_recursive_dict_key(self):
self._test_recursive_dict_key(dict)
def test_recursive_dict_subclass_key(self):
self._test_recursive_dict_key(MyDict, minprotocol=2)
def test_recursive_dict_like_key(self):
self._test_recursive_dict_key(REX_seven, asdict=lambda x: x.table)
def _test_recursive_tuple_and_dict_key(self, cls, asdict=identity, minprotocol=0):
# Tuple containing a dict containing an immutable object (as key)
# containing the original tuple.
t = (cls(),)
t[0][K(t)] = 1
for proto in range(minprotocol, pickle.HIGHEST_PROTOCOL + 1):
s = self.dumps(t, proto)
d = {}
k = K(d)
d[k] = 1
for proto in protocols:
s = self.dumps(d, proto)
x = self.loads(s)
self.assertIsInstance(x, tuple)
self.assertEqual(len(x), 1)
self.assertIsInstance(x[0], cls)
y = asdict(x[0])
self.assertEqual(len(y), 1)
self.assertIsInstance(list(y.keys())[0], K)
self.assertIs(list(y.keys())[0].value, x)
# Dict containing an immutable object (as key) containing a tuple
# containing the original dict.
t, = t
for proto in range(minprotocol, pickle.HIGHEST_PROTOCOL + 1):
s = self.dumps(t, proto)
x = self.loads(s)
self.assertIsInstance(x, cls)
y = asdict(x)
self.assertEqual(len(y), 1)
self.assertIsInstance(list(y.keys())[0], K)
self.assertIs(list(y.keys())[0].value[0], x)
def test_recursive_tuple_and_dict_key(self):
self._test_recursive_tuple_and_dict_key(dict)
def test_recursive_tuple_and_dict_subclass_key(self):
self._test_recursive_tuple_and_dict_key(MyDict, minprotocol=2)
def test_recursive_tuple_and_dict_like_key(self):
self._test_recursive_tuple_and_dict_key(REX_seven, asdict=lambda x: x.table)
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)
def test_recursive_set(self):
# Set containing an immutable object containing the original set.
y = set()
y.add(K(y))
k = K(y)
y.add(k)
for proto in range(4, pickle.HIGHEST_PROTOCOL + 1):
s = self.dumps(y, proto)
x = self.loads(s)
@ -1681,31 +1552,52 @@ class AbstractPickleTests(unittest.TestCase):
self.assertIsInstance(list(x)[0], K)
self.assertIs(list(x)[0].value, x)
# Immutable object containing a set containing the original object.
y, = y
for proto in range(4, pickle.HIGHEST_PROTOCOL + 1):
def test_recursive_list_subclass(self):
y = MyList()
y.append(y)
for proto in range(2, pickle.HIGHEST_PROTOCOL + 1):
s = self.dumps(y, proto)
x = self.loads(s)
self.assertIsInstance(x, K)
self.assertIsInstance(x.value, set)
self.assertEqual(len(x.value), 1)
self.assertIs(list(x.value)[0], x)
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)
def test_recursive_inst(self):
# Mutable object containing itself.
i = Object()
i = C()
i.attr = i
for proto in protocols:
s = self.dumps(i, proto)
x = self.loads(s)
self.assertIsInstance(x, Object)
self.assertIsInstance(x, C)
self.assertEqual(dir(x), dir(i))
self.assertIs(x.attr, x)
def test_recursive_multi(self):
l = []
d = {1:l}
i = Object()
i = C()
i.attr = d
l.append(i)
for proto in protocols:
@ -1715,94 +1607,49 @@ 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.assertIs(x[0].attr[1], x)
self.assertTrue(x[0].attr[1] is x)
def _test_recursive_collection_and_inst(self, factory):
# Mutable object containing a collection containing the original
# object.
o = Object()
o.attr = factory([o])
t = type(o.attr)
for proto in protocols:
s = self.dumps(o, proto)
x = self.loads(s)
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], Object)
self.assertIs(list(x)[0].attr, x)
def test_recursive_list_and_inst(self):
self._test_recursive_collection_and_inst(list)
def test_recursive_tuple_and_inst(self):
self._test_recursive_collection_and_inst(tuple)
def test_recursive_dict_and_inst(self):
self._test_recursive_collection_and_inst(dict.fromkeys)
def test_recursive_set_and_inst(self):
self._test_recursive_collection_and_inst(set)
def test_recursive_frozenset_and_inst(self):
self._test_recursive_collection_and_inst(frozenset)
def test_recursive_list_subclass_and_inst(self):
self._test_recursive_collection_and_inst(MyList)
def test_recursive_tuple_subclass_and_inst(self):
self._test_recursive_collection_and_inst(MyTuple)
def test_recursive_dict_subclass_and_inst(self):
self._test_recursive_collection_and_inst(MyDict.fromkeys)
def test_recursive_set_subclass_and_inst(self):
self._test_recursive_collection_and_inst(MySet)
def test_recursive_frozenset_subclass_and_inst(self):
self._test_recursive_collection_and_inst(MyFrozenSet)
def test_recursive_inst_state(self):
# Mutable object containing itself.
y = REX_state()
y.state = y
def check_recursive_collection_and_inst(self, factory):
h = H()
y = factory([h])
h.attr = 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.assertIsInstance(x, type(y))
self.assertEqual(len(x), 1)
self.assertIsInstance(x[0], REX_state)
self.assertIs(x[0].state, x)
self.assertIsInstance(list(x)[0], H)
self.assertIs(list(x)[0].attr, 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_recursive_list_and_inst(self):
self.check_recursive_collection_and_inst(list)
def test_recursive_tuple_and_inst(self):
self.check_recursive_collection_and_inst(tuple)
def test_recursive_dict_and_inst(self):
self.check_recursive_collection_and_inst(dict.fromkeys)
def test_recursive_set_and_inst(self):
self.check_recursive_collection_and_inst(set)
def test_recursive_frozenset_and_inst(self):
self.check_recursive_collection_and_inst(frozenset)
def test_recursive_list_subclass_and_inst(self):
self.check_recursive_collection_and_inst(MyList)
def test_recursive_tuple_subclass_and_inst(self):
self.check_recursive_collection_and_inst(MyTuple)
def test_recursive_dict_subclass_and_inst(self):
self.check_recursive_collection_and_inst(MyDict.fromkeys)
def test_recursive_set_subclass_and_inst(self):
self.check_recursive_collection_and_inst(MySet)
def test_recursive_frozenset_subclass_and_inst(self):
self.check_recursive_collection_and_inst(MyFrozenSet)
def test_unicode(self):
endcases = ['', '<\\u>', '<\\\u1234>', '<\n>',
@ -3215,19 +3062,6 @@ 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,7 +1,6 @@
"""Tests for the asdl parser in Parser/asdl.py"""
import importlib.machinery
import importlib.util
import os
from os.path import dirname
import sys
@ -27,10 +26,7 @@ class TestAsdlParser(unittest.TestCase):
sys.path.insert(0, parser_dir)
loader = importlib.machinery.SourceFileLoader(
'asdl', os.path.join(parser_dir, 'asdl.py'))
spec = importlib.util.spec_from_loader('asdl', loader)
module = importlib.util.module_from_spec(spec)
loader.exec_module(module)
cls.asdl = module
cls.asdl = loader.load_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,18 +1011,6 @@ 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,6 +1621,48 @@ 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,7 +4,8 @@
# 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()
# Functions not tested: {def,reset}_{shell,prog}_mode, getch(), getstr(),
# init_color()
# Only called, not tested: getmouse(), ungetmouse()
#
@ -12,7 +13,6 @@ import os
import string
import sys
import tempfile
import functools
import unittest
from test.support import requires, verbose, SaveSignals
@ -37,17 +37,7 @@ 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',
@ -58,59 +48,37 @@ class TestCurses(unittest.TestCase):
@classmethod
def setUpClass(cls):
if verbose:
print(f'TERM={term}', file=sys.stderr, flush=True)
if not sys.__stdout__.isatty():
# Temporary skip tests on non-tty
raise unittest.SkipTest('sys.__stdout__ is not a tty')
cls.tmp = tempfile.TemporaryFile()
fd = cls.tmp.fileno()
else:
cls.tmp = None
fd = sys.__stdout__.fileno()
# testing setupterm() inside initscr/endwin
# causes terminal breakage
stdout_fd = sys.__stdout__.fileno()
curses.setupterm(fd=stdout_fd)
curses.setupterm(fd=fd)
@classmethod
def tearDownClass(cls):
if cls.tmp:
cls.tmp.close()
del cls.tmp
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()
self.addCleanup(self.save_signals.restore)
if verbose and self.output is not None:
if verbose:
# just to make the test output a little more readable
sys.stderr.flush()
sys.stdout.flush()
print(file=self.output, flush=True)
print()
self.stdscr = curses.initscr()
if self.isatty:
curses.savetty()
self.addCleanup(curses.endwin)
self.addCleanup(curses.resetty)
curses.savetty()
def tearDown(self):
curses.resetty()
curses.endwin()
self.save_signals.restore()
def test_window_funcs(self):
"Test the methods of windows"
@ -128,7 +96,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.getmaxyx,
stdscr.getbkgd, stdscr.getkey, stdscr.getmaxyx,
stdscr.getparyx, stdscr.getyx, stdscr.inch,
stdscr.insertln, stdscr.instr, stdscr.is_wintouched,
win.noutrefresh, stdscr.redrawwin, stdscr.refresh,
@ -239,11 +207,6 @@ 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)
@ -262,20 +225,17 @@ 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.doupdate, curses.flash, curses.flushinp,
curses.cbreak, curses.def_prog_mode, curses.doupdate,
curses.flash, curses.flushinp,
curses.has_colors, curses.has_ic, curses.has_il,
curses.isendwin, curses.killchar, curses.longname,
curses.noecho, curses.nonl, curses.noqiflush,
curses.termattrs, curses.termname, curses.erasechar,
curses.nocbreak, curses.noecho, curses.nonl,
curses.noqiflush, curses.noraw,
curses.reset_prog_mode, 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'):
@ -287,9 +247,13 @@ 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)
if self.isatty:
curses.intrflush(1)
curses.intrflush(1)
curses.meta(1)
curses.napms(100)
curses.newpad(50,50)
@ -298,8 +262,7 @@ class TestCurses(unittest.TestCase):
curses.nl() ; curses.nl(1)
curses.putp(b'abc')
curses.qiflush()
if self.isatty:
curses.raw() ; curses.raw(1)
curses.raw() ; curses.raw(1)
curses.set_escdelay(25)
self.assertEqual(curses.get_escdelay(), 25)
curses.set_tabsize(4)
@ -318,127 +281,31 @@ class TestCurses(unittest.TestCase):
curses.use_env(1)
# Functions only available on a few platforms
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):
def test_colors_funcs(self):
if not curses.has_colors():
self.skipTest('requires colors support')
curses.start_color()
if verbose:
print(f'COLORS = {curses.COLORS}', file=sys.stderr)
print(f'COLOR_PAIRS = {curses.COLOR_PAIRS}', file=sys.stderr)
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)
@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)
if hasattr(curses, 'use_default_colors'):
curses.use_default_colors()
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))
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)
@requires_curses_func('keyname')
def test_keyname(self):
@ -506,6 +373,7 @@ 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
@ -609,8 +477,6 @@ 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_calling(self):
def test_init_subclass(self):
class MyEnum(Enum):
def __init_subclass__(cls, **kwds):
super(MyEnum, cls).__init_subclass__(**kwds)
@ -2155,16 +2155,6 @@ 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,59 +332,6 @@ 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,7 +27,8 @@ import functools
py_functools = import_helper.import_fresh_module('functools',
blocked=['_functools'])
c_functools = import_helper.import_fresh_module('functools')
c_functools = import_helper.import_fresh_module('functools',
fresh=['_functools'])
decimal = import_helper.import_fresh_module('decimal', fresh=['_decimal'])

View File

@ -7,7 +7,6 @@ import textwrap
import contextlib
from test.support.os_helper import FS_NONASCII
from typing import Dict, Union
@contextlib.contextmanager
@ -72,13 +71,8 @@ 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: FilesDef = {
files = {
"distinfo_pkg-1.0.0.dist-info": {
"METADATA": """
Name: distinfo-pkg
@ -92,55 +86,19 @@ 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()
@ -148,7 +106,7 @@ class DistInfoPkgOffPath(SiteDir):
class EggInfoPkg(OnSysPath, SiteDir):
files: FilesDef = {
files = {
"egginfo_pkg.egg-info": {
"PKG-INFO": """
Name: egginfo-pkg
@ -171,13 +129,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()
@ -185,7 +143,7 @@ class EggInfoPkg(OnSysPath, SiteDir):
class EggInfoFile(OnSysPath, SiteDir):
files: FilesDef = {
files = {
"egginfo_file.egg-info": """
Metadata-Version: 1.0
Name: egginfo_file
@ -198,7 +156,7 @@ class EggInfoFile(OnSysPath, SiteDir):
Description: UNKNOWN
Platform: UNKNOWN
""",
}
}
def setUp(self):
super(EggInfoFile, self).setUp()
@ -206,12 +164,12 @@ class EggInfoFile(OnSysPath, SiteDir):
class LocalPackage:
files: FilesDef = {
files = {
"setup.py": """
import setuptools
setuptools.setup(name="local-pkg", version="2.0.1")
""",
}
}
def setUp(self):
self.fixtures = contextlib.ExitStack()
@ -256,7 +214,8 @@ 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,3 +1,5 @@
# coding: utf-8
import re
import json
import pickle
@ -12,14 +14,10 @@ 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):
@ -72,11 +70,12 @@ 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):
"""
@ -145,15 +144,11 @@ 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):
@ -167,12 +162,24 @@ 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):
@ -258,21 +265,10 @@ 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
@ -281,5 +277,5 @@ class FileSystem(
fixtures.build_files(
{self.unicode_filename(): {}},
prefix=self.site_dir,
)
)
list(distributions())

View File

@ -2,26 +2,20 @@ 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.DistInfoPkgWithDot,
fixtures.EggInfoFile,
unittest.TestCase,
):
fixtures.EggInfoPkg,
fixtures.DistInfoPkg,
fixtures.EggInfoFile,
unittest.TestCase):
version_pattern = r'\d+\.\d+(\.\d)?'
@ -39,28 +33,16 @@ 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):
@ -69,13 +51,6 @@ 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'
@ -100,8 +75,13 @@ 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'))
@ -119,7 +99,10 @@ 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')
@ -129,8 +112,7 @@ class APITests(
assert "pytest; extra == 'test'" in deps
def test_more_complex_deps_requires_text(self):
requires = textwrap.dedent(
"""
requires = textwrap.dedent("""
dep1
dep2
@ -142,8 +124,7 @@ class APITests(
[extra2:python_version < "3"]
dep5
"""
)
""")
deps = sorted(Distribution._deps_from_requires_text(requires))
expected = [
'dep1',
@ -151,7 +132,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.
@ -159,27 +140,17 @@ 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,12 +3,8 @@ import unittest
from contextlib import ExitStack
from importlib.metadata import (
PackageNotFoundError,
distribution,
distributions,
entry_points,
files,
version,
distribution, entry_points, files, PackageNotFoundError,
version, distributions,
)
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(self.DESC, desc)
self.assertIn("Python", desc)
# With a pattern
desc = self.server.description(self.GROUP_PAT)
_check_desc(desc)
@ -309,7 +309,6 @@ 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
@ -344,11 +343,8 @@ class NetworkedNNTP_SSLTests(NetworkedNNTPTests):
# 400 connections per day are accepted from each IP address."
NNTP_HOST = 'nntp.aioe.org'
# 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'
GROUP_NAME = 'comp.lang.python'
GROUP_PAT = 'comp.lang.*'
NNTP_CLASS = getattr(nntplib, 'NNTP_SSL', None)

View File

@ -1,51 +0,0 @@
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,6 +1,4 @@
import os
import copy
import pickle
import platform
import subprocess
import sys
@ -236,38 +234,6 @@ 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,16 +204,6 @@ 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):
@ -309,46 +299,6 @@ 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,34 +542,6 @@ 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,17 +165,6 @@ 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,11 +1121,9 @@ 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] +
[1 << 16, _testcapi.INT_MAX]
)
s_bad_values = l_bad_values + [_testcapi.INT_MIN - 1,
_testcapi.INT_MAX + 1]
s_deprecated_values = [1<<16, _testcapi.INT_MAX]
for k in s_good_values:
socket.ntohs(k)
socket.htons(k)
@ -1138,6 +1136,9 @@ 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,13 +277,6 @@ 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.
@ -498,22 +491,6 @@ 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,28 +204,6 @@ 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('5Pi'))
check(x, size('4Pi'))
# PyCapsule
# XXX
# rangeiterator

View File

@ -874,48 +874,6 @@ 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,14 +138,10 @@ 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.
# 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)
# 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)
return integers
def test_getint(self):
@ -449,7 +445,7 @@ class TclTest(unittest.TestCase):
else:
self.assertEqual(result, str(i))
self.assertIsInstance(result, str)
if get_tk_patchlevel() < (8, 5): # bignum was added in Tcl 8.5
if tcl_version < (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,16 +737,6 @@ 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,7 +3021,6 @@ 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')
@ -3049,16 +3048,6 @@ 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,31 +346,6 @@ 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,17 +1851,9 @@ 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')),
# 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')),
('http', 'joe', 'password', 'proxy.example.com'))
]
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 _default_root is None:
if not _default_root:
if what:
raise RuntimeError(f"Too early to {what}: no default root window")
root = Tk()
@ -300,31 +300,6 @@ 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
@ -367,7 +342,7 @@ class Variable:
if name is not None and not isinstance(name, str):
raise TypeError("name must be a string")
global _varnum
if master is None:
if not master:
master = _get_default_root('create variable')
self._root = master._root()
self._tk = master.tk
@ -516,11 +491,15 @@ 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._name == other._name
and self.__class__.__name__ == other.__class__.__name__
and self._tk == other._tk)
return self.__class__.__name__ == other.__class__.__name__ \
and self._name == other._name
class StringVar(Variable):
@ -829,7 +808,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 func is None:
if not func:
# I'd rather use time.sleep(ms*0.001)
self.tk.call('after', ms)
return None
@ -1563,7 +1542,7 @@ class Misc:
def _root(self):
"""Internal function."""
w = self
while w.master is not None: w = w.master
while w.master: w = w.master
return w
_subst_format = ('%#', '%b', '%f', '%h', '%k',
'%s', '%t', '%w', '%x', '%y',
@ -2327,7 +2306,7 @@ class Tk(Misc, Wm):
self.tk.createcommand('exit', _exit)
self._tclCommands.append('tkerror')
self._tclCommands.append('exit')
if _support_default_root and _default_root is None:
if _support_default_root and not _default_root:
_default_root = self
self.protocol("WM_DELETE_WINDOW", self.destroy)
@ -2555,7 +2534,7 @@ class BaseWidget(Misc):
def _setup(self, master, cnf):
"""Internal function. Sets up information about children."""
if master is None:
if not master:
master = _get_default_root()
self.master = master
self.tk = master.tk
@ -3970,7 +3949,7 @@ class _setit:
def __call__(self, *args):
self.__var.set(self.__value)
if self.__callback is not None:
if self.__callback:
self.__callback(self.__value, *args)
@ -4019,7 +3998,7 @@ class Image:
def __init__(self, imgtype, name=None, cnf={}, master=None, **kw):
self.name = None
if master is None:
if not master:
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, _get_temp_root, _destroy_temp_root
from tkinter import Frame
class Dialog:
@ -18,7 +18,7 @@ class Dialog:
command = None
def __init__(self, master=None, **options):
if master is None:
if not master:
master = options.get('parent')
self.master = master
self.options = options
@ -37,17 +37,22 @@ class Dialog:
self._fixoptions()
master = self.master
if master is None:
master = _get_temp_root()
# we need a dummy widget to properly process the options
# (at least as long as we use Tkinter 1.63)
w = Frame(self.master)
try:
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)
s = w.tk.call(self.command, *w._options(self.options))
s = self._fixresult(w, s)
finally:
_destroy_temp_root(master)
try:
# get rid of the widget
w.destroy()
except:
pass
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 is not None:
if h.root:
return h
else:
return None
@ -143,7 +143,7 @@ class DndHandler:
def __del__(self):
root = self.root
self.root = None
if root is not None:
if root:
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 is not None:
while target_widget:
try:
attr = target_widget.dnd_accept
except AttributeError:
pass
else:
new_target = attr(source, event)
if new_target is not None:
if new_target:
break
target_widget = target_widget.master
old_target = self.target
if old_target is new_target:
if old_target is not None:
if old_target:
old_target.dnd_motion(source, event)
else:
if old_target is not None:
if old_target:
self.target = None
old_target.dnd_leave(source, event)
if new_target is not None:
if new_target:
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 is not None:
if target:
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 is not None:
if self.canvas:
self.detach()
if canvas is None:
if not canvas:
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 canvas is None:
if not canvas:
return
id = self.id
label = self.label

View File

@ -17,10 +17,10 @@ BOLD = "bold"
ITALIC = "italic"
def nametofont(name, root=None):
def nametofont(name):
"""Given the name of a tk named font, returns a Font representation.
"""
return Font(name=name, exists=True, root=root)
return Font(name=name, exists=True)
class Font:
@ -68,7 +68,7 @@ class Font:
def __init__(self, root=None, font=None, name=None, exists=False,
**options):
if root is None:
if not root:
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 and self._tk == other._tk
return self.name == other.name
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 root is None:
if not root:
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 root is None:
if not root:
root = tkinter._get_default_root('use font.names()')
return root.tk.splitlist(root.tk.call("font", "names"))

View File

@ -24,8 +24,7 @@ askstring -- get a string from the user
"""
from tkinter import *
from tkinter import _get_temp_root, _destroy_temp_root
from tkinter import messagebox
from tkinter import messagebox, _get_default_root
class SimpleDialog:
@ -56,8 +55,36 @@ 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.root.transient(master)
_place_window(self.root, master)
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
def go(self):
self.root.wait_visibility()
@ -100,8 +127,8 @@ class Dialog(Toplevel):
title -- the dialog title
'''
master = parent
if master is None:
master = _get_temp_root()
if not master:
master = _get_default_root('create dialog window')
Toplevel.__init__(self, master)
@ -125,12 +152,16 @@ class Dialog(Toplevel):
self.buttonbox()
if self.initial_focus is None:
if not self.initial_focus:
self.initial_focus = self
self.protocol("WM_DELETE_WINDOW", self.cancel)
_place_window(self, parent)
if parent is not None:
self.geometry("+%d+%d" % (parent.winfo_rootx()+50,
parent.winfo_rooty()+50))
self.deiconify() # become visible now
self.initial_focus.focus_set()
@ -143,7 +174,6 @@ class Dialog(Toplevel):
'''Destroy the window'''
self.initial_focus = None
Toplevel.destroy(self)
_destroy_temp_root(self.master)
#
# construction hooks
@ -221,37 +251,6 @@ 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

@ -1,39 +0,0 @@
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,22 +63,15 @@ class FontTest(AbstractTkTest, unittest.TestCase):
self.assertEqual(self.font.name, fontname)
self.assertEqual(str(self.font), fontname)
def test_equality(self):
def test_eq(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)
@ -108,11 +101,6 @@ 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}>'
@ -148,16 +136,6 @@ 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

@ -1,38 +0,0 @@
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,25 +10,13 @@ requires('gui')
class DefaultRootTest(AbstractDefaultRootTest, unittest.TestCase):
def test_askinteger(self):
@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
self.assertRaises(RuntimeError, askinteger, "Go To Line", "Line number")
root = tkinter.Tk()
with swap_attr(Dialog, 'wait_window', lambda self, w: w.destroy()):
askinteger("Go To Line", "Line number")
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")
root.destroy()
tkinter.NoDefaultRoot()
self.assertRaises(RuntimeError, askinteger, "Go To Line", "Line number")
tests_gui = (DefaultRootTest,)

View File

@ -58,32 +58,22 @@ class TestVariable(TestBase):
del v2
self.assertFalse(self.info_exists("name"))
def test_equality(self):
def test___eq__(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 = Variable(self.root, name="cba")
v3 = StringVar(self.root, name="abc")
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_configure_class(self):
def test_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_configure_colormap(self):
def test_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_configure_container(self):
def test_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_configure_visual(self):
def test_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_configure_menu(self):
def test_menu(self):
widget = self.create()
menu = tkinter.Menu(self.root)
self.checkParam(widget, 'menu', menu, eq=widget_eq)
self.checkParam(widget, 'menu', '')
def test_configure_screen(self):
def test_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_configure_use(self):
def test_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_configure_labelanchor(self):
def test_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_configure_labelwidget(self):
def test_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_configure_highlightthickness(self):
def test_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_configure_default(self):
def test_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_configure_offvalue(self):
def test_offvalue(self):
widget = self.create()
self.checkParams(widget, 'offvalue', 1, 2.3, '', 'any string')
def test_configure_onvalue(self):
def test_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_configure_value(self):
def test_value(self):
widget = self.create()
self.checkParams(widget, 'value', 1, 2.3, '', 'any string')
@ -254,19 +254,18 @@ class MenubuttonTest(AbstractLabelTest, unittest.TestCase):
def create(self, **kwargs):
return tkinter.Menubutton(self.root, **kwargs)
def test_configure_direction(self):
def test_direction(self):
widget = self.create()
self.checkEnumParam(widget, 'direction',
'above', 'below', 'flush', 'left', 'right')
def test_configure_height(self):
def test_height(self):
widget = self.create()
self.checkIntegerParam(widget, 'height', 100, -100, 0, conv=str)
test_configure_highlightthickness = \
StandardOptionsTests.test_configure_highlightthickness
test_highlightthickness = StandardOptionsTests.test_highlightthickness
def test_configure_image(self):
def test_image(self):
widget = self.create()
image = tkinter.PhotoImage(master=self.root, name='image1')
self.checkParam(widget, 'image', image, conv=str)
@ -280,23 +279,23 @@ class MenubuttonTest(AbstractLabelTest, unittest.TestCase):
if errmsg is not None:
self.assertEqual(str(cm.exception), errmsg)
def test_configure_menu(self):
def test_menu(self):
widget = self.create()
menu = tkinter.Menu(widget, name='menu')
self.checkParam(widget, 'menu', menu, eq=widget_eq)
menu.destroy()
def test_configure_padx(self):
def test_padx(self):
widget = self.create()
self.checkPixelsParam(widget, 'padx', 3, 4.4, 5.6, '12m')
self.checkParam(widget, 'padx', -2, expected=0)
def test_configure_pady(self):
def test_pady(self):
widget = self.create()
self.checkPixelsParam(widget, 'pady', 3, 4.4, 5.6, '12m')
self.checkParam(widget, 'pady', -2, expected=0)
def test_configure_width(self):
def test_width(self):
widget = self.create()
self.checkIntegerParam(widget, 'width', 402, -402, 0, conv=str)
@ -329,18 +328,18 @@ class EntryTest(AbstractWidgetTest, unittest.TestCase):
def create(self, **kwargs):
return tkinter.Entry(self.root, **kwargs)
def test_configure_disabledbackground(self):
def test_disabledbackground(self):
widget = self.create()
self.checkColorParam(widget, 'disabledbackground')
def test_configure_insertborderwidth(self):
def test_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_configure_insertwidth(self):
def test_insertwidth(self):
widget = self.create()
self.checkPixelsParam(widget, 'insertwidth', 1.3, 3.6, '10p')
self.checkParam(widget, 'insertwidth', 0.1, expected=2)
@ -350,32 +349,32 @@ class EntryTest(AbstractWidgetTest, unittest.TestCase):
else:
self.checkParam(widget, 'insertwidth', 0.9, expected=1)
def test_configure_invalidcommand(self):
def test_invalidcommand(self):
widget = self.create()
self.checkCommandParam(widget, 'invalidcommand')
self.checkCommandParam(widget, 'invcmd')
def test_configure_readonlybackground(self):
def test_readonlybackground(self):
widget = self.create()
self.checkColorParam(widget, 'readonlybackground')
def test_configure_show(self):
def test_show(self):
widget = self.create()
self.checkParam(widget, 'show', '*')
self.checkParam(widget, 'show', '')
self.checkParam(widget, 'show', ' ')
def test_configure_state(self):
def test_state(self):
widget = self.create()
self.checkEnumParam(widget, 'state',
'disabled', 'normal', 'readonly')
def test_configure_validate(self):
def test_validate(self):
widget = self.create()
self.checkEnumParam(widget, 'validate',
'all', 'key', 'focus', 'focusin', 'focusout', 'none')
def test_configure_validatecommand(self):
def test_validatecommand(self):
widget = self.create()
self.checkCommandParam(widget, 'validatecommand')
self.checkCommandParam(widget, 'vcmd')
@ -428,25 +427,25 @@ class SpinboxTest(EntryTest, unittest.TestCase):
def create(self, **kwargs):
return tkinter.Spinbox(self.root, **kwargs)
test_configure_show = None
test_show = None
def test_configure_buttonbackground(self):
def test_buttonbackground(self):
widget = self.create()
self.checkColorParam(widget, 'buttonbackground')
def test_configure_buttoncursor(self):
def test_buttoncursor(self):
widget = self.create()
self.checkCursorParam(widget, 'buttoncursor')
def test_configure_buttondownrelief(self):
def test_buttondownrelief(self):
widget = self.create()
self.checkReliefParam(widget, 'buttondownrelief')
def test_configure_buttonuprelief(self):
def test_buttonuprelief(self):
widget = self.create()
self.checkReliefParam(widget, 'buttonuprelief')
def test_configure_format(self):
def test_format(self):
widget = self.create()
self.checkParam(widget, 'format', '%2f')
self.checkParam(widget, 'format', '%2.2f')
@ -461,25 +460,25 @@ class SpinboxTest(EntryTest, unittest.TestCase):
self.checkParam(widget, 'format', '%09.200f')
self.checkInvalidParam(widget, 'format', '%d')
def test_configure_from(self):
def test_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_configure_increment(self):
def test_increment(self):
widget = self.create()
self.checkFloatParam(widget, 'increment', -1, 1, 10.2, 12.8, 0)
def test_configure_to(self):
def test_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_configure_values(self):
def test_values(self):
# XXX
widget = self.create()
self.assertEqual(widget['values'], '')
@ -490,7 +489,7 @@ class SpinboxTest(EntryTest, unittest.TestCase):
expected='42 3.14 {} {any string}')
self.checkParam(widget, 'values', '')
def test_configure_wrap(self):
def test_wrap(self):
widget = self.create()
self.checkBooleanParam(widget, 'wrap')
@ -556,17 +555,17 @@ class TextTest(AbstractWidgetTest, unittest.TestCase):
def create(self, **kwargs):
return tkinter.Text(self.root, **kwargs)
def test_configure_autoseparators(self):
def test_autoseparators(self):
widget = self.create()
self.checkBooleanParam(widget, 'autoseparators')
@requires_tcl(8, 5)
def test_configure_blockcursor(self):
def test_blockcursor(self):
widget = self.create()
self.checkBooleanParam(widget, 'blockcursor')
@requires_tcl(8, 5)
def test_configure_endline(self):
def test_endline(self):
widget = self.create()
text = '\n'.join('Line %d' for i in range(100))
widget.insert('end', text)
@ -579,50 +578,50 @@ class TextTest(AbstractWidgetTest, unittest.TestCase):
self.checkInvalidParam(widget, 'endline', 10,
errmsg='-startline must be less than or equal to -endline')
def test_configure_height(self):
def test_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_configure_maxundo(self):
def test_maxundo(self):
widget = self.create()
self.checkIntegerParam(widget, 'maxundo', 0, 5, -1)
@requires_tcl(8, 5)
def test_configure_inactiveselectbackground(self):
def test_inactiveselectbackground(self):
widget = self.create()
self.checkColorParam(widget, 'inactiveselectbackground')
@requires_tcl(8, 6)
def test_configure_insertunfocussed(self):
def test_insertunfocussed(self):
widget = self.create()
self.checkEnumParam(widget, 'insertunfocussed',
'hollow', 'none', 'solid')
def test_configure_selectborderwidth(self):
def test_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_configure_spacing1(self):
def test_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_configure_spacing2(self):
def test_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_configure_spacing3(self):
def test_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_configure_startline(self):
def test_startline(self):
widget = self.create()
text = '\n'.join('Line %d' for i in range(100))
widget.insert('end', text)
@ -635,14 +634,14 @@ class TextTest(AbstractWidgetTest, unittest.TestCase):
self.checkInvalidParam(widget, 'startline', 70,
errmsg='-startline must be less than or equal to -endline')
def test_configure_state(self):
def test_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_configure_tabs(self):
def test_tabs(self):
widget = self.create()
if get_tk_patchlevel() < (8, 5, 11):
self.checkParam(widget, 'tabs', (10.2, 20.7, '1i', '2i'),
@ -658,21 +657,21 @@ class TextTest(AbstractWidgetTest, unittest.TestCase):
keep_orig=tcl_version >= (8, 5))
@requires_tcl(8, 5)
def test_configure_tabstyle(self):
def test_tabstyle(self):
widget = self.create()
self.checkEnumParam(widget, 'tabstyle', 'tabular', 'wordprocessor')
def test_configure_undo(self):
def test_undo(self):
widget = self.create()
self.checkBooleanParam(widget, 'undo')
def test_configure_width(self):
def test_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_configure_wrap(self):
def test_wrap(self):
widget = self.create()
if tcl_version < (8, 5):
self.checkParams(widget, 'wrap', 'char', 'none', 'word')
@ -710,16 +709,16 @@ class CanvasTest(AbstractWidgetTest, unittest.TestCase):
def create(self, **kwargs):
return tkinter.Canvas(self.root, **kwargs)
def test_configure_closeenough(self):
def test_closeenough(self):
widget = self.create()
self.checkFloatParam(widget, 'closeenough', 24, 2.4, 3.6, -3,
conv=float)
def test_configure_confine(self):
def test_confine(self):
widget = self.create()
self.checkBooleanParam(widget, 'confine')
def test_configure_offset(self):
def test_offset(self):
widget = self.create()
self.assertEqual(widget['offset'], '0,0')
self.checkParams(widget, 'offset',
@ -728,7 +727,7 @@ class CanvasTest(AbstractWidgetTest, unittest.TestCase):
self.checkParam(widget, 'offset', '#5,6')
self.checkInvalidParam(widget, 'offset', 'spam')
def test_configure_scrollregion(self):
def test_scrollregion(self):
widget = self.create()
self.checkParam(widget, 'scrollregion', '0 0 200 150')
self.checkParam(widget, 'scrollregion', (0, 0, 200, 150),
@ -740,17 +739,17 @@ class CanvasTest(AbstractWidgetTest, unittest.TestCase):
self.checkInvalidParam(widget, 'scrollregion', (0, 0, 200))
self.checkInvalidParam(widget, 'scrollregion', (0, 0, 200, 150, 0))
def test_configure_state(self):
def test_state(self):
widget = self.create()
self.checkEnumParam(widget, 'state', 'disabled', 'normal',
errmsg='bad state value "{}": must be normal or disabled')
def test_configure_xscrollincrement(self):
def test_xscrollincrement(self):
widget = self.create()
self.checkPixelsParam(widget, 'xscrollincrement',
40, 0, 41.2, 43.6, -40, '0.5i')
def test_configure_yscrollincrement(self):
def test_yscrollincrement(self):
widget = self.create()
self.checkPixelsParam(widget, 'yscrollincrement',
10, 0, 11.2, 13.6, -10, '0.1i')
@ -795,26 +794,26 @@ class ListboxTest(AbstractWidgetTest, unittest.TestCase):
def create(self, **kwargs):
return tkinter.Listbox(self.root, **kwargs)
def test_configure_activestyle(self):
def test_activestyle(self):
widget = self.create()
self.checkEnumParam(widget, 'activestyle',
'dotbox', 'none', 'underline')
test_justify = requires_tcl(8, 6, 5)(StandardOptionsTests.test_configure_justify)
test_justify = requires_tcl(8, 6, 5)(StandardOptionsTests.test_justify)
def test_configure_listvariable(self):
def test_listvariable(self):
widget = self.create()
var = tkinter.DoubleVar(self.root)
self.checkVariableParam(widget, 'listvariable', var)
def test_configure_selectmode(self):
def test_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_configure_state(self):
def test_state(self):
widget = self.create()
self.checkEnumParam(widget, 'state', 'disabled', 'normal')
@ -929,53 +928,53 @@ class ScaleTest(AbstractWidgetTest, unittest.TestCase):
def create(self, **kwargs):
return tkinter.Scale(self.root, **kwargs)
def test_configure_bigincrement(self):
def test_bigincrement(self):
widget = self.create()
self.checkFloatParam(widget, 'bigincrement', 12.4, 23.6, -5)
def test_configure_digits(self):
def test_digits(self):
widget = self.create()
self.checkIntegerParam(widget, 'digits', 5, 0)
def test_configure_from(self):
def test_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_configure_label(self):
def test_label(self):
widget = self.create()
self.checkParam(widget, 'label', 'any string')
self.checkParam(widget, 'label', '')
def test_configure_length(self):
def test_length(self):
widget = self.create()
self.checkPixelsParam(widget, 'length', 130, 131.2, 135.6, '5i')
def test_configure_resolution(self):
def test_resolution(self):
widget = self.create()
self.checkFloatParam(widget, 'resolution', 4.2, 0, 6.7, -2)
def test_configure_showvalue(self):
def test_showvalue(self):
widget = self.create()
self.checkBooleanParam(widget, 'showvalue')
def test_configure_sliderlength(self):
def test_sliderlength(self):
widget = self.create()
self.checkPixelsParam(widget, 'sliderlength',
10, 11.2, 15.6, -3, '3m')
def test_configure_sliderrelief(self):
def test_sliderrelief(self):
widget = self.create()
self.checkReliefParam(widget, 'sliderrelief')
def test_configure_tickinterval(self):
def test_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_configure_to(self):
def test_to(self):
widget = self.create()
self.checkFloatParam(widget, 'to', 300, 14.9, 15.1, -10,
conv=float_round)
@ -999,15 +998,15 @@ class ScrollbarTest(AbstractWidgetTest, unittest.TestCase):
def create(self, **kwargs):
return tkinter.Scrollbar(self.root, **kwargs)
def test_configure_activerelief(self):
def test_activerelief(self):
widget = self.create()
self.checkReliefParam(widget, 'activerelief')
def test_configure_elementborderwidth(self):
def test_elementborderwidth(self):
widget = self.create()
self.checkPixelsParam(widget, 'elementborderwidth', 4.3, 5.6, -2, '1m')
def test_configure_orient(self):
def test_orient(self):
widget = self.create()
self.checkEnumParam(widget, 'orient', 'vertical', 'horizontal',
errmsg='bad orientation "{}": must be vertical or horizontal')
@ -1048,63 +1047,63 @@ class PanedWindowTest(AbstractWidgetTest, unittest.TestCase):
def create(self, **kwargs):
return tkinter.PanedWindow(self.root, **kwargs)
def test_configure_handlepad(self):
def test_handlepad(self):
widget = self.create()
self.checkPixelsParam(widget, 'handlepad', 5, 6.4, 7.6, -3, '1m')
def test_configure_handlesize(self):
def test_handlesize(self):
widget = self.create()
self.checkPixelsParam(widget, 'handlesize', 8, 9.4, 10.6, -3, '2m',
conv=noconv)
def test_configure_height(self):
def test_height(self):
widget = self.create()
self.checkPixelsParam(widget, 'height', 100, 101.2, 102.6, -100, 0, '1i',
conv=noconv)
def test_configure_opaqueresize(self):
def test_opaqueresize(self):
widget = self.create()
self.checkBooleanParam(widget, 'opaqueresize')
@requires_tcl(8, 6, 5)
def test_configure_proxybackground(self):
def test_proxybackground(self):
widget = self.create()
self.checkColorParam(widget, 'proxybackground')
@requires_tcl(8, 6, 5)
def test_configure_proxyborderwidth(self):
def test_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_configure_proxyrelief(self):
def test_proxyrelief(self):
widget = self.create()
self.checkReliefParam(widget, 'proxyrelief')
def test_configure_sashcursor(self):
def test_sashcursor(self):
widget = self.create()
self.checkCursorParam(widget, 'sashcursor')
def test_configure_sashpad(self):
def test_sashpad(self):
widget = self.create()
self.checkPixelsParam(widget, 'sashpad', 8, 1.3, 2.6, -2, '2m')
def test_configure_sashrelief(self):
def test_sashrelief(self):
widget = self.create()
self.checkReliefParam(widget, 'sashrelief')
def test_configure_sashwidth(self):
def test_sashwidth(self):
widget = self.create()
self.checkPixelsParam(widget, 'sashwidth', 10, 11.1, 15.6, -3, '1m',
conv=noconv)
def test_configure_showhandle(self):
def test_showhandle(self):
widget = self.create()
self.checkBooleanParam(widget, 'showhandle')
def test_configure_width(self):
def test_width(self):
widget = self.create()
self.checkPixelsParam(widget, 'width', 402, 403.4, 404.6, -402, 0, '5i',
conv=noconv)
@ -1223,23 +1222,23 @@ class MenuTest(AbstractWidgetTest, unittest.TestCase):
def create(self, **kwargs):
return tkinter.Menu(self.root, **kwargs)
def test_configure_postcommand(self):
def test_postcommand(self):
widget = self.create()
self.checkCommandParam(widget, 'postcommand')
def test_configure_tearoff(self):
def test_tearoff(self):
widget = self.create()
self.checkBooleanParam(widget, 'tearoff')
def test_configure_tearoffcommand(self):
def test_tearoffcommand(self):
widget = self.create()
self.checkCommandParam(widget, 'tearoffcommand')
def test_configure_title(self):
def test_title(self):
widget = self.create()
self.checkParam(widget, 'title', 'any string')
def test_configure_type(self):
def test_type(self):
widget = self.create()
self.checkEnumParam(widget, 'type',
'normal', 'tearoff', 'menubar')
@ -1292,7 +1291,7 @@ class MessageTest(AbstractWidgetTest, unittest.TestCase):
def create(self, **kwargs):
return tkinter.Message(self.root, **kwargs)
def test_configure_aspect(self):
def test_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_configure_class(self):
def test_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_configure_padding(self):
def test_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_configure_style(self):
def test_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_configure_labelanchor(self):
def test_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_configure_labelwidget(self):
def test_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_configure_compound(self):
def test_compound(self):
widget = self.create()
self.checkEnumParam(widget, 'compound',
'none', 'text', 'image', 'center',
'top', 'bottom', 'left', 'right')
def test_configure_state(self):
def test_state(self):
widget = self.create()
self.checkParams(widget, 'state', 'active', 'disabled', 'normal')
def test_configure_width(self):
def test_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_configure_font(self):
def test_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_configure_default(self):
def test_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_configure_offvalue(self):
def test_offvalue(self):
widget = self.create()
self.checkParams(widget, 'offvalue', 1, 2.3, '', 'any string')
def test_configure_onvalue(self):
def test_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_configure_invalidcommand(self):
def test_invalidcommand(self):
widget = self.create()
self.checkCommandParam(widget, 'invalidcommand')
def test_configure_show(self):
def test_show(self):
widget = self.create()
self.checkParam(widget, 'show', '*')
self.checkParam(widget, 'show', '')
self.checkParam(widget, 'show', ' ')
def test_configure_state(self):
def test_state(self):
widget = self.create()
self.checkParams(widget, 'state',
'disabled', 'normal', 'readonly')
def test_configure_validate(self):
def test_validate(self):
widget = self.create()
self.checkEnumParam(widget, 'validate',
'all', 'key', 'focus', 'focusin', 'focusout', 'none')
def test_configure_validatecommand(self):
def test_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_configure_height(self):
def test_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_configure_postcommand(self):
def test_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_configure_values(self):
def test_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_configure_orient(self):
def test_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_configure_value(self):
def test_value(self):
widget = self.create()
self.checkParams(widget, 'value', 1, 2.3, '', 'any string')
def test_configure_invoke(self):
def test_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_configure_menu(self):
def test_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_configure_from(self):
def test_from(self):
widget = self.create()
self.checkFloatParam(widget, 'from', 100, 14.9, 15.1, conv=False)
def test_configure_length(self):
def test_length(self):
widget = self.create()
self.checkPixelsParam(widget, 'length', 130, 131.2, 135.6, '5i')
def test_configure_to(self):
def test_to(self):
widget = self.create()
self.checkFloatParam(widget, 'to', 300, 14.9, 15.1, -10, conv=False)
def test_configure_value(self):
def test_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_configure_length(self):
def test_length(self):
widget = self.create()
self.checkPixelsParam(widget, 'length', 100.1, 56.7, '2i')
def test_configure_maximum(self):
def test_maximum(self):
widget = self.create()
self.checkFloatParam(widget, 'maximum', 150.2, 77.7, 0, -10, conv=False)
def test_configure_mode(self):
def test_mode(self):
widget = self.create()
self.checkEnumParam(widget, 'mode', 'determinate', 'indeterminate')
def test_configure_phase(self):
def test_phase(self):
# XXX
pass
def test_configure_value(self):
def test_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_configure_tabs(self):
def test_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_configure_command(self):
def test_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_configure_to(self):
def test_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_configure_from(self):
def test_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_configure_increment(self):
def test_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_configure_format(self):
def test_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_configure_wrap(self):
def test_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_configure_values(self):
def test_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_configure_columns(self):
def test_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_configure_displaycolumns(self):
def test_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_configure_height(self):
def test_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_configure_selectmode(self):
def test_selectmode(self):
widget = self.create()
self.checkEnumParam(widget, 'selectmode',
'none', 'browse', 'extended')
def test_configure_show(self):
def test_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_configure_activebackground(self):
def test_activebackground(self):
widget = self.create()
self.checkColorParam(widget, 'activebackground')
def test_configure_activeborderwidth(self):
def test_activeborderwidth(self):
widget = self.create()
self.checkPixelsParam(widget, 'activeborderwidth',
0, 1.3, 2.9, 6, -2, '10p')
def test_configure_activeforeground(self):
def test_activeforeground(self):
widget = self.create()
self.checkColorParam(widget, 'activeforeground')
def test_configure_anchor(self):
def test_anchor(self):
widget = self.create()
self.checkEnumParam(widget, 'anchor',
'n', 'ne', 'e', 'se', 's', 'sw', 'w', 'nw', 'center')
def test_configure_background(self):
def test_background(self):
widget = self.create()
self.checkColorParam(widget, 'background')
if 'bg' in self.OPTIONS:
self.checkColorParam(widget, 'bg')
def test_configure_bitmap(self):
def test_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_configure_borderwidth(self):
def test_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_configure_compound(self):
def test_compound(self):
widget = self.create()
self.checkEnumParam(widget, 'compound',
'bottom', 'center', 'left', 'none', 'right', 'top')
def test_configure_cursor(self):
def test_cursor(self):
widget = self.create()
self.checkCursorParam(widget, 'cursor')
def test_configure_disabledforeground(self):
def test_disabledforeground(self):
widget = self.create()
self.checkColorParam(widget, 'disabledforeground')
def test_configure_exportselection(self):
def test_exportselection(self):
widget = self.create()
self.checkBooleanParam(widget, 'exportselection')
def test_configure_font(self):
def test_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_configure_foreground(self):
def test_foreground(self):
widget = self.create()
self.checkColorParam(widget, 'foreground')
if 'fg' in self.OPTIONS:
self.checkColorParam(widget, 'fg')
def test_configure_highlightbackground(self):
def test_highlightbackground(self):
widget = self.create()
self.checkColorParam(widget, 'highlightbackground')
def test_configure_highlightcolor(self):
def test_highlightcolor(self):
widget = self.create()
self.checkColorParam(widget, 'highlightcolor')
def test_configure_highlightthickness(self):
def test_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_configure_image(self):
def test_image(self):
widget = self.create()
self.checkImageParam(widget, 'image')
def test_configure_insertbackground(self):
def test_insertbackground(self):
widget = self.create()
self.checkColorParam(widget, 'insertbackground')
def test_configure_insertborderwidth(self):
def test_insertborderwidth(self):
widget = self.create()
self.checkPixelsParam(widget, 'insertborderwidth',
0, 1.3, 2.6, 6, -2, '10p')
def test_configure_insertofftime(self):
def test_insertofftime(self):
widget = self.create()
self.checkIntegerParam(widget, 'insertofftime', 100)
def test_configure_insertontime(self):
def test_insertontime(self):
widget = self.create()
self.checkIntegerParam(widget, 'insertontime', 100)
def test_configure_insertwidth(self):
def test_insertwidth(self):
widget = self.create()
self.checkPixelsParam(widget, 'insertwidth', 1.3, 2.6, -2, '10p')
def test_configure_jump(self):
def test_jump(self):
widget = self.create()
self.checkBooleanParam(widget, 'jump')
def test_configure_justify(self):
def test_justify(self):
widget = self.create()
self.checkEnumParam(widget, 'justify', 'left', 'right', 'center',
errmsg='bad justification "{}": must be '
@ -369,155 +369,154 @@ class StandardOptionsTests:
errmsg='ambiguous justification "": must be '
'left, right, or center')
def test_configure_orient(self):
def test_orient(self):
widget = self.create()
self.assertEqual(str(widget['orient']), self.default_orient)
self.checkEnumParam(widget, 'orient', 'horizontal', 'vertical')
def test_configure_padx(self):
def test_padx(self):
widget = self.create()
self.checkPixelsParam(widget, 'padx', 3, 4.4, 5.6, -2, '12m',
conv=self._conv_pad_pixels)
def test_configure_pady(self):
def test_pady(self):
widget = self.create()
self.checkPixelsParam(widget, 'pady', 3, 4.4, 5.6, -2, '12m',
conv=self._conv_pad_pixels)
def test_configure_relief(self):
def test_relief(self):
widget = self.create()
self.checkReliefParam(widget, 'relief')
def test_configure_repeatdelay(self):
def test_repeatdelay(self):
widget = self.create()
self.checkIntegerParam(widget, 'repeatdelay', -500, 500)
def test_configure_repeatinterval(self):
def test_repeatinterval(self):
widget = self.create()
self.checkIntegerParam(widget, 'repeatinterval', -500, 500)
def test_configure_selectbackground(self):
def test_selectbackground(self):
widget = self.create()
self.checkColorParam(widget, 'selectbackground')
def test_configure_selectborderwidth(self):
def test_selectborderwidth(self):
widget = self.create()
self.checkPixelsParam(widget, 'selectborderwidth', 1.3, 2.6, -2, '10p')
def test_configure_selectforeground(self):
def test_selectforeground(self):
widget = self.create()
self.checkColorParam(widget, 'selectforeground')
def test_configure_setgrid(self):
def test_setgrid(self):
widget = self.create()
self.checkBooleanParam(widget, 'setgrid')
def test_configure_state(self):
def test_state(self):
widget = self.create()
self.checkEnumParam(widget, 'state', 'active', 'disabled', 'normal')
def test_configure_takefocus(self):
def test_takefocus(self):
widget = self.create()
self.checkParams(widget, 'takefocus', '0', '1', '')
def test_configure_text(self):
def test_text(self):
widget = self.create()
self.checkParams(widget, 'text', '', 'any string')
def test_configure_textvariable(self):
def test_textvariable(self):
widget = self.create()
var = tkinter.StringVar(self.root)
self.checkVariableParam(widget, 'textvariable', var)
def test_configure_troughcolor(self):
def test_troughcolor(self):
widget = self.create()
self.checkColorParam(widget, 'troughcolor')
def test_configure_underline(self):
def test_underline(self):
widget = self.create()
self.checkIntegerParam(widget, 'underline', 0, 1, 10)
def test_configure_wraplength(self):
def test_wraplength(self):
widget = self.create()
self.checkPixelsParam(widget, 'wraplength', 100)
def test_configure_xscrollcommand(self):
def test_xscrollcommand(self):
widget = self.create()
self.checkCommandParam(widget, 'xscrollcommand')
def test_configure_yscrollcommand(self):
def test_yscrollcommand(self):
widget = self.create()
self.checkCommandParam(widget, 'yscrollcommand')
# non-standard but common options
def test_configure_command(self):
def test_command(self):
widget = self.create()
self.checkCommandParam(widget, 'command')
def test_configure_indicatoron(self):
def test_indicatoron(self):
widget = self.create()
self.checkBooleanParam(widget, 'indicatoron')
def test_configure_offrelief(self):
def test_offrelief(self):
widget = self.create()
self.checkReliefParam(widget, 'offrelief')
def test_configure_overrelief(self):
def test_overrelief(self):
widget = self.create()
self.checkReliefParam(widget, 'overrelief')
def test_configure_selectcolor(self):
def test_selectcolor(self):
widget = self.create()
self.checkColorParam(widget, 'selectcolor')
def test_configure_selectimage(self):
def test_selectimage(self):
widget = self.create()
self.checkImageParam(widget, 'selectimage')
@requires_tcl(8, 5)
def test_configure_tristateimage(self):
def test_tristateimage(self):
widget = self.create()
self.checkImageParam(widget, 'tristateimage')
@requires_tcl(8, 5)
def test_configure_tristatevalue(self):
def test_tristatevalue(self):
widget = self.create()
self.checkParam(widget, 'tristatevalue', 'unknowable')
def test_configure_variable(self):
def test_variable(self):
widget = self.create()
var = tkinter.DoubleVar(self.root)
self.checkVariableParam(widget, 'variable', var)
class IntegerSizeTests:
def test_configure_height(self):
def test_height(self):
widget = self.create()
self.checkIntegerParam(widget, 'height', 100, -100, 0)
def test_configure_width(self):
def test_width(self):
widget = self.create()
self.checkIntegerParam(widget, 'width', 402, -402, 0)
class PixelSizeTests:
def test_configure_height(self):
def test_height(self):
widget = self.create()
self.checkPixelsParam(widget, 'height', 100, 101.2, 102.6, -100, 0, '3c')
def test_configure_width(self):
def test_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_configure_xxx methods from source classes for
# every xxx option in the OPTIONS class attribute if they are not defined
# explicitly.
# This decorator adds test_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_configure_' + option
methodname = 'test_' + 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 master is None:
if not master:
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 master is None:
if not master:
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 parent is None:
if not parent:
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 is not None:
if ret and callback:
return callback(*args, **kw)
return ret

View File

@ -544,9 +544,8 @@ 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::
@ -736,11 +735,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 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::
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::
T = TypeVar('T')
P = ParamSpec('P')
@ -1250,7 +1249,7 @@ def _no_init(self, *args, **kwargs):
raise TypeError('Protocols cannot be instantiated')
def _allow_reckless_class_checks():
def _allow_reckless_class_cheks():
"""Allow instance and class checks for special stdlib modules.
The abc and functools modules indiscriminately call isinstance() and
@ -1339,12 +1338,12 @@ class Protocol(Generic, metaclass=_ProtocolMeta):
# First, perform various sanity checks.
if not getattr(cls, '_is_runtime_protocol', False):
if _allow_reckless_class_checks():
if _allow_reckless_class_cheks():
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_checks():
if _allow_reckless_class_cheks():
return NotImplemented
raise TypeError("Protocols with non-method members"
" don't support issubclass()")
@ -1669,8 +1668,6 @@ def get_origin(tp):
return tp.__origin__
if tp is Generic:
return Generic
if isinstance(tp, types.Union):
return types.Union
return None
@ -1687,14 +1684,12 @@ def get_args(tp):
"""
if isinstance(tp, _AnnotatedAlias):
return (tp.__origin__,) + tp.__metadata__
if isinstance(tp, (_GenericAlias, GenericAlias)):
if isinstance(tp, _GenericAlias):
res = tp.__args__
if (tp.__origin__ is collections.abc.Callable
and not (res[0] is Ellipsis
or isinstance(res[0], (ParamSpec, _ConcatenateGenericAlias)))):
if tp.__origin__ is collections.abc.Callable and res[0] is not Ellipsis:
res = (list(res[:-1]), res[-1])
return res
if isinstance(tp, types.Union):
if isinstance(tp, GenericAlias):
return tp.__args__
return ()

View File

@ -773,11 +773,7 @@ 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 '/'
if '@' in r_scheme:
host_separator = r_scheme.find('@')
end = r_scheme.find("/", host_separator)
else:
end = r_scheme.find("/", 2)
end = r_scheme.find("/", 2)
if end == -1:
end = None
authority = r_scheme[2:end]

View File

@ -242,12 +242,15 @@ def library_recipes():
result.extend([
dict(
name="OpenSSL 1.1.1i",
url="https://www.openssl.org/source/openssl-1.1.1i.tar.gz",
checksum='08987c3cf125202e2b0840035efb392c',
name="OpenSSL 1.1.1g",
url="https://www.openssl.org/source/openssl-1.1.1g.tar.gz",
checksum='76766e98997660138cdaf13a187bd234',
buildrecipe=build_universal_openssl,
configure=None,
install=None,
patches=[
"openssl-mac-arm64.patch",
],
),
])
@ -260,10 +263,10 @@ def library_recipes():
tk_patches = ['tk868_on_10_8_10_9.patch']
else:
tcl_tk_ver='8.6.11'
tcl_checksum='8a4c004f48984a03a7747e9ba06e4da4'
tcl_tk_ver='8.6.10'
tcl_checksum='97c55573f8520bcab74e21bfd8d0aadc'
tk_checksum='c7ee71a2d05bba78dfffd76528dc17c6'
tk_checksum='602a47ad9ecac7bf655ada729d140a94'
tk_patches = [ ]
@ -354,9 +357,9 @@ def library_recipes():
),
),
dict(
name="SQLite 3.34.0",
url="https://sqlite.org/2020/sqlite-autoconf-3340000.tar.gz",
checksum='7f33c9db7b713957fcb9271fe9049fef',
name="SQLite 3.33.0",
url="https://sqlite.org/2020/sqlite-autoconf-3330000.tar.gz",
checksum='842a8a100d7b01b09e543deb2b7951dd',
extra_cflags=('-Os '
'-DSQLITE_ENABLE_FTS5 '
'-DSQLITE_ENABLE_FTS4 '
@ -1135,6 +1138,7 @@ 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)
@ -1611,7 +1615,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

@ -0,0 +1,41 @@
diff -ur openssl-1.1.1g-orig/Configurations/10-main.conf openssl-1.1.1g/Configurations/10-main.conf
--- openssl-1.1.1g-orig/Configurations/10-main.conf 2020-04-21 14:22:39.000000000 +0200
+++ openssl-1.1.1g/Configurations/10-main.conf 2020-07-26 12:21:32.000000000 +0200
@@ -1557,6 +1557,14 @@
bn_ops => "SIXTY_FOUR_BIT_LONG",
perlasm_scheme => "macosx",
},
+ "darwin64-arm64-cc" => {
+ inherit_from => [ "darwin-common", asm("aarch64_asm") ],
+ CFLAGS => add("-Wall"),
+ cflags => add("-arch arm64"),
+ lib_cppflags => add("-DL_ENDIAN"),
+ bn_ops => "SIXTY_FOUR_BIT_LONG",
+ perlasm_scheme => "ios64",
+ },
##### GNU Hurd
"hurd-x86" => {
diff -ur openssl-1.1.1g-orig/config openssl-1.1.1g/config
--- openssl-1.1.1g-orig/config 2020-04-21 14:22:39.000000000 +0200
+++ openssl-1.1.1g/config 2020-07-26 12:21:59.000000000 +0200
@@ -255,6 +255,9 @@
;;
x86_64)
echo "x86_64-apple-darwin${VERSION}"
+ ;;
+ arm64)
+ echo "arm64-apple-darwin${VERSION}"
;;
*)
echo "i686-apple-darwin${VERSION}"
@@ -497,6 +500,9 @@
else
OUT="darwin64-x86_64-cc"
fi ;;
+ x86_64-apple-darwin*)
+ OUT="darwin64-arm64-cc"
+ ;;
armv6+7-*-iphoneos)
__CNF_CFLAGS="$__CNF_CFLAGS -arch armv6 -arch armv7"
__CNF_CXXFLAGS="$__CNF_CXXFLAGS -arch armv6 -arch armv7"

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|fish)
bash|ksh|sh|*csh|zsh)
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,22 +76,6 @@ 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-2021 Python Software Foundation</string>
<string>%version%, © 2001-2020 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-2021 Python Software Foundation</string>
<string>%VERSION%, © 2001-2020 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