Compare commits
1 Commits
master
...
revert-239
Author | SHA1 | Date |
---|---|---|
Ethan Furman | 630d2e14c5 |
|
@ -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
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
|
@ -28,7 +28,7 @@ jobs:
|
||||||
- name: Check for source changes
|
- name: Check for source changes
|
||||||
id: check
|
id: check
|
||||||
run: |
|
run: |
|
||||||
if [ -z "$GITHUB_BASE_REF" ]; then
|
if [ -z "GITHUB_BASE_REF" ]; then
|
||||||
echo '::set-output name=run_tests::true'
|
echo '::set-output name=run_tests::true'
|
||||||
else
|
else
|
||||||
git fetch origin $GITHUB_BASE_REF --depth=1
|
git fetch origin $GITHUB_BASE_REF --depth=1
|
||||||
|
@ -99,8 +99,6 @@ jobs:
|
||||||
if: needs.check_source.outputs.run_tests == 'true'
|
if: needs.check_source.outputs.run_tests == 'true'
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
- name: Register MSVC problem matcher
|
|
||||||
run: echo "::add-matcher::.github/problem-matchers/msvc.json"
|
|
||||||
- name: Build CPython
|
- name: Build CPython
|
||||||
run: .\PCbuild\build.bat -e -p x64
|
run: .\PCbuild\build.bat -e -p x64
|
||||||
- name: Display build info
|
- name: Display build info
|
||||||
|
|
|
@ -4,7 +4,7 @@ Copyright
|
||||||
|
|
||||||
Python and this documentation is:
|
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.
|
Copyright © 2000 BeOpen.com. All rights reserved.
|
||||||
|
|
||||||
|
|
|
@ -934,42 +934,32 @@ here is a pure Python equivalent:
|
||||||
if doc is None and fget is not None:
|
if doc is None and fget is not None:
|
||||||
doc = fget.__doc__
|
doc = fget.__doc__
|
||||||
self.__doc__ = doc
|
self.__doc__ = doc
|
||||||
self._name = ''
|
|
||||||
|
|
||||||
def __set_name__(self, owner, name):
|
|
||||||
self._name = name
|
|
||||||
|
|
||||||
def __get__(self, obj, objtype=None):
|
def __get__(self, obj, objtype=None):
|
||||||
if obj is None:
|
if obj is None:
|
||||||
return self
|
return self
|
||||||
if self.fget is None:
|
if self.fget is None:
|
||||||
raise AttributeError(f'unreadable attribute {self._name}')
|
raise AttributeError("unreadable attribute")
|
||||||
return self.fget(obj)
|
return self.fget(obj)
|
||||||
|
|
||||||
def __set__(self, obj, value):
|
def __set__(self, obj, value):
|
||||||
if self.fset is None:
|
if self.fset is None:
|
||||||
raise AttributeError(f"can't set attribute {self._name}")
|
raise AttributeError("can't set attribute")
|
||||||
self.fset(obj, value)
|
self.fset(obj, value)
|
||||||
|
|
||||||
def __delete__(self, obj):
|
def __delete__(self, obj):
|
||||||
if self.fdel is None:
|
if self.fdel is None:
|
||||||
raise AttributeError(f"can't delete attribute {self._name}")
|
raise AttributeError("can't delete attribute")
|
||||||
self.fdel(obj)
|
self.fdel(obj)
|
||||||
|
|
||||||
def getter(self, fget):
|
def getter(self, fget):
|
||||||
prop = type(self)(fget, self.fset, self.fdel, self.__doc__)
|
return type(self)(fget, self.fset, self.fdel, self.__doc__)
|
||||||
prop._name = self._name
|
|
||||||
return prop
|
|
||||||
|
|
||||||
def setter(self, fset):
|
def setter(self, fset):
|
||||||
prop = type(self)(self.fget, fset, self.fdel, self.__doc__)
|
return type(self)(self.fget, fset, self.fdel, self.__doc__)
|
||||||
prop._name = self._name
|
|
||||||
return prop
|
|
||||||
|
|
||||||
def deleter(self, fdel):
|
def deleter(self, fdel):
|
||||||
prop = type(self)(self.fget, self.fset, fdel, self.__doc__)
|
return type(self)(self.fget, self.fset, fdel, self.__doc__)
|
||||||
prop._name = self._name
|
|
||||||
return prop
|
|
||||||
|
|
||||||
.. testcode::
|
.. testcode::
|
||||||
:hide:
|
:hide:
|
||||||
|
|
|
@ -112,15 +112,14 @@ The module :mod:`curses` defines the following functions:
|
||||||
.. function:: color_content(color_number)
|
.. function:: color_content(color_number)
|
||||||
|
|
||||||
Return the intensity of the red, green, and blue (RGB) components in the color
|
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
|
containing the R,G,B values for the given color, which will be between
|
||||||
``0`` (no component) and ``1000`` (maximum amount of component).
|
``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.
|
Return the attribute value for displaying text in the specified color. This
|
||||||
Only the first 256 color pairs are supported. This
|
|
||||||
attribute value can be combined with :const:`A_STANDOUT`, :const:`A_REVERSE`,
|
attribute value can be combined with :const:`A_STANDOUT`, :const:`A_REVERSE`,
|
||||||
and the other :const:`A_\*` attributes. :func:`pair_number` is the counterpart
|
and the other :const:`A_\*` attributes. :func:`pair_number` is the counterpart
|
||||||
to this function.
|
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
|
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
|
followed by three RGB values (for the amounts of red, green, and blue
|
||||||
components). The value of *color_number* must be between ``0`` and
|
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
|
``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
|
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``.
|
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 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
|
``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
|
be changed). The value of *fg* and *bg* arguments must be between ``0`` and
|
||||||
``COLORS - 1``, or, after calling :func:`use_default_colors`, ``-1``.
|
:const:`COLORS`. If the color-pair was previously initialized, the screen is
|
||||||
If the color-pair was previously initialized, the screen is
|
|
||||||
refreshed and all occurrences of that color-pair are changed to the new
|
refreshed and all occurrences of that color-pair are changed to the new
|
||||||
definition.
|
definition.
|
||||||
|
|
||||||
|
@ -452,7 +450,7 @@ The module :mod:`curses` defines the following functions:
|
||||||
.. function:: pair_content(pair_number)
|
.. function:: pair_content(pair_number)
|
||||||
|
|
||||||
Return a tuple ``(fg, bg)`` containing the colors for the requested color pair.
|
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)
|
.. function:: pair_number(attr)
|
||||||
|
|
|
@ -289,7 +289,7 @@ variant, :attr:`~.BaseHeader.max_count` is set to 1.
|
||||||
A :class:`ParameterizedMIMEHeader` class that handles the
|
A :class:`ParameterizedMIMEHeader` class that handles the
|
||||||
:mailheader:`Content-Disposition` header.
|
:mailheader:`Content-Disposition` header.
|
||||||
|
|
||||||
.. attribute:: content_disposition
|
.. attribute:: content-disposition
|
||||||
|
|
||||||
``inline`` and ``attachment`` are the only valid values in common use.
|
``inline`` and ``attachment`` are the only valid values in common use.
|
||||||
|
|
||||||
|
|
|
@ -62,26 +62,16 @@ The :mod:`functools` module defines the following functions:
|
||||||
Example::
|
Example::
|
||||||
|
|
||||||
class DataSet:
|
class DataSet:
|
||||||
|
|
||||||
def __init__(self, sequence_of_numbers):
|
def __init__(self, sequence_of_numbers):
|
||||||
self._data = tuple(sequence_of_numbers)
|
self._data = sequence_of_numbers
|
||||||
|
|
||||||
@cached_property
|
@cached_property
|
||||||
def stdev(self):
|
def stdev(self):
|
||||||
return statistics.stdev(self._data)
|
return statistics.stdev(self._data)
|
||||||
|
|
||||||
The mechanics of :func:`cached_property` are somewhat different from
|
@cached_property
|
||||||
:func:`property`. A regular property blocks attribute writes unless a
|
def variance(self):
|
||||||
setter is defined. In contrast, a *cached_property* allows writes.
|
return statistics.variance(self._data)
|
||||||
|
|
||||||
The *cached_property* decorator only runs on lookups and only when an
|
|
||||||
attribute of the same name doesn't exist. When it does run, the
|
|
||||||
*cached_property* writes to the attribute with the same name. Subsequent
|
|
||||||
attribute reads and writes take precedence over the *cached_property*
|
|
||||||
method and it works like a normal attribute.
|
|
||||||
|
|
||||||
The cached value can be cleared by deleting the attribute. This
|
|
||||||
allows the *cached_property* method to run again.
|
|
||||||
|
|
||||||
Note, this decorator interferes with the operation of :pep:`412`
|
Note, this decorator interferes with the operation of :pep:`412`
|
||||||
key-sharing dictionaries. This means that instance dictionaries
|
key-sharing dictionaries. This means that instance dictionaries
|
||||||
|
|
|
@ -115,9 +115,8 @@ Every distribution includes some metadata, which you can extract using the
|
||||||
|
|
||||||
>>> wheel_metadata = metadata('wheel') # doctest: +SKIP
|
>>> wheel_metadata = metadata('wheel') # doctest: +SKIP
|
||||||
|
|
||||||
The keys of the returned data structure, a ``PackageMetadata``,
|
The keys of the returned data structure [#f1]_ name the metadata keywords, and
|
||||||
name the metadata keywords, and
|
their values are returned unparsed from the distribution metadata::
|
||||||
the values are returned unparsed from the distribution metadata::
|
|
||||||
|
|
||||||
>>> wheel_metadata['Requires-Python'] # doctest: +SKIP
|
>>> wheel_metadata['Requires-Python'] # doctest: +SKIP
|
||||||
'>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*'
|
'>=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``
|
There are all kinds of additional metadata available on the ``Distribution``
|
||||||
instance::
|
instance::
|
||||||
|
|
||||||
>>> dist.metadata['Requires-Python'] # doctest: +SKIP
|
>>> d.metadata['Requires-Python'] # doctest: +SKIP
|
||||||
'>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*'
|
'>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*'
|
||||||
>>> dist.metadata['License'] # doctest: +SKIP
|
>>> d.metadata['License'] # doctest: +SKIP
|
||||||
'MIT'
|
'MIT'
|
||||||
|
|
||||||
The full set of available metadata is not described here. See :pep:`566`
|
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
|
.. 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.
|
||||||
|
|
|
@ -786,18 +786,6 @@ which incur interpreter overhead.
|
||||||
def dotproduct(vec1, vec2):
|
def dotproduct(vec1, vec2):
|
||||||
return sum(map(operator.mul, 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):
|
def flatten(list_of_lists):
|
||||||
"Flatten one level of nesting"
|
"Flatten one level of nesting"
|
||||||
return chain.from_iterable(list_of_lists)
|
return chain.from_iterable(list_of_lists)
|
||||||
|
|
|
@ -665,14 +665,14 @@ The ``errors`` module has the following attributes:
|
||||||
|
|
||||||
.. data:: codes
|
.. data:: codes
|
||||||
|
|
||||||
A dictionary mapping string descriptions to their error codes.
|
A dictionary mapping numeric error codes to their string descriptions.
|
||||||
|
|
||||||
.. versionadded:: 3.2
|
.. versionadded:: 3.2
|
||||||
|
|
||||||
|
|
||||||
.. data:: messages
|
.. data:: messages
|
||||||
|
|
||||||
A dictionary mapping numeric error codes to their string descriptions.
|
A dictionary mapping string descriptions to their error codes.
|
||||||
|
|
||||||
.. versionadded:: 3.2
|
.. versionadded:: 3.2
|
||||||
|
|
||||||
|
|
|
@ -135,15 +135,6 @@ Functions for integers
|
||||||
values. Formerly it used a style like ``int(random()*n)`` which could produce
|
values. Formerly it used a style like ``int(random()*n)`` which could produce
|
||||||
slightly uneven distributions.
|
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)
|
.. function:: randint(a, b)
|
||||||
|
|
||||||
Return a random integer *N* such that ``a <= N <= b``. Alias for
|
Return a random integer *N* such that ``a <= N <= b``. Alias for
|
||||||
|
|
|
@ -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;
|
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.
|
otherwise, it performs a 2-byte swap operation.
|
||||||
|
|
||||||
.. versionchanged:: 3.10
|
.. deprecated:: 3.7
|
||||||
Raises :exc:`OverflowError` if *x* does not fit in a 16-bit unsigned
|
In case *x* does not fit in 16-bit unsigned integer, but does fit in a
|
||||||
integer.
|
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)
|
.. 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;
|
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.
|
otherwise, it performs a 2-byte swap operation.
|
||||||
|
|
||||||
.. versionchanged:: 3.10
|
.. deprecated:: 3.7
|
||||||
Raises :exc:`OverflowError` if *x* does not fit in a 16-bit unsigned
|
In case *x* does not fit in 16-bit unsigned integer, but does fit in a
|
||||||
integer.
|
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)
|
.. function:: inet_aton(ip_string)
|
||||||
|
|
|
@ -546,7 +546,7 @@ Connection Objects
|
||||||
con.close()
|
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
|
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
|
by other clients, or concurrently by the same connection. The copy will be
|
||||||
|
|
|
@ -198,7 +198,7 @@ However, for reading convenience, most of the examples show sorted sequences.
|
||||||
|
|
||||||
.. versionadded:: 3.6
|
.. versionadded:: 3.6
|
||||||
|
|
||||||
.. versionchanged:: 3.10
|
.. versionchanged:: 3.8
|
||||||
Added support for *weights*.
|
Added support for *weights*.
|
||||||
|
|
||||||
.. function:: median(data)
|
.. function:: median(data)
|
||||||
|
|
|
@ -4959,11 +4959,6 @@ All parameterized generics implement special read-only attributes.
|
||||||
(~T,)
|
(~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::
|
.. seealso::
|
||||||
|
|
||||||
* :pep:`585` -- "Type Hinting Generics In Standard Collections"
|
* :pep:`585` -- "Type Hinting Generics In Standard Collections"
|
||||||
|
|
|
@ -1187,9 +1187,8 @@ calls these functions.
|
||||||
The arguments shown above are merely some common ones.
|
The arguments shown above are merely some common ones.
|
||||||
The full function signature is largely the same as that of :func:`run` -
|
The full function signature is largely the same as that of :func:`run` -
|
||||||
most arguments are passed directly through to that interface.
|
most arguments are passed directly through to that interface.
|
||||||
One API deviation from :func:`run` behavior exists: passing ``input=None``
|
However, explicitly passing ``input=None`` to inherit the parent's
|
||||||
will behave the same as ``input=b''`` (or ``input=''``, depending on other
|
standard input file handle is not supported.
|
||||||
arguments) rather than using the parent's standard input file handle.
|
|
||||||
|
|
||||||
By default, this function will return the data as encoded bytes. The actual
|
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
|
encoding of the output data may depend on the command being invoked, so the
|
||||||
|
|
|
@ -160,8 +160,6 @@ Examining Symbol Tables
|
||||||
|
|
||||||
Return ``True`` if the symbol is annotated.
|
Return ``True`` if the symbol is annotated.
|
||||||
|
|
||||||
.. versionadded:: 3.6
|
|
||||||
|
|
||||||
.. method:: is_free()
|
.. method:: is_free()
|
||||||
|
|
||||||
Return ``True`` if the symbol is referenced in its block, but not assigned
|
Return ``True`` if the symbol is referenced in its block, but not assigned
|
||||||
|
|
|
@ -91,9 +91,6 @@ The different font weights and slants are:
|
||||||
|
|
||||||
Return the names of defined fonts.
|
Return the names of defined fonts.
|
||||||
|
|
||||||
.. function:: nametofont(name, root=None)
|
.. function:: nametofont(name)
|
||||||
|
|
||||||
Return a :class:`Font` representation of a tk named font.
|
Return a :class:`Font` representation of a tk named font.
|
||||||
|
|
||||||
.. versionchanged:: 3.10
|
|
||||||
The *root* parameter was added.
|
|
|
@ -18,8 +18,7 @@
|
||||||
--------------
|
--------------
|
||||||
|
|
||||||
This module provides runtime support for type hints as specified by
|
This module provides runtime support for type hints as specified by
|
||||||
:pep:`484`, :pep:`526`, :pep:`544`, :pep:`586`, :pep:`589`, :pep:`591`,
|
:pep:`484`, :pep:`526`, :pep:`544`, :pep:`586`, :pep:`589`, :pep:`591`, and :pep:`613`.
|
||||||
:pep:`612` and :pep:`613`.
|
|
||||||
The most fundamental support consists of the types :data:`Any`, :data:`Union`,
|
The most fundamental support consists of the types :data:`Any`, :data:`Union`,
|
||||||
:data:`Tuple`, :data:`Callable`, :class:`TypeVar`, and
|
:data:`Tuple`, :data:`Callable`, :class:`TypeVar`, and
|
||||||
:class:`Generic`. For full specification please see :pep:`484`. For
|
: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
|
the call signature by substituting a literal ellipsis
|
||||||
for the list of arguments in the type hint: ``Callable[..., ReturnType]``.
|
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:
|
||||||
|
|
||||||
Generics
|
Generics
|
||||||
|
@ -333,43 +316,6 @@ User defined generic type aliases are also supported. Examples::
|
||||||
.. versionchanged:: 3.7
|
.. versionchanged:: 3.7
|
||||||
:class:`Generic` no longer has a custom metaclass.
|
: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
|
A user-defined generic class can have ABCs as base classes without a metaclass
|
||||||
conflict. Generic metaclasses are not supported. The outcome of parameterizing
|
conflict. Generic metaclasses are not supported. The outcome of parameterizing
|
||||||
generics is cached, and most types in the typing module are hashable and
|
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
|
``Callable[..., Any]``, and in turn to
|
||||||
:class:`collections.abc.Callable`.
|
: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
|
.. deprecated:: 3.9
|
||||||
:class:`collections.abc.Callable` now supports ``[]``. See :pep:`585` and
|
:class:`collections.abc.Callable` now supports ``[]``. See :pep:`585` and
|
||||||
:ref:`types-genericalias`.
|
: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])
|
.. class:: Type(Generic[CT_co])
|
||||||
|
|
||||||
A variable annotated with ``C`` may accept a value of type ``C``. In
|
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,
|
for the type variable must be a subclass of the boundary type,
|
||||||
see :pep:`484`.
|
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
|
.. data:: AnyStr
|
||||||
|
|
||||||
``AnyStr`` is a type variable defined as
|
``AnyStr`` is a type variable defined as
|
||||||
|
|
|
@ -100,7 +100,7 @@ PSF LICENSE AGREEMENT FOR PYTHON |release|
|
||||||
analyze, test, perform and/or display publicly, prepare derivative works,
|
analyze, test, perform and/or display publicly, prepare derivative works,
|
||||||
distribute, and otherwise use Python |release| alone or in any derivative
|
distribute, and otherwise use Python |release| alone or in any derivative
|
||||||
version, provided, however, that PSF's License Agreement and PSF's notice of
|
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
|
Reserved" are retained in Python |release| alone or in any derivative version
|
||||||
prepared by Licensee.
|
prepared by Licensee.
|
||||||
|
|
||||||
|
|
|
@ -168,7 +168,6 @@ library/ipaddress,,::,2001:db00::0/24
|
||||||
library/ipaddress,,:db00,2001:db00::0/ffff:ff00::
|
library/ipaddress,,:db00,2001:db00::0/ffff:ff00::
|
||||||
library/ipaddress,,::,2001:db00::0/ffff:ff00::
|
library/ipaddress,,::,2001:db00::0/ffff:ff00::
|
||||||
library/itertools,,:step,elements from seq[start:stop:step]
|
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/itertools,,:stop,elements from seq[start:stop:step]
|
||||||
library/logging.handlers,,:port,host:port
|
library/logging.handlers,,:port,host:port
|
||||||
library/mmap,,:i2,obj[i1:i2]
|
library/mmap,,:i2,obj[i1:i2]
|
||||||
|
|
|
|
@ -144,28 +144,6 @@ See :pep:`604` for more details.
|
||||||
|
|
||||||
(Contributed by Maggie Moss and Philippe Prados in :issue:`41428`.)
|
(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
|
Other Language Changes
|
||||||
======================
|
======================
|
||||||
|
|
||||||
|
@ -426,11 +404,9 @@ Optimizations
|
||||||
average.
|
average.
|
||||||
(Contributed by Victor Stinner in :issue:`41006`.)
|
(Contributed by Victor Stinner in :issue:`41006`.)
|
||||||
|
|
||||||
* The ``LOAD_ATTR`` instruction now uses new "per opcode cache" mechanism. It
|
* The ``LOAD_ATTR`` instruction now uses new "per opcode cache" mechanism.
|
||||||
is about 36% faster now. This makes optimized ``LOAD_ATTR`` instructions the
|
It is about 36% faster now. (Contributed by Pablo Galindo and Yury Selivanov
|
||||||
current most performance attribute access method (faster than slots).
|
in :issue:`42093`, based on ideas implemented originally in PyPy and MicroPython.)
|
||||||
(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
|
* When building Python with ``--enable-optimizations`` now
|
||||||
``-fno-semantic-interposition`` is added to both the compile and link line.
|
``-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.
|
silently in Python 3.9.
|
||||||
(Contributed by Ken Jin in :issue:`42195`.)
|
(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
|
CPython bytecode changes
|
||||||
========================
|
========================
|
||||||
|
|
||||||
|
@ -588,10 +558,6 @@ Build Changes
|
||||||
* The :mod:`atexit` module must now always be built as a built-in module.
|
* The :mod:`atexit` module must now always be built as a built-in module.
|
||||||
(Contributed by Victor Stinner in :issue:`42639`.)
|
(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
|
C API Changes
|
||||||
=============
|
=============
|
||||||
|
|
|
@ -1482,37 +1482,4 @@ and to match the behavior of static type checkers specified in the PEP.
|
||||||
File "<stdin>", line 1, in <module>
|
File "<stdin>", line 1, in <module>
|
||||||
TypeError: unhashable type: 'set'
|
TypeError: unhashable type: 'set'
|
||||||
|
|
||||||
(Contributed by Yurii Karabas in :issue:`42345`.)
|
(Contributed by Yurii Karabas in :issue:`42345`.)
|
||||||
|
|
||||||
macOS 11.0 (Big Sur) and Apple Silicon Mac support
|
|
||||||
--------------------------------------------------
|
|
||||||
|
|
||||||
As of 3.9.1, Python now fully supports building and running on macOS 11.0
|
|
||||||
(Big Sur) and on Apple Silicon Macs (based on the ``ARM64`` architecture).
|
|
||||||
A new universal build variant, ``universal2``, is now available to natively
|
|
||||||
support both ``ARM64`` and ``Intel 64`` in one set of executables. Binaries
|
|
||||||
can also now be built on current versions of macOS to be deployed on a range
|
|
||||||
of older macOS versions (tested to 10.9) while making some newer OS
|
|
||||||
functions and options conditionally available based on the operating system
|
|
||||||
version in use at runtime ("weaklinking").
|
|
||||||
|
|
||||||
(Contributed by Ronald Oussoren and Lawrence D'Anna in :issue:`41100`.)
|
|
||||||
|
|
||||||
Notable changes in Python 3.9.2
|
|
||||||
===============================
|
|
||||||
|
|
||||||
collections.abc
|
|
||||||
---------------
|
|
||||||
|
|
||||||
:class:`collections.abc.Callable` generic now flattens type parameters, similar
|
|
||||||
to what :data:`typing.Callable` currently does. This means that
|
|
||||||
``collections.abc.Callable[[int, str], str]`` will have ``__args__`` of
|
|
||||||
``(int, str, str)``; previously this was ``([int, str], str)``. To allow this
|
|
||||||
change, :class:`types.GenericAlias` can now be subclassed, and a subclass will
|
|
||||||
be returned when subscripting the :class:`collections.abc.Callable` type.
|
|
||||||
Code which accesses the arguments via :func:`typing.get_args` or ``__args__``
|
|
||||||
need to account for this change. A :exc:`DeprecationWarning` may be emitted for
|
|
||||||
invalid forms of parameterizing :class:`collections.abc.Callable` which may have
|
|
||||||
passed silently in Python 3.9.1. This :exc:`DeprecationWarning` will
|
|
||||||
become a :exc:`TypeError` in Python 3.10.
|
|
||||||
(Contributed by Ken Jin in :issue:`42195`.)
|
|
|
@ -580,23 +580,18 @@ star_targets[expr_ty]:
|
||||||
| a=star_target !',' { a }
|
| a=star_target !',' { a }
|
||||||
| a=star_target b=(',' c=star_target { c })* [','] {
|
| a=star_target b=(',' c=star_target { c })* [','] {
|
||||||
_Py_Tuple(CHECK(asdl_expr_seq*, _PyPegen_seq_insert_in_front(p, a, b)), Store, EXTRA) }
|
_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_seq[asdl_expr_seq*]: a[asdl_expr_seq*]=','.star_target+ [','] { a }
|
||||||
star_targets_tuple_seq[asdl_expr_seq*]:
|
|
||||||
| a=star_target b=(',' c=star_target { c })+ [','] { (asdl_expr_seq*) _PyPegen_seq_insert_in_front(p, a, b) }
|
|
||||||
| a=star_target ',' { (asdl_expr_seq*) _PyPegen_singleton_seq(p, a) }
|
|
||||||
star_target[expr_ty] (memo):
|
star_target[expr_ty] (memo):
|
||||||
| '*' a=(!'*' star_target) {
|
| '*' a=(!'*' star_target) {
|
||||||
_Py_Starred(CHECK(expr_ty, _PyPegen_set_expr_context(p, a, Store)), Store, EXTRA) }
|
_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=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) }
|
| a=t_primary '[' b=slices ']' !t_lookahead { _Py_Subscript(a, b, Store, EXTRA) }
|
||||||
| star_atom
|
| star_atom
|
||||||
star_atom[expr_ty]:
|
star_atom[expr_ty]:
|
||||||
| a=NAME { _PyPegen_set_expr_context(p, a, Store) }
|
| a=NAME { _PyPegen_set_expr_context(p, a, Store) }
|
||||||
| '(' a=target_with_star_atom ')' { _PyPegen_set_expr_context(p, a, Store) }
|
| '(' a=star_target ')' { _PyPegen_set_expr_context(p, a, Store) }
|
||||||
| '(' a=[star_targets_tuple_seq] ')' { _Py_Tuple(a, Store, EXTRA) }
|
| '(' a=[star_targets_seq] ')' { _Py_Tuple(a, Store, EXTRA) }
|
||||||
| '[' a=[star_targets_list_seq] ']' { _Py_List(a, Store, EXTRA) }
|
| '[' a=[star_targets_seq] ']' { _Py_List(a, Store, EXTRA) }
|
||||||
|
|
||||||
single_target[expr_ty]:
|
single_target[expr_ty]:
|
||||||
| single_subscript_attribute_target
|
| single_subscript_attribute_target
|
||||||
|
|
|
@ -63,7 +63,7 @@ PyVectorcall_Function(PyObject *callable)
|
||||||
{
|
{
|
||||||
PyTypeObject *tp;
|
PyTypeObject *tp;
|
||||||
Py_ssize_t offset;
|
Py_ssize_t offset;
|
||||||
vectorcallfunc ptr;
|
vectorcallfunc *ptr;
|
||||||
|
|
||||||
assert(callable != NULL);
|
assert(callable != NULL);
|
||||||
tp = Py_TYPE(callable);
|
tp = Py_TYPE(callable);
|
||||||
|
@ -73,8 +73,8 @@ PyVectorcall_Function(PyObject *callable)
|
||||||
assert(PyCallable_Check(callable));
|
assert(PyCallable_Check(callable));
|
||||||
offset = tp->tp_vectorcall_offset;
|
offset = tp->tp_vectorcall_offset;
|
||||||
assert(offset > 0);
|
assert(offset > 0);
|
||||||
memcpy(&ptr, (char *) callable + offset, sizeof(ptr));
|
ptr = (vectorcallfunc *)(((char *)callable) + offset);
|
||||||
return ptr;
|
return *ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Call the callable object 'callable' with the "vectorcall" calling
|
/* Call the callable object 'callable' with the "vectorcall" calling
|
||||||
|
|
|
@ -35,13 +35,12 @@ PyAPI_FUNC(Py_ssize_t) _Py_GetRefTotal(void);
|
||||||
_PyObject_{Get,Set,Has}AttrId are __getattr__ versions using _Py_Identifier*.
|
_PyObject_{Get,Set,Has}AttrId are __getattr__ versions using _Py_Identifier*.
|
||||||
*/
|
*/
|
||||||
typedef struct _Py_Identifier {
|
typedef struct _Py_Identifier {
|
||||||
|
struct _Py_Identifier *next;
|
||||||
const char* string;
|
const char* string;
|
||||||
// Index in PyInterpreterState.unicode.ids.array. It is process-wide
|
PyObject *object;
|
||||||
// unique and must be initialized to -1.
|
|
||||||
Py_ssize_t index;
|
|
||||||
} _Py_Identifier;
|
} _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_static_string(varname, value) static _Py_Identifier varname = _Py_static_string_init(value)
|
||||||
#define _Py_IDENTIFIER(varname) _Py_static_string(PyId_##varname, #varname)
|
#define _Py_IDENTIFIER(varname) _Py_static_string(PyId_##varname, #varname)
|
||||||
|
|
||||||
|
|
|
@ -64,11 +64,6 @@ struct _Py_bytes_state {
|
||||||
PyBytesObject *characters[256];
|
PyBytesObject *characters[256];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct _Py_unicode_ids {
|
|
||||||
Py_ssize_t size;
|
|
||||||
PyObject **array;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct _Py_unicode_state {
|
struct _Py_unicode_state {
|
||||||
// The empty Unicode object is a singleton to improve performance.
|
// The empty Unicode object is a singleton to improve performance.
|
||||||
PyObject *empty_string;
|
PyObject *empty_string;
|
||||||
|
@ -76,19 +71,6 @@ struct _Py_unicode_state {
|
||||||
shared as well. */
|
shared as well. */
|
||||||
PyObject *latin1[256];
|
PyObject *latin1[256];
|
||||||
struct _Py_unicode_fs_codec fs_codec;
|
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 {
|
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 */
|
/* interpreter state */
|
||||||
|
|
||||||
#define _PY_NSMALLPOSINTS 257
|
#define _PY_NSMALLPOSINTS 257
|
||||||
|
@ -316,7 +277,6 @@ struct _is {
|
||||||
struct _Py_exc_state exc_state;
|
struct _Py_exc_state exc_state;
|
||||||
|
|
||||||
struct ast_state ast;
|
struct ast_state ast;
|
||||||
struct type_cache type_cache;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
extern void _PyInterpreterState_ClearModules(PyInterpreterState *interp);
|
extern void _PyInterpreterState_ClearModules(PyInterpreterState *interp);
|
||||||
|
|
|
@ -27,9 +27,6 @@ _PyType_HasFeature(PyTypeObject *type, unsigned long feature) {
|
||||||
return ((type->tp_flags & feature) != 0);
|
return ((type->tp_flags & feature) != 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
extern void _PyType_InitCache(PyInterpreterState *interp);
|
|
||||||
|
|
||||||
|
|
||||||
/* Inline functions trading binary compatibility for speed:
|
/* Inline functions trading binary compatibility for speed:
|
||||||
_PyObject_Init() is the fast version of PyObject_Init(), and
|
_PyObject_Init() is the fast version of PyObject_Init(), and
|
||||||
_PyObject_InitVar() is the fast version of PyObject_InitVar().
|
_PyObject_InitVar() is the fast version of PyObject_InitVar().
|
||||||
|
|
|
@ -76,7 +76,7 @@ extern void _PyExc_Fini(PyThreadState *tstate);
|
||||||
extern void _PyImport_Fini(void);
|
extern void _PyImport_Fini(void);
|
||||||
extern void _PyImport_Fini2(void);
|
extern void _PyImport_Fini2(void);
|
||||||
extern void _PyGC_Fini(PyThreadState *tstate);
|
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 _Py_HashRandomization_Fini(void);
|
||||||
extern void _PyUnicode_Fini(PyThreadState *tstate);
|
extern void _PyUnicode_Fini(PyThreadState *tstate);
|
||||||
extern void _PyUnicode_ClearInterned(PyThreadState *tstate);
|
extern void _PyUnicode_ClearInterned(PyThreadState *tstate);
|
||||||
|
|
|
@ -49,11 +49,6 @@ typedef struct _Py_AuditHookEntry {
|
||||||
void *userData;
|
void *userData;
|
||||||
} _Py_AuditHookEntry;
|
} _Py_AuditHookEntry;
|
||||||
|
|
||||||
struct _Py_unicode_runtime_ids {
|
|
||||||
PyThread_type_lock lock;
|
|
||||||
Py_ssize_t next_index;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Full Python runtime state */
|
/* Full Python runtime state */
|
||||||
|
|
||||||
typedef struct pyruntimestate {
|
typedef struct pyruntimestate {
|
||||||
|
@ -111,8 +106,6 @@ typedef struct pyruntimestate {
|
||||||
void *open_code_userdata;
|
void *open_code_userdata;
|
||||||
_Py_AuditHookEntry *audit_hook_head;
|
_Py_AuditHookEntry *audit_hook_head;
|
||||||
|
|
||||||
struct _Py_unicode_runtime_ids unicode_ids;
|
|
||||||
|
|
||||||
// XXX Consolidate globals found via the check-c-globals script.
|
// XXX Consolidate globals found via the check-c-globals script.
|
||||||
} _PyRuntimeState;
|
} _PyRuntimeState;
|
||||||
|
|
||||||
|
|
|
@ -20,10 +20,10 @@
|
||||||
#define PY_MINOR_VERSION 10
|
#define PY_MINOR_VERSION 10
|
||||||
#define PY_MICRO_VERSION 0
|
#define PY_MICRO_VERSION 0
|
||||||
#define PY_RELEASE_LEVEL PY_RELEASE_LEVEL_ALPHA
|
#define PY_RELEASE_LEVEL PY_RELEASE_LEVEL_ALPHA
|
||||||
#define PY_RELEASE_SERIAL 4
|
#define PY_RELEASE_SERIAL 3
|
||||||
|
|
||||||
/* Version as a string */
|
/* Version as a string */
|
||||||
#define PY_VERSION "3.10.0a4+"
|
#define PY_VERSION "3.10.0a3+"
|
||||||
/*--end constants--*/
|
/*--end constants--*/
|
||||||
|
|
||||||
/* Version as a single 4-byte hex number, e.g. 0x010502B2 == 1.5.2b2.
|
/* Version as a single 4-byte hex number, e.g. 0x010502B2 == 1.5.2b2.
|
||||||
|
|
2
LICENSE
2
LICENSE
|
@ -84,7 +84,7 @@ analyze, test, perform and/or display publicly, prepare derivative works,
|
||||||
distribute, and otherwise use Python alone or in any derivative version,
|
distribute, and otherwise use Python alone or in any derivative version,
|
||||||
provided, however, that PSF's License Agreement and PSF's notice of copyright,
|
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,
|
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
|
All Rights Reserved" are retained in Python alone or in any derivative version
|
||||||
prepared by Licensee.
|
prepared by Licensee.
|
||||||
|
|
||||||
|
|
|
@ -63,10 +63,7 @@ def literal_eval(node_or_string):
|
||||||
if isinstance(node_or_string, Expression):
|
if isinstance(node_or_string, Expression):
|
||||||
node_or_string = node_or_string.body
|
node_or_string = node_or_string.body
|
||||||
def _raise_malformed_node(node):
|
def _raise_malformed_node(node):
|
||||||
msg = "malformed node or string"
|
raise ValueError(f'malformed node or string: {node!r}')
|
||||||
if lno := getattr(node, 'lineno', None):
|
|
||||||
msg += f' on line {lno}'
|
|
||||||
raise ValueError(msg + f': {node!r}')
|
|
||||||
def _convert_num(node):
|
def _convert_num(node):
|
||||||
if not isinstance(node, Constant) or type(node.value) not in (int, float, complex):
|
if not isinstance(node, Constant) or type(node.value) not in (int, float, complex):
|
||||||
_raise_malformed_node(node)
|
_raise_malformed_node(node)
|
||||||
|
|
|
@ -344,7 +344,7 @@ def a85encode(b, *, foldspaces=False, wrapcol=0, pad=False, adobe=False):
|
||||||
global _a85chars, _a85chars2
|
global _a85chars, _a85chars2
|
||||||
# Delay the initialization of tables to not waste memory
|
# Delay the initialization of tables to not waste memory
|
||||||
# if the function is never called
|
# if the function is never called
|
||||||
if _a85chars2 is None:
|
if _a85chars is None:
|
||||||
_a85chars = [bytes((i,)) for i in range(33, 118)]
|
_a85chars = [bytes((i,)) for i in range(33, 118)]
|
||||||
_a85chars2 = [(a + b) for a in _a85chars for b in _a85chars]
|
_a85chars2 = [(a + b) for a in _a85chars for b in _a85chars]
|
||||||
|
|
||||||
|
@ -452,7 +452,7 @@ def b85encode(b, pad=False):
|
||||||
global _b85chars, _b85chars2
|
global _b85chars, _b85chars2
|
||||||
# Delay the initialization of tables to not waste memory
|
# Delay the initialization of tables to not waste memory
|
||||||
# if the function is never called
|
# if the function is never called
|
||||||
if _b85chars2 is None:
|
if _b85chars is None:
|
||||||
_b85chars = [bytes((i,)) for i in _b85alphabet]
|
_b85chars = [bytes((i,)) for i in _b85alphabet]
|
||||||
_b85chars2 = [(a + b) for a in _b85chars for b in _b85chars]
|
_b85chars2 = [(a + b) for a in _b85chars for b in _b85chars]
|
||||||
return _85encode(b, _b85chars, _b85chars2, pad)
|
return _85encode(b, _b85chars, _b85chars2, pad)
|
||||||
|
|
|
@ -178,7 +178,7 @@ class EnumMeta(type):
|
||||||
Metaclass for Enum
|
Metaclass for Enum
|
||||||
"""
|
"""
|
||||||
@classmethod
|
@classmethod
|
||||||
def __prepare__(metacls, cls, bases, **kwds):
|
def __prepare__(metacls, cls, bases):
|
||||||
# check that previous enum members do not exist
|
# check that previous enum members do not exist
|
||||||
metacls._check_for_existing_members(cls, bases)
|
metacls._check_for_existing_members(cls, bases)
|
||||||
# create the namespace dict
|
# create the namespace dict
|
||||||
|
@ -235,10 +235,10 @@ class EnumMeta(type):
|
||||||
# create our new Enum type
|
# create our new Enum type
|
||||||
if bases:
|
if bases:
|
||||||
bases = (_NoInitSubclass, ) + 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, )
|
enum_class.__bases__ = enum_class.__bases__[1:] #or (object, )
|
||||||
else:
|
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)
|
old_init_subclass = getattr(enum_class, '__init_subclass__', None)
|
||||||
# and restore the new one (if there was one)
|
# and restore the new one (if there was one)
|
||||||
if new_init_subclass is not None:
|
if new_init_subclass is not None:
|
||||||
|
|
|
@ -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
|
bpo-42508: Keep IDLE running on macOS. Remove obsolete workaround
|
||||||
that prevented running files with shortcuts when using new universal2
|
that prevented running files with shortcuts when using new universal2
|
||||||
installers built on macOS 11.
|
installers built on macOS 11.
|
||||||
|
|
|
@ -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
|
Shell Preferences: Auto-Squeeze Min. Lines is the minimum number of lines
|
||||||
of output to automatically "squeeze".
|
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.
|
|
||||||
''',
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -28,8 +28,8 @@ variables:
|
||||||
(There are a few more, but they are rarely useful.)
|
(There are a few more, but they are rarely useful.)
|
||||||
|
|
||||||
The extension class must not directly bind Window Manager (e.g. X) events.
|
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
|
Rather, it must define one or more virtual events, e.g. <<zoom-height>>, and
|
||||||
corresponding methods, e.g. z_in_event(). The virtual events will be
|
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
|
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
|
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
|
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
|
implement. (They are also not required to create keybindings, but in that
|
||||||
case there must be empty bindings in cofig-extensions.def)
|
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 = [
|
menudefs = [
|
||||||
('format', [
|
('edit', [
|
||||||
('Z in', '<<z-in>>'),
|
None, # Separator
|
||||||
('Z out', '<<z-out>>'),
|
('_Zoom Height', '<<zoom-height>>'),
|
||||||
] )
|
])
|
||||||
]
|
]
|
||||||
|
|
||||||
def __init__(self, editwin):
|
def __init__(self, editwin):
|
||||||
self.editwin = editwin
|
self.editwin = editwin
|
||||||
|
|
||||||
def z_in_event(self, event=None):
|
def zoom_height_event(self, event):
|
||||||
"...Do what you want here..."
|
"...Do what you want here..."
|
||||||
|
|
||||||
The final piece of the puzzle is the file "config-extensions.def", which is
|
The final piece of the puzzle is the file "config-extensions.def", which is
|
||||||
|
|
|
@ -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)
|
|
|
@ -1,73 +1,42 @@
|
||||||
"""Example extension, also used for testing.
|
"Example extension, also used for testing."
|
||||||
|
|
||||||
See extend.txt for more details on creating an extension.
|
|
||||||
See config-extension.def for configuring an extension.
|
|
||||||
"""
|
|
||||||
|
|
||||||
from idlelib.config import idleConf
|
from idlelib.config import idleConf
|
||||||
from functools import wraps
|
|
||||||
|
|
||||||
|
ztext = idleConf.GetOption('extensions', 'ZzDummy', 'z-text')
|
||||||
def format_selection(format_line):
|
|
||||||
"Apply a formatting function to all of the selected lines."
|
|
||||||
|
|
||||||
@wraps(format_line)
|
|
||||||
def apply(self, event=None):
|
|
||||||
head, tail, chars, lines = self.formatter.get_region()
|
|
||||||
for pos in range(len(lines) - 1):
|
|
||||||
line = lines[pos]
|
|
||||||
lines[pos] = format_line(self, line)
|
|
||||||
self.formatter.set_region(head, tail, chars, lines)
|
|
||||||
return 'break'
|
|
||||||
|
|
||||||
return apply
|
|
||||||
|
|
||||||
|
|
||||||
class ZzDummy:
|
class ZzDummy:
|
||||||
"""Prepend or remove initial text from selected lines."""
|
|
||||||
|
|
||||||
# Extend the format menu.
|
## menudefs = [
|
||||||
menudefs = [
|
## ('format', [
|
||||||
('format', [
|
## ('Z in', '<<z-in>>'),
|
||||||
('Z in', '<<z-in>>'),
|
## ('Z out', '<<z-out>>'),
|
||||||
('Z out', '<<z-out>>'),
|
## ] )
|
||||||
] )
|
## ]
|
||||||
]
|
|
||||||
|
|
||||||
def __init__(self, editwin):
|
def __init__(self, editwin):
|
||||||
"Initialize the settings for this extension."
|
|
||||||
self.editwin = editwin
|
|
||||||
self.text = editwin.text
|
self.text = editwin.text
|
||||||
self.formatter = editwin.fregion
|
z_in = False
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def reload(cls):
|
def reload(cls):
|
||||||
"Load class variables from config."
|
|
||||||
cls.ztext = idleConf.GetOption('extensions', 'ZzDummy', 'z-text')
|
cls.ztext = idleConf.GetOption('extensions', 'ZzDummy', 'z-text')
|
||||||
|
|
||||||
@format_selection
|
def z_in_event(self, event):
|
||||||
def z_in_event(self, line):
|
|
||||||
"""Insert text at the beginning of each selected line.
|
|
||||||
|
|
||||||
This is bound to the <<z-in>> virtual event when the extensions
|
|
||||||
are loaded.
|
|
||||||
"""
|
"""
|
||||||
return f'{self.ztext}{line}'
|
|
||||||
|
|
||||||
@format_selection
|
|
||||||
def z_out_event(self, line):
|
|
||||||
"""Remove specific text from the beginning of each selected line.
|
|
||||||
|
|
||||||
This is bound to the <<z-out>> virtual event when the extensions
|
|
||||||
are loaded.
|
|
||||||
"""
|
"""
|
||||||
zlength = 0 if not line.startswith(self.ztext) else len(self.ztext)
|
text = self.text
|
||||||
return line[zlength:]
|
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()
|
ZzDummy.reload()
|
||||||
|
|
||||||
|
##if __name__ == "__main__":
|
||||||
if __name__ == "__main__":
|
## import unittest
|
||||||
import unittest
|
## unittest.main('idlelib.idle_test.test_zzdummy',
|
||||||
unittest.main('idlelib.idle_test.test_zzdummy', verbosity=2, exit=False)
|
## verbosity=2, exit=False)
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import io
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import abc
|
import abc
|
||||||
|
@ -17,7 +18,6 @@ from contextlib import suppress
|
||||||
from importlib import import_module
|
from importlib import import_module
|
||||||
from importlib.abc import MetaPathFinder
|
from importlib.abc import MetaPathFinder
|
||||||
from itertools import starmap
|
from itertools import starmap
|
||||||
from typing import Any, List, Optional, Protocol, TypeVar, Union
|
|
||||||
|
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
|
@ -31,7 +31,7 @@ __all__ = [
|
||||||
'metadata',
|
'metadata',
|
||||||
'requires',
|
'requires',
|
||||||
'version',
|
'version',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
class PackageNotFoundError(ModuleNotFoundError):
|
class PackageNotFoundError(ModuleNotFoundError):
|
||||||
|
@ -43,7 +43,7 @@ class PackageNotFoundError(ModuleNotFoundError):
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def name(self):
|
def name(self):
|
||||||
(name,) = self.args
|
name, = self.args
|
||||||
return name
|
return name
|
||||||
|
|
||||||
|
|
||||||
|
@ -60,7 +60,7 @@ class EntryPoint(
|
||||||
r'(?P<module>[\w.]+)\s*'
|
r'(?P<module>[\w.]+)\s*'
|
||||||
r'(:\s*(?P<attr>[\w.]+))?\s*'
|
r'(:\s*(?P<attr>[\w.]+))?\s*'
|
||||||
r'(?P<extras>\[.*\])?\s*$'
|
r'(?P<extras>\[.*\])?\s*$'
|
||||||
)
|
)
|
||||||
"""
|
"""
|
||||||
A regular expression describing the syntax for an entry point,
|
A regular expression describing the syntax for an entry point,
|
||||||
which might look like:
|
which might look like:
|
||||||
|
@ -77,8 +77,6 @@ class EntryPoint(
|
||||||
following the attr, and following any extras.
|
following the attr, and following any extras.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
dist: Optional['Distribution'] = None
|
|
||||||
|
|
||||||
def load(self):
|
def load(self):
|
||||||
"""Load the entry point from its definition. If only a module
|
"""Load the entry point from its definition. If only a module
|
||||||
is indicated by the value, return that module. Otherwise,
|
is indicated by the value, return that module. Otherwise,
|
||||||
|
@ -106,27 +104,23 @@ class EntryPoint(
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _from_config(cls, config):
|
def _from_config(cls, config):
|
||||||
return (
|
return [
|
||||||
cls(name, value, group)
|
cls(name, value, group)
|
||||||
for group in config.sections()
|
for group in config.sections()
|
||||||
for name, value in config.items(group)
|
for name, value in config.items(group)
|
||||||
)
|
]
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _from_text(cls, text):
|
def _from_text(cls, text):
|
||||||
config = ConfigParser(delimiters='=')
|
config = ConfigParser(delimiters='=')
|
||||||
# case sensitive: https://stackoverflow.com/q/1611799/812183
|
# case sensitive: https://stackoverflow.com/q/1611799/812183
|
||||||
config.optionxform = str
|
config.optionxform = str
|
||||||
config.read_string(text)
|
try:
|
||||||
return cls._from_config(config)
|
config.read_string(text)
|
||||||
|
except AttributeError: # pragma: nocover
|
||||||
@classmethod
|
# Python 2 has no read_string
|
||||||
def _from_text_for(cls, text, dist):
|
config.readfp(io.StringIO(text))
|
||||||
return (ep._for(dist) for ep in cls._from_text(text))
|
return EntryPoint._from_config(config)
|
||||||
|
|
||||||
def _for(self, dist):
|
|
||||||
self.dist = dist
|
|
||||||
return self
|
|
||||||
|
|
||||||
def __iter__(self):
|
def __iter__(self):
|
||||||
"""
|
"""
|
||||||
|
@ -138,7 +132,7 @@ class EntryPoint(
|
||||||
return (
|
return (
|
||||||
self.__class__,
|
self.__class__,
|
||||||
(self.name, self.value, self.group),
|
(self.name, self.value, self.group),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class PackagePath(pathlib.PurePosixPath):
|
class PackagePath(pathlib.PurePosixPath):
|
||||||
|
@ -165,25 +159,6 @@ class FileHash:
|
||||||
return '<FileHash mode: {} value: {}>'.format(self.mode, self.value)
|
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:
|
class Distribution:
|
||||||
"""A Python distribution package."""
|
"""A Python distribution package."""
|
||||||
|
|
||||||
|
@ -235,8 +210,9 @@ class Distribution:
|
||||||
raise ValueError("cannot accept context and kwargs")
|
raise ValueError("cannot accept context and kwargs")
|
||||||
context = context or DistributionFinder.Context(**kwargs)
|
context = context or DistributionFinder.Context(**kwargs)
|
||||||
return itertools.chain.from_iterable(
|
return itertools.chain.from_iterable(
|
||||||
resolver(context) for resolver in cls._discover_resolvers()
|
resolver(context)
|
||||||
)
|
for resolver in cls._discover_resolvers()
|
||||||
|
)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def at(path):
|
def at(path):
|
||||||
|
@ -251,24 +227,24 @@ class Distribution:
|
||||||
def _discover_resolvers():
|
def _discover_resolvers():
|
||||||
"""Search the meta_path for resolvers."""
|
"""Search the meta_path for resolvers."""
|
||||||
declared = (
|
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)
|
return filter(None, declared)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _local(cls, root='.'):
|
def _local(cls, root='.'):
|
||||||
from pep517 import build, meta
|
from pep517 import build, meta
|
||||||
|
|
||||||
system = build.compat_system(root)
|
system = build.compat_system(root)
|
||||||
builder = functools.partial(
|
builder = functools.partial(
|
||||||
meta.build,
|
meta.build,
|
||||||
source_dir=root,
|
source_dir=root,
|
||||||
system=system,
|
system=system,
|
||||||
)
|
)
|
||||||
return PathDistribution(zipfile.Path(meta.build_as_zip(builder)))
|
return PathDistribution(zipfile.Path(meta.build_as_zip(builder)))
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def metadata(self) -> PackageMetadata:
|
def metadata(self):
|
||||||
"""Return the parsed metadata for this Distribution.
|
"""Return the parsed metadata for this Distribution.
|
||||||
|
|
||||||
The returned object will have keys that name the various bits of
|
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
|
# effect is to just end up using the PathDistribution's self._path
|
||||||
# (which points to the egg-info file) attribute unchanged.
|
# (which points to the egg-info file) attribute unchanged.
|
||||||
or self.read_text('')
|
or self.read_text('')
|
||||||
)
|
)
|
||||||
return email.message_from_string(text)
|
return email.message_from_string(text)
|
||||||
|
|
||||||
@property
|
|
||||||
def name(self):
|
|
||||||
"""Return the 'Name' metadata for the distribution package."""
|
|
||||||
return self.metadata['Name']
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def version(self):
|
def version(self):
|
||||||
"""Return the 'Version' metadata for the distribution package."""
|
"""Return the 'Version' metadata for the distribution package."""
|
||||||
|
@ -296,7 +267,7 @@ class Distribution:
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def entry_points(self):
|
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
|
@property
|
||||||
def files(self):
|
def files(self):
|
||||||
|
@ -353,10 +324,9 @@ class Distribution:
|
||||||
section_pairs = cls._read_sections(source.splitlines())
|
section_pairs = cls._read_sections(source.splitlines())
|
||||||
sections = {
|
sections = {
|
||||||
section: list(map(operator.itemgetter('line'), results))
|
section: list(map(operator.itemgetter('line'), results))
|
||||||
for section, results in itertools.groupby(
|
for section, results in
|
||||||
section_pairs, operator.itemgetter('section')
|
itertools.groupby(section_pairs, operator.itemgetter('section'))
|
||||||
)
|
}
|
||||||
}
|
|
||||||
return cls._convert_egg_info_reqs_to_simple_reqs(sections)
|
return cls._convert_egg_info_reqs_to_simple_reqs(sections)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
@ -380,7 +350,6 @@ class Distribution:
|
||||||
requirement. This method converts the former to the
|
requirement. This method converts the former to the
|
||||||
latter. See _test_deps_from_requires_text for an example.
|
latter. See _test_deps_from_requires_text for an example.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def make_condition(name):
|
def make_condition(name):
|
||||||
return name and 'extra == "{name}"'.format(name=name)
|
return name and 'extra == "{name}"'.format(name=name)
|
||||||
|
|
||||||
|
@ -469,69 +438,48 @@ class FastPath:
|
||||||
names = zip_path.root.namelist()
|
names = zip_path.root.namelist()
|
||||||
self.joinpath = zip_path.joinpath
|
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):
|
def search(self, name):
|
||||||
return (
|
for child in self.children():
|
||||||
self.joinpath(child)
|
n_low = child.lower()
|
||||||
for child in self.children()
|
if (n_low in name.exact_matches
|
||||||
if name.matches(child, self.base)
|
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:
|
class Prepared:
|
||||||
"""
|
"""
|
||||||
A prepared search for metadata on a possibly-named package.
|
A prepared search for metadata on a possibly-named package.
|
||||||
"""
|
"""
|
||||||
|
normalized = ''
|
||||||
normalized = None
|
prefix = ''
|
||||||
suffixes = '.dist-info', '.egg-info'
|
suffixes = '.dist-info', '.egg-info'
|
||||||
exact_matches = [''][:0]
|
exact_matches = [''][:0]
|
||||||
|
versionless_egg_name = ''
|
||||||
|
|
||||||
def __init__(self, name):
|
def __init__(self, name):
|
||||||
self.name = name
|
self.name = name
|
||||||
if name is None:
|
if name is None:
|
||||||
return
|
return
|
||||||
self.normalized = self.normalize(name)
|
self.normalized = name.lower().replace('-', '_')
|
||||||
self.exact_matches = [self.normalized + suffix for suffix in self.suffixes]
|
self.prefix = self.normalized + '-'
|
||||||
|
self.exact_matches = [
|
||||||
@staticmethod
|
self.normalized + suffix for suffix in self.suffixes]
|
||||||
def normalize(name):
|
self.versionless_egg_name = self.normalized + '.egg'
|
||||||
"""
|
|
||||||
PEP 503 normalization plus dashes as underscores.
|
|
||||||
"""
|
|
||||||
return re.sub(r"[-_.]+", "-", name).lower().replace('-', '_')
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def legacy_normalize(name):
|
|
||||||
"""
|
|
||||||
Normalize the package name as found in the convention in
|
|
||||||
older packaging tools versions and specs.
|
|
||||||
"""
|
|
||||||
return name.lower().replace('-', '_')
|
|
||||||
|
|
||||||
def matches(self, cand, base):
|
|
||||||
low = cand.lower()
|
|
||||||
pre, ext = os.path.splitext(low)
|
|
||||||
name, sep, rest = pre.partition('-')
|
|
||||||
return (
|
|
||||||
low in self.exact_matches
|
|
||||||
or ext in self.suffixes
|
|
||||||
and (not self.normalized or name.replace('.', '_') == self.normalized)
|
|
||||||
# legacy case:
|
|
||||||
or self.is_egg(base)
|
|
||||||
and low == 'egg-info'
|
|
||||||
)
|
|
||||||
|
|
||||||
def is_egg(self, base):
|
|
||||||
normalized = self.legacy_normalize(self.name or '')
|
|
||||||
prefix = normalized + '-' if normalized else ''
|
|
||||||
versionless_egg_name = normalized + '.egg' if self.name else ''
|
|
||||||
return (
|
|
||||||
base == versionless_egg_name
|
|
||||||
or base.startswith(prefix)
|
|
||||||
and base.endswith('.egg')
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class MetadataPathFinder(DistributionFinder):
|
class MetadataPathFinder(DistributionFinder):
|
||||||
|
@ -552,8 +500,9 @@ class MetadataPathFinder(DistributionFinder):
|
||||||
def _search_paths(cls, name, paths):
|
def _search_paths(cls, name, paths):
|
||||||
"""Find metadata directories in paths heuristically."""
|
"""Find metadata directories in paths heuristically."""
|
||||||
return itertools.chain.from_iterable(
|
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):
|
class PathDistribution(Distribution):
|
||||||
|
@ -566,15 +515,9 @@ class PathDistribution(Distribution):
|
||||||
self._path = path
|
self._path = path
|
||||||
|
|
||||||
def read_text(self, filename):
|
def read_text(self, filename):
|
||||||
with suppress(
|
with suppress(FileNotFoundError, IsADirectoryError, KeyError,
|
||||||
FileNotFoundError,
|
NotADirectoryError, PermissionError):
|
||||||
IsADirectoryError,
|
|
||||||
KeyError,
|
|
||||||
NotADirectoryError,
|
|
||||||
PermissionError,
|
|
||||||
):
|
|
||||||
return self._path.joinpath(filename).read_text(encoding='utf-8')
|
return self._path.joinpath(filename).read_text(encoding='utf-8')
|
||||||
|
|
||||||
read_text.__doc__ = Distribution.read_text.__doc__
|
read_text.__doc__ = Distribution.read_text.__doc__
|
||||||
|
|
||||||
def locate_file(self, path):
|
def locate_file(self, path):
|
||||||
|
@ -598,11 +541,11 @@ def distributions(**kwargs):
|
||||||
return Distribution.discover(**kwargs)
|
return Distribution.discover(**kwargs)
|
||||||
|
|
||||||
|
|
||||||
def metadata(distribution_name) -> PackageMetadata:
|
def metadata(distribution_name):
|
||||||
"""Get the metadata for the named package.
|
"""Get the metadata for the named package.
|
||||||
|
|
||||||
:param distribution_name: The name of the distribution package to query.
|
: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
|
return Distribution.from_name(distribution_name).metadata
|
||||||
|
|
||||||
|
@ -622,11 +565,15 @@ def entry_points():
|
||||||
|
|
||||||
:return: EntryPoint objects for all installed packages.
|
: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')
|
by_group = operator.attrgetter('group')
|
||||||
ordered = sorted(eps, key=by_group)
|
ordered = sorted(eps, key=by_group)
|
||||||
grouped = itertools.groupby(ordered, 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):
|
def files(distribution_name):
|
||||||
|
|
|
@ -174,7 +174,7 @@ def libc_ver(executable=None, lib='', version='', chunksize=16384):
|
||||||
The file is read and scanned in chunks of chunksize bytes.
|
The file is read and scanned in chunks of chunksize bytes.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if not executable:
|
if executable is None:
|
||||||
try:
|
try:
|
||||||
ver = os.confstr('CS_GNU_LIBC_VERSION')
|
ver = os.confstr('CS_GNU_LIBC_VERSION')
|
||||||
# parse 'glibc 2.28' as ('glibc', '2.28')
|
# parse 'glibc 2.28' as ('glibc', '2.28')
|
||||||
|
@ -769,7 +769,7 @@ class uname_result(
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
A uname_result that's largely compatible with a
|
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"
|
resolved late and cached to avoid calling "uname"
|
||||||
except when needed.
|
except when needed.
|
||||||
"""
|
"""
|
||||||
|
@ -784,25 +784,12 @@ class uname_result(
|
||||||
(self.processor,)
|
(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):
|
def __getitem__(self, key):
|
||||||
return tuple(self)[key]
|
return tuple(iter(self))[key]
|
||||||
|
|
||||||
def __len__(self):
|
def __len__(self):
|
||||||
return len(tuple(iter(self)))
|
return len(tuple(iter(self)))
|
||||||
|
|
||||||
def __reduce__(self):
|
|
||||||
return uname_result, tuple(self)[:len(self._fields)]
|
|
||||||
|
|
||||||
|
|
||||||
_uname_cache = None
|
_uname_cache = None
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- 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'
|
topics = {'assert': 'The "assert" statement\n'
|
||||||
'**********************\n'
|
'**********************\n'
|
||||||
'\n'
|
'\n'
|
||||||
|
@ -461,12 +461,13 @@ topics = {'assert': 'The "assert" statement\n'
|
||||||
'\n'
|
'\n'
|
||||||
' async_for_stmt ::= "async" for_stmt\n'
|
' async_for_stmt ::= "async" for_stmt\n'
|
||||||
'\n'
|
'\n'
|
||||||
'An *asynchronous iterable* provides an "__aiter__" method that\n'
|
'An *asynchronous iterable* is able to call asynchronous code in '
|
||||||
'directly returns an *asynchronous iterator*, which can call\n'
|
'its\n'
|
||||||
'asynchronous code in its "__anext__" method.\n'
|
'*iter* implementation, and *asynchronous iterator* can call\n'
|
||||||
|
'asynchronous code in its *next* method.\n'
|
||||||
'\n'
|
'\n'
|
||||||
'The "async for" statement allows convenient iteration over\n'
|
'The "async for" statement allows convenient iteration over\n'
|
||||||
'asynchronous iterables.\n'
|
'asynchronous iterators.\n'
|
||||||
'\n'
|
'\n'
|
||||||
'The following code:\n'
|
'The following code:\n'
|
||||||
'\n'
|
'\n'
|
||||||
|
@ -2382,9 +2383,8 @@ topics = {'assert': 'The "assert" statement\n'
|
||||||
'compatible\n'
|
'compatible\n'
|
||||||
'with an exception if it is the class or a base class of the '
|
'with an exception if it is the class or a base class of the '
|
||||||
'exception\n'
|
'exception\n'
|
||||||
'object, or a tuple containing an item that is the class or a '
|
'object or a tuple containing an item compatible with the '
|
||||||
'base\n'
|
'exception.\n'
|
||||||
'class of the exception object.\n'
|
|
||||||
'\n'
|
'\n'
|
||||||
'If no except clause matches the exception, the search for an '
|
'If no except clause matches the exception, the search for an '
|
||||||
'exception\n'
|
'exception\n'
|
||||||
|
@ -2451,32 +2451,11 @@ topics = {'assert': 'The "assert" statement\n'
|
||||||
'(see\n'
|
'(see\n'
|
||||||
'section The standard type hierarchy) identifying the point in '
|
'section The standard type hierarchy) identifying the point in '
|
||||||
'the\n'
|
'the\n'
|
||||||
'program where the exception occurred. The details about the '
|
'program where the exception occurred. "sys.exc_info()" values '
|
||||||
'exception\n'
|
'are\n'
|
||||||
'accessed via "sys.exc_info()" are restored to their previous '
|
'restored to their previous values (before the call) when '
|
||||||
'values\n'
|
'returning\n'
|
||||||
'when leaving an exception handler:\n'
|
'from a function that handled an exception.\n'
|
||||||
'\n'
|
|
||||||
' >>> print(sys.exc_info())\n'
|
|
||||||
' (None, None, None)\n'
|
|
||||||
' >>> try:\n'
|
|
||||||
' ... raise TypeError\n'
|
|
||||||
' ... except:\n'
|
|
||||||
' ... print(sys.exc_info())\n'
|
|
||||||
' ... try:\n'
|
|
||||||
' ... raise ValueError\n'
|
|
||||||
' ... except:\n'
|
|
||||||
' ... print(sys.exc_info())\n'
|
|
||||||
' ... print(sys.exc_info())\n'
|
|
||||||
' ...\n'
|
|
||||||
" (<class 'TypeError'>, TypeError(), <traceback object at "
|
|
||||||
'0x10efad080>)\n'
|
|
||||||
" (<class 'ValueError'>, ValueError(), <traceback object at "
|
|
||||||
'0x10efad040>)\n'
|
|
||||||
" (<class 'TypeError'>, TypeError(), <traceback object at "
|
|
||||||
'0x10efad080>)\n'
|
|
||||||
' >>> print(sys.exc_info())\n'
|
|
||||||
' (None, None, None)\n'
|
|
||||||
'\n'
|
'\n'
|
||||||
'The optional "else" clause is executed if the control flow '
|
'The optional "else" clause is executed if the control flow '
|
||||||
'leaves the\n'
|
'leaves the\n'
|
||||||
|
@ -3006,12 +2985,13 @@ topics = {'assert': 'The "assert" statement\n'
|
||||||
'\n'
|
'\n'
|
||||||
' async_for_stmt ::= "async" for_stmt\n'
|
' async_for_stmt ::= "async" for_stmt\n'
|
||||||
'\n'
|
'\n'
|
||||||
'An *asynchronous iterable* provides an "__aiter__" method that\n'
|
'An *asynchronous iterable* is able to call asynchronous code in '
|
||||||
'directly returns an *asynchronous iterator*, which can call\n'
|
'its\n'
|
||||||
'asynchronous code in its "__anext__" method.\n'
|
'*iter* implementation, and *asynchronous iterator* can call\n'
|
||||||
|
'asynchronous code in its *next* method.\n'
|
||||||
'\n'
|
'\n'
|
||||||
'The "async for" statement allows convenient iteration over\n'
|
'The "async for" statement allows convenient iteration over\n'
|
||||||
'asynchronous iterables.\n'
|
'asynchronous iterators.\n'
|
||||||
'\n'
|
'\n'
|
||||||
'The following code:\n'
|
'The following code:\n'
|
||||||
'\n'
|
'\n'
|
||||||
|
@ -5544,51 +5524,44 @@ topics = {'assert': 'The "assert" statement\n'
|
||||||
' | | formats the result in either fixed-point '
|
' | | formats the result in either fixed-point '
|
||||||
'format or in |\n'
|
'format or in |\n'
|
||||||
' | | scientific notation, depending on its '
|
' | | scientific notation, depending on its '
|
||||||
'magnitude. A |\n'
|
'magnitude. The |\n'
|
||||||
' | | precision of "0" is treated as equivalent '
|
' | | precise rules are as follows: suppose that '
|
||||||
'to a precision |\n'
|
'the result |\n'
|
||||||
' | | of "1". The precise rules are as follows: '
|
|
||||||
'suppose that |\n'
|
|
||||||
' | | the result formatted with presentation '
|
|
||||||
'type "\'e\'" and |\n'
|
|
||||||
' | | precision "p-1" would have exponent '
|
|
||||||
'"exp". Then, if "m <= |\n'
|
|
||||||
' | | exp < p", where "m" is -4 for floats and '
|
|
||||||
'-6 for |\n'
|
|
||||||
' | | "Decimals", the number is formatted with '
|
|
||||||
'presentation type |\n'
|
|
||||||
' | | "\'f\'" and precision "p-1-exp". '
|
|
||||||
'Otherwise, the number is |\n'
|
|
||||||
' | | formatted with presentation type "\'e\'" '
|
' | | 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'
|
'and precision |\n'
|
||||||
' | | "p-1". In both cases insignificant '
|
' | | "p-1-exp". Otherwise, the number is '
|
||||||
'trailing zeros are |\n'
|
'formatted with |\n'
|
||||||
' | | removed from the significand, and the '
|
' | | presentation type "\'e\'" and precision '
|
||||||
'decimal point is |\n'
|
'"p-1". In both cases |\n'
|
||||||
' | | also removed if there are no remaining '
|
' | | insignificant trailing zeros are removed '
|
||||||
'digits following |\n'
|
'from the |\n'
|
||||||
' | | it, unless the "\'#\'" option is used. '
|
' | | significand, and the decimal point is also '
|
||||||
'With no precision |\n'
|
'removed if |\n'
|
||||||
' | | given, uses a precision of "6" significant '
|
' | | there are no remaining digits following '
|
||||||
'digits for |\n'
|
'it, unless the |\n'
|
||||||
' | | "float". For "Decimal", the coefficient of '
|
' | | "\'#\'" option is used. Positive and '
|
||||||
'the result is |\n'
|
'negative infinity, |\n'
|
||||||
' | | formed from the coefficient digits of the '
|
' | | positive and negative zero, and nans, are '
|
||||||
'value; |\n'
|
'formatted as |\n'
|
||||||
' | | scientific notation is used for values '
|
' | | "inf", "-inf", "0", "-0" and "nan" '
|
||||||
'smaller than "1e-6" |\n'
|
'respectively, |\n'
|
||||||
' | | in absolute value and values where the '
|
' | | regardless of the precision. A precision '
|
||||||
'place value of the |\n'
|
'of "0" is |\n'
|
||||||
' | | least significant digit is larger than 1, '
|
' | | treated as equivalent to a precision of '
|
||||||
'and fixed-point |\n'
|
'"1". With no |\n'
|
||||||
' | | notation is used otherwise. Positive and '
|
' | | precision given, uses a precision of "6" '
|
||||||
'negative |\n'
|
'significant |\n'
|
||||||
' | | infinity, positive and negative zero, and '
|
' | | digits for "float", and shows all '
|
||||||
'nans, are |\n'
|
'coefficient digits for |\n'
|
||||||
' | | formatted as "inf", "-inf", "0", "-0" and '
|
' | | '
|
||||||
'"nan" |\n'
|
'"Decimal". '
|
||||||
' | | respectively, regardless of the '
|
'|\n'
|
||||||
'precision. |\n'
|
|
||||||
' '
|
' '
|
||||||
'+-----------+------------------------------------------------------------+\n'
|
'+-----------+------------------------------------------------------------+\n'
|
||||||
' | "\'G\'" | General format. Same as "\'g\'" except '
|
' | "\'G\'" | General format. Same as "\'g\'" except '
|
||||||
|
@ -5613,24 +5586,19 @@ topics = {'assert': 'The "assert" statement\n'
|
||||||
'percent sign. |\n'
|
'percent sign. |\n'
|
||||||
' '
|
' '
|
||||||
'+-----------+------------------------------------------------------------+\n'
|
'+-----------+------------------------------------------------------------+\n'
|
||||||
' | None | For "float" this is the same as "\'g\'", '
|
' | None | Similar to "\'g\'", except that '
|
||||||
'except that when |\n'
|
'fixed-point notation, when |\n'
|
||||||
' | | fixed-point notation is used to format the '
|
' | | used, has at least one digit past the '
|
||||||
'result, it |\n'
|
'decimal point. The |\n'
|
||||||
' | | always includes at least one digit past '
|
' | | default precision is as high as needed to '
|
||||||
'the decimal point. |\n'
|
'represent the |\n'
|
||||||
' | | The precision used is as large as needed '
|
' | | particular value. The overall effect is to '
|
||||||
'to represent the |\n'
|
'match the |\n'
|
||||||
' | | given value faithfully. For "Decimal", '
|
' | | output of "str()" as altered by the other '
|
||||||
'this is the same |\n'
|
'format |\n'
|
||||||
' | | as either "\'g\'" or "\'G\'" depending on '
|
' | | '
|
||||||
'the value of |\n'
|
'modifiers. '
|
||||||
' | | "context.capitals" for the current decimal '
|
'|\n'
|
||||||
'context. The |\n'
|
|
||||||
' | | overall effect is to match the output of '
|
|
||||||
'"str()" as |\n'
|
|
||||||
' | | altered by the other format '
|
|
||||||
'modifiers. |\n'
|
|
||||||
' '
|
' '
|
||||||
'+-----------+------------------------------------------------------------+\n'
|
'+-----------+------------------------------------------------------------+\n'
|
||||||
'\n'
|
'\n'
|
||||||
|
@ -6004,10 +5972,8 @@ topics = {'assert': 'The "assert" statement\n'
|
||||||
'\n'
|
'\n'
|
||||||
'Names listed in a "global" statement must not be defined as '
|
'Names listed in a "global" statement must not be defined as '
|
||||||
'formal\n'
|
'formal\n'
|
||||||
'parameters, or as targets in "with" statements or "except" '
|
'parameters or in a "for" loop control target, "class" definition,\n'
|
||||||
'clauses, or\n'
|
'function definition, "import" statement, or variable annotation.\n'
|
||||||
'in a "for" target list, "class" definition, function definition,\n'
|
|
||||||
'"import" statement, or variable annotation.\n'
|
|
||||||
'\n'
|
'\n'
|
||||||
'**CPython implementation detail:** The current implementation does '
|
'**CPython implementation detail:** The current implementation does '
|
||||||
'not\n'
|
'not\n'
|
||||||
|
@ -7959,7 +7925,7 @@ topics = {'assert': 'The "assert" statement\n'
|
||||||
'immediate\n'
|
'immediate\n'
|
||||||
' subclasses. This method returns a list of all those '
|
' subclasses. This method returns a list of all those '
|
||||||
'references\n'
|
'references\n'
|
||||||
' still alive. The list is in definition order. Example:\n'
|
' still alive. Example:\n'
|
||||||
'\n'
|
'\n'
|
||||||
' >>> int.__subclasses__()\n'
|
' >>> int.__subclasses__()\n'
|
||||||
" [<class 'bool'>]\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'
|
'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 '
|
'with an exception if it is the class or a base class of the '
|
||||||
'exception\n'
|
'exception\n'
|
||||||
'object, or a tuple containing an item that is the class or a base\n'
|
'object or a tuple containing an item compatible with the exception.\n'
|
||||||
'class of the exception object.\n'
|
|
||||||
'\n'
|
'\n'
|
||||||
'If no except clause matches the exception, the search for an '
|
'If no except clause matches the exception, the search for an '
|
||||||
'exception\n'
|
'exception\n'
|
||||||
|
@ -11314,31 +11279,9 @@ topics = {'assert': 'The "assert" statement\n'
|
||||||
'the\n'
|
'the\n'
|
||||||
'exception class, the exception instance and a traceback object (see\n'
|
'exception class, the exception instance and a traceback object (see\n'
|
||||||
'section The standard type hierarchy) identifying the point in the\n'
|
'section The standard type hierarchy) identifying the point in the\n'
|
||||||
'program where the exception occurred. The details about the '
|
'program where the exception occurred. "sys.exc_info()" values are\n'
|
||||||
'exception\n'
|
'restored to their previous values (before the call) when returning\n'
|
||||||
'accessed via "sys.exc_info()" are restored to their previous values\n'
|
'from a function that handled an exception.\n'
|
||||||
'when leaving an exception handler:\n'
|
|
||||||
'\n'
|
|
||||||
' >>> print(sys.exc_info())\n'
|
|
||||||
' (None, None, None)\n'
|
|
||||||
' >>> try:\n'
|
|
||||||
' ... raise TypeError\n'
|
|
||||||
' ... except:\n'
|
|
||||||
' ... print(sys.exc_info())\n'
|
|
||||||
' ... try:\n'
|
|
||||||
' ... raise ValueError\n'
|
|
||||||
' ... except:\n'
|
|
||||||
' ... print(sys.exc_info())\n'
|
|
||||||
' ... print(sys.exc_info())\n'
|
|
||||||
' ...\n'
|
|
||||||
" (<class 'TypeError'>, TypeError(), <traceback object at "
|
|
||||||
'0x10efad080>)\n'
|
|
||||||
" (<class 'ValueError'>, ValueError(), <traceback object at "
|
|
||||||
'0x10efad040>)\n'
|
|
||||||
" (<class 'TypeError'>, TypeError(), <traceback object at "
|
|
||||||
'0x10efad080>)\n'
|
|
||||||
' >>> print(sys.exc_info())\n'
|
|
||||||
' (None, None, None)\n'
|
|
||||||
'\n'
|
'\n'
|
||||||
'The optional "else" clause is executed if the control flow leaves '
|
'The optional "else" clause is executed if the control flow leaves '
|
||||||
'the\n'
|
'the\n'
|
||||||
|
@ -11502,6 +11445,7 @@ topics = {'assert': 'The "assert" statement\n'
|
||||||
' There are two types of integers:\n'
|
' There are two types of integers:\n'
|
||||||
'\n'
|
'\n'
|
||||||
' Integers ("int")\n'
|
' Integers ("int")\n'
|
||||||
|
'\n'
|
||||||
' These represent numbers in an unlimited range, subject to\n'
|
' These represent numbers in an unlimited range, subject to\n'
|
||||||
' available (virtual) memory only. For the purpose of '
|
' available (virtual) memory only. For the purpose of '
|
||||||
'shift\n'
|
'shift\n'
|
||||||
|
|
|
@ -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 math import tau as TWOPI, floor as _floor, isfinite as _isfinite
|
||||||
from os import urandom as _urandom
|
from os import urandom as _urandom
|
||||||
from _collections_abc import Set as _Set, Sequence as _Sequence
|
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 itertools import accumulate as _accumulate, repeat as _repeat
|
||||||
from bisect import bisect as _bisect
|
from bisect import bisect as _bisect
|
||||||
import os as _os
|
import os as _os
|
||||||
|
@ -96,7 +95,6 @@ LOG4 = _log(4.0)
|
||||||
SG_MAGICCONST = 1.0 + _log(4.5)
|
SG_MAGICCONST = 1.0 + _log(4.5)
|
||||||
BPF = 53 # Number of bits in a float
|
BPF = 53 # Number of bits in a float
|
||||||
RECIP_BPF = 2 ** -BPF
|
RECIP_BPF = 2 ** -BPF
|
||||||
_ONE = 1
|
|
||||||
|
|
||||||
|
|
||||||
class Random(_random.Random):
|
class Random(_random.Random):
|
||||||
|
@ -289,7 +287,7 @@ class Random(_random.Random):
|
||||||
|
|
||||||
## -------------------- integer methods -------------------
|
## -------------------- 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]).
|
"""Choose a random item from range(start, stop[, step]).
|
||||||
|
|
||||||
This fixes the problem with randint() which includes the
|
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
|
# This code is a bit messy to make it fast for the
|
||||||
# common case while still doing adequate error checking.
|
# common case while still doing adequate error checking.
|
||||||
try:
|
istart = int(start)
|
||||||
istart = _index(start)
|
if istart != start:
|
||||||
except TypeError:
|
raise ValueError("non-integer arg 1 for randrange()")
|
||||||
if int(start) == start:
|
|
||||||
istart = int(start)
|
|
||||||
_warn('Float arguments to randrange() have been deprecated\n'
|
|
||||||
'since Python 3.10 and will be removed in a subsequent '
|
|
||||||
'version.',
|
|
||||||
DeprecationWarning, 2)
|
|
||||||
else:
|
|
||||||
_warn('randrange() will raise TypeError in the future',
|
|
||||||
DeprecationWarning, 2)
|
|
||||||
raise ValueError("non-integer arg 1 for randrange()")
|
|
||||||
|
|
||||||
if stop is None:
|
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:
|
if istart > 0:
|
||||||
return self._randbelow(istart)
|
return self._randbelow(istart)
|
||||||
raise ValueError("empty range for randrange()")
|
raise ValueError("empty range for randrange()")
|
||||||
|
|
||||||
# stop argument supplied.
|
# stop argument supplied.
|
||||||
try:
|
istop = int(stop)
|
||||||
istop = _index(stop)
|
if istop != stop:
|
||||||
except TypeError:
|
raise ValueError("non-integer stop for randrange()")
|
||||||
if int(stop) == stop:
|
|
||||||
istop = int(stop)
|
|
||||||
_warn('Float arguments to randrange() have been deprecated\n'
|
|
||||||
'since Python 3.10 and will be removed in a subsequent '
|
|
||||||
'version.',
|
|
||||||
DeprecationWarning, 2)
|
|
||||||
else:
|
|
||||||
_warn('randrange() will raise TypeError in the future',
|
|
||||||
DeprecationWarning, 2)
|
|
||||||
raise ValueError("non-integer stop for randrange()")
|
|
||||||
|
|
||||||
try:
|
|
||||||
istep = _index(step)
|
|
||||||
except TypeError:
|
|
||||||
if int(step) == step:
|
|
||||||
istep = int(step)
|
|
||||||
_warn('Float arguments to randrange() have been deprecated\n'
|
|
||||||
'since Python 3.10 and will be removed in a subsequent '
|
|
||||||
'version.',
|
|
||||||
DeprecationWarning, 2)
|
|
||||||
else:
|
|
||||||
_warn('randrange() will raise TypeError in the future',
|
|
||||||
DeprecationWarning, 2)
|
|
||||||
raise ValueError("non-integer step for randrange()")
|
|
||||||
width = istop - istart
|
width = istop - istart
|
||||||
if istep == 1:
|
if step == 1 and width > 0:
|
||||||
if width > 0:
|
return istart + self._randbelow(width)
|
||||||
return istart + self._randbelow(width)
|
if step == 1:
|
||||||
raise ValueError("empty range for randrange() (%d, %d, %d)" % (istart, istop, width))
|
raise ValueError("empty range for randrange() (%d, %d, %d)" % (istart, istop, width))
|
||||||
|
|
||||||
# Non-unit step argument supplied.
|
# Non-unit step argument supplied.
|
||||||
|
istep = int(step)
|
||||||
|
if istep != step:
|
||||||
|
raise ValueError("non-integer step for randrange()")
|
||||||
if istep > 0:
|
if istep > 0:
|
||||||
n = (width + istep - 1) // istep
|
n = (width + istep - 1) // istep
|
||||||
elif istep < 0:
|
elif istep < 0:
|
||||||
n = (width + istep + 1) // istep
|
n = (width + istep + 1) // istep
|
||||||
else:
|
else:
|
||||||
raise ValueError("zero step for randrange()")
|
raise ValueError("zero step for randrange()")
|
||||||
|
|
||||||
if n <= 0:
|
if n <= 0:
|
||||||
raise ValueError("empty range for randrange()")
|
raise ValueError("empty range for randrange()")
|
||||||
|
|
||||||
return istart + istep * self._randbelow(n)
|
return istart + istep * self._randbelow(n)
|
||||||
|
|
||||||
def randint(self, a, b):
|
def randint(self, a, b):
|
||||||
|
|
|
@ -1082,8 +1082,7 @@ class LMTP(SMTP):
|
||||||
# Handle Unix-domain sockets.
|
# Handle Unix-domain sockets.
|
||||||
try:
|
try:
|
||||||
self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
|
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.file = None
|
||||||
self.sock.connect(host)
|
self.sock.connect(host)
|
||||||
except OSError:
|
except OSError:
|
||||||
|
|
|
@ -628,39 +628,6 @@ if hasattr(os, "fork"):
|
||||||
self.collect_children(blocking=self.block_on_close)
|
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:
|
class ThreadingMixIn:
|
||||||
"""Mix-in class to handle each request in a new thread."""
|
"""Mix-in class to handle each request in a new thread."""
|
||||||
|
|
||||||
|
@ -669,9 +636,9 @@ class ThreadingMixIn:
|
||||||
daemon_threads = False
|
daemon_threads = False
|
||||||
# If true, server_close() waits until all non-daemonic threads terminate.
|
# If true, server_close() waits until all non-daemonic threads terminate.
|
||||||
block_on_close = True
|
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.
|
# used by server_close() to wait for all threads completion.
|
||||||
_threads = _NoThreads()
|
_threads = None
|
||||||
|
|
||||||
def process_request_thread(self, request, client_address):
|
def process_request_thread(self, request, client_address):
|
||||||
"""Same as in BaseServer but as a thread.
|
"""Same as in BaseServer but as a thread.
|
||||||
|
@ -688,17 +655,23 @@ class ThreadingMixIn:
|
||||||
|
|
||||||
def process_request(self, request, client_address):
|
def process_request(self, request, client_address):
|
||||||
"""Start a new thread to process the request."""
|
"""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,
|
t = threading.Thread(target = self.process_request_thread,
|
||||||
args = (request, client_address))
|
args = (request, client_address))
|
||||||
t.daemon = self.daemon_threads
|
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()
|
t.start()
|
||||||
|
|
||||||
def server_close(self):
|
def server_close(self):
|
||||||
super().server_close()
|
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"):
|
if hasattr(os, "fork"):
|
||||||
|
|
|
@ -260,14 +260,6 @@ class TraceCallbackTests(unittest.TestCase):
|
||||||
cur.execute(queries[0])
|
cur.execute(queries[0])
|
||||||
con2.execute("create table bar(x)")
|
con2.execute("create table bar(x)")
|
||||||
cur.execute(queries[1])
|
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)
|
self.assertEqual(traced_statements, queries)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -420,11 +420,7 @@ def check_output(*popenargs, timeout=None, **kwargs):
|
||||||
if 'input' in kwargs and kwargs['input'] is None:
|
if 'input' in kwargs and kwargs['input'] is None:
|
||||||
# Explicitly passing input=None was previously equivalent to passing an
|
# Explicitly passing input=None was previously equivalent to passing an
|
||||||
# empty string. That is maintained here for backwards compatibility.
|
# empty string. That is maintained here for backwards compatibility.
|
||||||
if kwargs.get('universal_newlines') or kwargs.get('text'):
|
kwargs['input'] = '' if kwargs.get('universal_newlines', False) else b''
|
||||||
empty = ''
|
|
||||||
else:
|
|
||||||
empty = b''
|
|
||||||
kwargs['input'] = empty
|
|
||||||
|
|
||||||
return run(*popenargs, stdout=PIPE, timeout=timeout, check=True,
|
return run(*popenargs, stdout=PIPE, timeout=timeout, check=True,
|
||||||
**kwargs).stdout
|
**kwargs).stdout
|
||||||
|
|
|
@ -14,6 +14,6 @@ the user build or load random bytecodes anyway. Otherwise, this is a
|
||||||
|
|
||||||
import types
|
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'')
|
(), (), (), '', '', 1, b'')
|
||||||
exec(co)
|
exec(co)
|
||||||
|
|
|
@ -107,9 +107,6 @@ class MockSocket:
|
||||||
def close(self):
|
def close(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def connect(self, host):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
def socket(family=None, type=None, proto=None):
|
def socket(family=None, type=None, proto=None):
|
||||||
return MockSocket(family)
|
return MockSocket(family)
|
||||||
|
@ -155,12 +152,8 @@ error = socket_module.error
|
||||||
|
|
||||||
|
|
||||||
# Constants
|
# Constants
|
||||||
_GLOBAL_DEFAULT_TIMEOUT = socket_module._GLOBAL_DEFAULT_TIMEOUT
|
|
||||||
AF_INET = socket_module.AF_INET
|
AF_INET = socket_module.AF_INET
|
||||||
AF_INET6 = socket_module.AF_INET6
|
AF_INET6 = socket_module.AF_INET6
|
||||||
SOCK_STREAM = socket_module.SOCK_STREAM
|
SOCK_STREAM = socket_module.SOCK_STREAM
|
||||||
SOL_SOCKET = None
|
SOL_SOCKET = None
|
||||||
SO_REUSEADDR = None
|
SO_REUSEADDR = None
|
||||||
|
|
||||||
if hasattr(socket_module, 'AF_UNIX'):
|
|
||||||
AF_UNIX = socket_module.AF_UNIX
|
|
||||||
|
|
|
@ -69,10 +69,6 @@ def count_opcode(code, pickle):
|
||||||
return n
|
return n
|
||||||
|
|
||||||
|
|
||||||
def identity(x):
|
|
||||||
return x
|
|
||||||
|
|
||||||
|
|
||||||
class UnseekableIO(io.BytesIO):
|
class UnseekableIO(io.BytesIO):
|
||||||
def peek(self, *args):
|
def peek(self, *args):
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
@ -142,12 +138,11 @@ class E(C):
|
||||||
def __getinitargs__(self):
|
def __getinitargs__(self):
|
||||||
return ()
|
return ()
|
||||||
|
|
||||||
# Simple mutable object.
|
class H(object):
|
||||||
class Object:
|
|
||||||
pass
|
pass
|
||||||
|
|
||||||
# Hashable immutable key object containing unheshable mutable data.
|
# Hashable mutable key
|
||||||
class K:
|
class K(object):
|
||||||
def __init__(self, value):
|
def __init__(self, value):
|
||||||
self.value = value
|
self.value = value
|
||||||
|
|
||||||
|
@ -162,6 +157,10 @@ __main__.D = D
|
||||||
D.__module__ = "__main__"
|
D.__module__ = "__main__"
|
||||||
__main__.E = E
|
__main__.E = E
|
||||||
E.__module__ = "__main__"
|
E.__module__ = "__main__"
|
||||||
|
__main__.H = H
|
||||||
|
H.__module__ = "__main__"
|
||||||
|
__main__.K = K
|
||||||
|
K.__module__ = "__main__"
|
||||||
|
|
||||||
class myint(int):
|
class myint(int):
|
||||||
def __init__(self, x):
|
def __init__(self, x):
|
||||||
|
@ -1497,182 +1496,54 @@ class AbstractPickleTests(unittest.TestCase):
|
||||||
got = filelike.getvalue()
|
got = filelike.getvalue()
|
||||||
self.assertEqual(expected, got)
|
self.assertEqual(expected, got)
|
||||||
|
|
||||||
def _test_recursive_list(self, cls, aslist=identity, minprotocol=0):
|
def test_recursive_list(self):
|
||||||
# List containing itself.
|
l = []
|
||||||
l = cls()
|
|
||||||
l.append(l)
|
l.append(l)
|
||||||
for proto in range(minprotocol, pickle.HIGHEST_PROTOCOL + 1):
|
for proto in protocols:
|
||||||
s = self.dumps(l, proto)
|
s = self.dumps(l, proto)
|
||||||
x = self.loads(s)
|
x = self.loads(s)
|
||||||
self.assertIsInstance(x, cls)
|
self.assertIsInstance(x, list)
|
||||||
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.assertEqual(len(x), 1)
|
self.assertEqual(len(x), 1)
|
||||||
self.assertIsInstance(x[0], cls)
|
self.assertIs(x[0], x)
|
||||||
y = aslist(x[0])
|
|
||||||
self.assertEqual(len(y), 1)
|
|
||||||
self.assertIs(y[0], x)
|
|
||||||
|
|
||||||
# List containing a tuple containing the original list.
|
|
||||||
t, = t
|
|
||||||
for proto in range(minprotocol, pickle.HIGHEST_PROTOCOL + 1):
|
|
||||||
s = self.dumps(t, proto)
|
|
||||||
x = self.loads(s)
|
|
||||||
self.assertIsInstance(x, cls)
|
|
||||||
y = aslist(x)
|
|
||||||
self.assertEqual(len(y), 1)
|
|
||||||
self.assertIsInstance(y[0], tuple)
|
|
||||||
self.assertEqual(len(y[0]), 1)
|
|
||||||
self.assertIs(y[0][0], x)
|
|
||||||
|
|
||||||
def test_recursive_tuple_and_list(self):
|
def test_recursive_tuple_and_list(self):
|
||||||
self._test_recursive_tuple_and_list(list)
|
t = ([],)
|
||||||
|
t[0].append(t)
|
||||||
def test_recursive_tuple_and_list_subclass(self):
|
for proto in protocols:
|
||||||
self._test_recursive_tuple_and_list(MyList, minprotocol=2)
|
s = self.dumps(t, proto)
|
||||||
|
|
||||||
def test_recursive_tuple_and_list_like(self):
|
|
||||||
self._test_recursive_tuple_and_list(REX_six, aslist=lambda x: x.items)
|
|
||||||
|
|
||||||
def _test_recursive_dict(self, cls, asdict=identity, minprotocol=0):
|
|
||||||
# Dict containing itself.
|
|
||||||
d = cls()
|
|
||||||
d[1] = d
|
|
||||||
for proto in range(minprotocol, pickle.HIGHEST_PROTOCOL + 1):
|
|
||||||
s = self.dumps(d, proto)
|
|
||||||
x = self.loads(s)
|
x = self.loads(s)
|
||||||
self.assertIsInstance(x, cls)
|
self.assertIsInstance(x, tuple)
|
||||||
y = asdict(x)
|
self.assertEqual(len(x), 1)
|
||||||
self.assertEqual(list(y.keys()), [1])
|
self.assertIsInstance(x[0], list)
|
||||||
self.assertIs(y[1], x)
|
self.assertEqual(len(x[0]), 1)
|
||||||
|
self.assertIs(x[0][0], x)
|
||||||
|
|
||||||
def test_recursive_dict(self):
|
def test_recursive_dict(self):
|
||||||
self._test_recursive_dict(dict)
|
d = {}
|
||||||
|
d[1] = d
|
||||||
def test_recursive_dict_subclass(self):
|
for proto in protocols:
|
||||||
self._test_recursive_dict(MyDict, minprotocol=2)
|
|
||||||
|
|
||||||
def test_recursive_dict_like(self):
|
|
||||||
self._test_recursive_dict(REX_seven, asdict=lambda x: x.table)
|
|
||||||
|
|
||||||
def _test_recursive_tuple_and_dict(self, cls, asdict=identity, minprotocol=0):
|
|
||||||
# Tuple containing a dict containing the original tuple.
|
|
||||||
t = (cls(),)
|
|
||||||
t[0][1] = t
|
|
||||||
for proto in range(minprotocol, pickle.HIGHEST_PROTOCOL + 1):
|
|
||||||
s = self.dumps(t, proto)
|
|
||||||
x = self.loads(s)
|
|
||||||
self.assertIsInstance(x, tuple)
|
|
||||||
self.assertEqual(len(x), 1)
|
|
||||||
self.assertIsInstance(x[0], cls)
|
|
||||||
y = asdict(x[0])
|
|
||||||
self.assertEqual(list(y), [1])
|
|
||||||
self.assertIs(y[1], x)
|
|
||||||
|
|
||||||
# Dict containing a tuple containing the original dict.
|
|
||||||
t, = t
|
|
||||||
for proto in range(minprotocol, pickle.HIGHEST_PROTOCOL + 1):
|
|
||||||
s = self.dumps(t, proto)
|
|
||||||
x = self.loads(s)
|
|
||||||
self.assertIsInstance(x, cls)
|
|
||||||
y = asdict(x)
|
|
||||||
self.assertEqual(list(y), [1])
|
|
||||||
self.assertIsInstance(y[1], tuple)
|
|
||||||
self.assertEqual(len(y[1]), 1)
|
|
||||||
self.assertIs(y[1][0], x)
|
|
||||||
|
|
||||||
def test_recursive_tuple_and_dict(self):
|
|
||||||
self._test_recursive_tuple_and_dict(dict)
|
|
||||||
|
|
||||||
def test_recursive_tuple_and_dict_subclass(self):
|
|
||||||
self._test_recursive_tuple_and_dict(MyDict, minprotocol=2)
|
|
||||||
|
|
||||||
def test_recursive_tuple_and_dict_like(self):
|
|
||||||
self._test_recursive_tuple_and_dict(REX_seven, asdict=lambda x: x.table)
|
|
||||||
|
|
||||||
def _test_recursive_dict_key(self, cls, asdict=identity, minprotocol=0):
|
|
||||||
# Dict containing an immutable object (as key) containing the original
|
|
||||||
# dict.
|
|
||||||
d = cls()
|
|
||||||
d[K(d)] = 1
|
|
||||||
for proto in range(minprotocol, pickle.HIGHEST_PROTOCOL + 1):
|
|
||||||
s = self.dumps(d, proto)
|
s = self.dumps(d, proto)
|
||||||
x = self.loads(s)
|
x = self.loads(s)
|
||||||
self.assertIsInstance(x, cls)
|
self.assertIsInstance(x, dict)
|
||||||
y = asdict(x)
|
self.assertEqual(list(x.keys()), [1])
|
||||||
self.assertEqual(len(y.keys()), 1)
|
self.assertIs(x[1], x)
|
||||||
self.assertIsInstance(list(y.keys())[0], K)
|
|
||||||
self.assertIs(list(y.keys())[0].value, x)
|
|
||||||
|
|
||||||
def test_recursive_dict_key(self):
|
def test_recursive_dict_key(self):
|
||||||
self._test_recursive_dict_key(dict)
|
d = {}
|
||||||
|
k = K(d)
|
||||||
def test_recursive_dict_subclass_key(self):
|
d[k] = 1
|
||||||
self._test_recursive_dict_key(MyDict, minprotocol=2)
|
for proto in protocols:
|
||||||
|
s = self.dumps(d, proto)
|
||||||
def test_recursive_dict_like_key(self):
|
|
||||||
self._test_recursive_dict_key(REX_seven, asdict=lambda x: x.table)
|
|
||||||
|
|
||||||
def _test_recursive_tuple_and_dict_key(self, cls, asdict=identity, minprotocol=0):
|
|
||||||
# Tuple containing a dict containing an immutable object (as key)
|
|
||||||
# containing the original tuple.
|
|
||||||
t = (cls(),)
|
|
||||||
t[0][K(t)] = 1
|
|
||||||
for proto in range(minprotocol, pickle.HIGHEST_PROTOCOL + 1):
|
|
||||||
s = self.dumps(t, proto)
|
|
||||||
x = self.loads(s)
|
x = self.loads(s)
|
||||||
self.assertIsInstance(x, tuple)
|
self.assertIsInstance(x, dict)
|
||||||
self.assertEqual(len(x), 1)
|
self.assertEqual(len(x.keys()), 1)
|
||||||
self.assertIsInstance(x[0], cls)
|
self.assertIsInstance(list(x.keys())[0], K)
|
||||||
y = asdict(x[0])
|
self.assertIs(list(x.keys())[0].value, x)
|
||||||
self.assertEqual(len(y), 1)
|
|
||||||
self.assertIsInstance(list(y.keys())[0], K)
|
|
||||||
self.assertIs(list(y.keys())[0].value, x)
|
|
||||||
|
|
||||||
# Dict containing an immutable object (as key) containing a tuple
|
|
||||||
# containing the original dict.
|
|
||||||
t, = t
|
|
||||||
for proto in range(minprotocol, pickle.HIGHEST_PROTOCOL + 1):
|
|
||||||
s = self.dumps(t, proto)
|
|
||||||
x = self.loads(s)
|
|
||||||
self.assertIsInstance(x, cls)
|
|
||||||
y = asdict(x)
|
|
||||||
self.assertEqual(len(y), 1)
|
|
||||||
self.assertIsInstance(list(y.keys())[0], K)
|
|
||||||
self.assertIs(list(y.keys())[0].value[0], x)
|
|
||||||
|
|
||||||
def test_recursive_tuple_and_dict_key(self):
|
|
||||||
self._test_recursive_tuple_and_dict_key(dict)
|
|
||||||
|
|
||||||
def test_recursive_tuple_and_dict_subclass_key(self):
|
|
||||||
self._test_recursive_tuple_and_dict_key(MyDict, minprotocol=2)
|
|
||||||
|
|
||||||
def test_recursive_tuple_and_dict_like_key(self):
|
|
||||||
self._test_recursive_tuple_and_dict_key(REX_seven, asdict=lambda x: x.table)
|
|
||||||
|
|
||||||
def test_recursive_set(self):
|
def test_recursive_set(self):
|
||||||
# Set containing an immutable object containing the original set.
|
|
||||||
y = set()
|
y = set()
|
||||||
y.add(K(y))
|
k = K(y)
|
||||||
|
y.add(k)
|
||||||
for proto in range(4, pickle.HIGHEST_PROTOCOL + 1):
|
for proto in range(4, pickle.HIGHEST_PROTOCOL + 1):
|
||||||
s = self.dumps(y, proto)
|
s = self.dumps(y, proto)
|
||||||
x = self.loads(s)
|
x = self.loads(s)
|
||||||
|
@ -1681,31 +1552,52 @@ class AbstractPickleTests(unittest.TestCase):
|
||||||
self.assertIsInstance(list(x)[0], K)
|
self.assertIsInstance(list(x)[0], K)
|
||||||
self.assertIs(list(x)[0].value, x)
|
self.assertIs(list(x)[0].value, x)
|
||||||
|
|
||||||
# Immutable object containing a set containing the original object.
|
def test_recursive_list_subclass(self):
|
||||||
y, = y
|
y = MyList()
|
||||||
for proto in range(4, pickle.HIGHEST_PROTOCOL + 1):
|
y.append(y)
|
||||||
|
for proto in range(2, pickle.HIGHEST_PROTOCOL + 1):
|
||||||
s = self.dumps(y, proto)
|
s = self.dumps(y, proto)
|
||||||
x = self.loads(s)
|
x = self.loads(s)
|
||||||
self.assertIsInstance(x, K)
|
self.assertIsInstance(x, MyList)
|
||||||
self.assertIsInstance(x.value, set)
|
self.assertEqual(len(x), 1)
|
||||||
self.assertEqual(len(x.value), 1)
|
self.assertIs(x[0], x)
|
||||||
self.assertIs(list(x.value)[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):
|
def test_recursive_inst(self):
|
||||||
# Mutable object containing itself.
|
i = C()
|
||||||
i = Object()
|
|
||||||
i.attr = i
|
i.attr = i
|
||||||
for proto in protocols:
|
for proto in protocols:
|
||||||
s = self.dumps(i, proto)
|
s = self.dumps(i, proto)
|
||||||
x = self.loads(s)
|
x = self.loads(s)
|
||||||
self.assertIsInstance(x, Object)
|
self.assertIsInstance(x, C)
|
||||||
self.assertEqual(dir(x), dir(i))
|
self.assertEqual(dir(x), dir(i))
|
||||||
self.assertIs(x.attr, x)
|
self.assertIs(x.attr, x)
|
||||||
|
|
||||||
def test_recursive_multi(self):
|
def test_recursive_multi(self):
|
||||||
l = []
|
l = []
|
||||||
d = {1:l}
|
d = {1:l}
|
||||||
i = Object()
|
i = C()
|
||||||
i.attr = d
|
i.attr = d
|
||||||
l.append(i)
|
l.append(i)
|
||||||
for proto in protocols:
|
for proto in protocols:
|
||||||
|
@ -1715,94 +1607,49 @@ class AbstractPickleTests(unittest.TestCase):
|
||||||
self.assertEqual(len(x), 1)
|
self.assertEqual(len(x), 1)
|
||||||
self.assertEqual(dir(x[0]), dir(i))
|
self.assertEqual(dir(x[0]), dir(i))
|
||||||
self.assertEqual(list(x[0].attr.keys()), [1])
|
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):
|
def check_recursive_collection_and_inst(self, factory):
|
||||||
# Mutable object containing a collection containing the original
|
h = H()
|
||||||
# object.
|
y = factory([h])
|
||||||
o = Object()
|
h.attr = y
|
||||||
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
|
|
||||||
for proto in protocols:
|
for proto in protocols:
|
||||||
s = self.dumps(y, proto)
|
s = self.dumps(y, proto)
|
||||||
x = self.loads(s)
|
x = self.loads(s)
|
||||||
self.assertIsInstance(x, REX_state)
|
self.assertIsInstance(x, type(y))
|
||||||
self.assertIs(x.state, x)
|
|
||||||
|
|
||||||
def test_recursive_tuple_and_inst_state(self):
|
|
||||||
# Tuple containing a mutable object containing the original tuple.
|
|
||||||
t = (REX_state(),)
|
|
||||||
t[0].state = t
|
|
||||||
for proto in protocols:
|
|
||||||
s = self.dumps(t, proto)
|
|
||||||
x = self.loads(s)
|
|
||||||
self.assertIsInstance(x, tuple)
|
|
||||||
self.assertEqual(len(x), 1)
|
self.assertEqual(len(x), 1)
|
||||||
self.assertIsInstance(x[0], REX_state)
|
self.assertIsInstance(list(x)[0], H)
|
||||||
self.assertIs(x[0].state, x)
|
self.assertIs(list(x)[0].attr, x)
|
||||||
|
|
||||||
# Mutable object containing a tuple containing the object.
|
def test_recursive_list_and_inst(self):
|
||||||
t, = t
|
self.check_recursive_collection_and_inst(list)
|
||||||
for proto in protocols:
|
|
||||||
s = self.dumps(t, proto)
|
def test_recursive_tuple_and_inst(self):
|
||||||
x = self.loads(s)
|
self.check_recursive_collection_and_inst(tuple)
|
||||||
self.assertIsInstance(x, REX_state)
|
|
||||||
self.assertIsInstance(x.state, tuple)
|
def test_recursive_dict_and_inst(self):
|
||||||
self.assertEqual(len(x.state), 1)
|
self.check_recursive_collection_and_inst(dict.fromkeys)
|
||||||
self.assertIs(x.state[0], x)
|
|
||||||
|
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):
|
def test_unicode(self):
|
||||||
endcases = ['', '<\\u>', '<\\\u1234>', '<\n>',
|
endcases = ['', '<\\u>', '<\\\u1234>', '<\n>',
|
||||||
|
@ -3215,19 +3062,6 @@ class REX_seven(object):
|
||||||
def __reduce__(self):
|
def __reduce__(self):
|
||||||
return type(self), (), None, None, iter(self.table.items())
|
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
|
# Test classes for newobj
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
"""Tests for the asdl parser in Parser/asdl.py"""
|
"""Tests for the asdl parser in Parser/asdl.py"""
|
||||||
|
|
||||||
import importlib.machinery
|
import importlib.machinery
|
||||||
import importlib.util
|
|
||||||
import os
|
import os
|
||||||
from os.path import dirname
|
from os.path import dirname
|
||||||
import sys
|
import sys
|
||||||
|
@ -27,10 +26,7 @@ class TestAsdlParser(unittest.TestCase):
|
||||||
sys.path.insert(0, parser_dir)
|
sys.path.insert(0, parser_dir)
|
||||||
loader = importlib.machinery.SourceFileLoader(
|
loader = importlib.machinery.SourceFileLoader(
|
||||||
'asdl', os.path.join(parser_dir, 'asdl.py'))
|
'asdl', os.path.join(parser_dir, 'asdl.py'))
|
||||||
spec = importlib.util.spec_from_loader('asdl', loader)
|
cls.asdl = loader.load_module()
|
||||||
module = importlib.util.module_from_spec(spec)
|
|
||||||
loader.exec_module(module)
|
|
||||||
cls.asdl = module
|
|
||||||
cls.mod = cls.asdl.parse(os.path.join(parser_dir, 'Python.asdl'))
|
cls.mod = cls.asdl.parse(os.path.join(parser_dir, 'Python.asdl'))
|
||||||
cls.assertTrue(cls.asdl.check(cls.mod), 'Module validation failed')
|
cls.assertTrue(cls.asdl.check(cls.mod), 'Module validation failed')
|
||||||
|
|
||||||
|
|
|
@ -1011,18 +1011,6 @@ Module(
|
||||||
self.assertEqual(ast.literal_eval(" \t -1"), -1)
|
self.assertEqual(ast.literal_eval(" \t -1"), -1)
|
||||||
self.assertRaises(IndentationError, ast.literal_eval, "\n -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):
|
def test_bad_integer(self):
|
||||||
# issue13436: Bad error message with invalid numeric values
|
# issue13436: Bad error message with invalid numeric values
|
||||||
body = [ast.ImportFrom(module='time',
|
body = [ast.ImportFrom(module='time',
|
||||||
|
|
|
@ -1621,6 +1621,48 @@ class BuiltinTest(unittest.TestCase):
|
||||||
self.assertEqual(self.iter_error(z1, ValueError), t)
|
self.assertEqual(self.iter_error(z1, ValueError), t)
|
||||||
self.assertEqual(self.iter_error(z2, 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):
|
def test_zip_bad_iterable(self):
|
||||||
exception = TypeError()
|
exception = TypeError()
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,8 @@
|
||||||
# This script doesn't actually display anything very coherent. but it
|
# This script doesn't actually display anything very coherent. but it
|
||||||
# does call (nearly) every method and function.
|
# 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()
|
# Only called, not tested: getmouse(), ungetmouse()
|
||||||
#
|
#
|
||||||
|
|
||||||
|
@ -12,7 +13,6 @@ import os
|
||||||
import string
|
import string
|
||||||
import sys
|
import sys
|
||||||
import tempfile
|
import tempfile
|
||||||
import functools
|
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
from test.support import requires, verbose, SaveSignals
|
from test.support import requires, verbose, SaveSignals
|
||||||
|
@ -37,17 +37,7 @@ def requires_curses_func(name):
|
||||||
return unittest.skipUnless(hasattr(curses, name),
|
return unittest.skipUnless(hasattr(curses, name),
|
||||||
'requires curses.%s' % 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')
|
term = os.environ.get('TERM')
|
||||||
SHORT_MAX = 0x7fff
|
|
||||||
|
|
||||||
# If newterm was supported we could use it instead of initscr and not exit
|
# If newterm was supported we could use it instead of initscr and not exit
|
||||||
@unittest.skipIf(not term or term == 'unknown',
|
@unittest.skipIf(not term or term == 'unknown',
|
||||||
|
@ -58,59 +48,37 @@ class TestCurses(unittest.TestCase):
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def setUpClass(cls):
|
def setUpClass(cls):
|
||||||
if verbose:
|
if not sys.__stdout__.isatty():
|
||||||
print(f'TERM={term}', file=sys.stderr, flush=True)
|
# 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
|
# testing setupterm() inside initscr/endwin
|
||||||
# causes terminal breakage
|
# causes terminal breakage
|
||||||
stdout_fd = sys.__stdout__.fileno()
|
curses.setupterm(fd=fd)
|
||||||
curses.setupterm(fd=stdout_fd)
|
|
||||||
|
@classmethod
|
||||||
|
def tearDownClass(cls):
|
||||||
|
if cls.tmp:
|
||||||
|
cls.tmp.close()
|
||||||
|
del cls.tmp
|
||||||
|
|
||||||
def setUp(self):
|
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 = SaveSignals()
|
||||||
self.save_signals.save()
|
self.save_signals.save()
|
||||||
self.addCleanup(self.save_signals.restore)
|
if verbose:
|
||||||
if verbose and self.output is not None:
|
|
||||||
# just to make the test output a little more readable
|
# just to make the test output a little more readable
|
||||||
sys.stderr.flush()
|
print()
|
||||||
sys.stdout.flush()
|
|
||||||
print(file=self.output, flush=True)
|
|
||||||
self.stdscr = curses.initscr()
|
self.stdscr = curses.initscr()
|
||||||
if self.isatty:
|
curses.savetty()
|
||||||
curses.savetty()
|
|
||||||
self.addCleanup(curses.endwin)
|
def tearDown(self):
|
||||||
self.addCleanup(curses.resetty)
|
curses.resetty()
|
||||||
|
curses.endwin()
|
||||||
|
self.save_signals.restore()
|
||||||
|
|
||||||
def test_window_funcs(self):
|
def test_window_funcs(self):
|
||||||
"Test the methods of windows"
|
"Test the methods of windows"
|
||||||
|
@ -128,7 +96,7 @@ class TestCurses(unittest.TestCase):
|
||||||
for meth in [stdscr.clear, stdscr.clrtobot,
|
for meth in [stdscr.clear, stdscr.clrtobot,
|
||||||
stdscr.clrtoeol, stdscr.cursyncup, stdscr.delch,
|
stdscr.clrtoeol, stdscr.cursyncup, stdscr.delch,
|
||||||
stdscr.deleteln, stdscr.erase, stdscr.getbegyx,
|
stdscr.deleteln, stdscr.erase, stdscr.getbegyx,
|
||||||
stdscr.getbkgd, stdscr.getmaxyx,
|
stdscr.getbkgd, stdscr.getkey, stdscr.getmaxyx,
|
||||||
stdscr.getparyx, stdscr.getyx, stdscr.inch,
|
stdscr.getparyx, stdscr.getyx, stdscr.inch,
|
||||||
stdscr.insertln, stdscr.instr, stdscr.is_wintouched,
|
stdscr.insertln, stdscr.instr, stdscr.is_wintouched,
|
||||||
win.noutrefresh, stdscr.redrawwin, stdscr.refresh,
|
win.noutrefresh, stdscr.redrawwin, stdscr.refresh,
|
||||||
|
@ -239,11 +207,6 @@ class TestCurses(unittest.TestCase):
|
||||||
if hasattr(stdscr, 'enclose'):
|
if hasattr(stdscr, 'enclose'):
|
||||||
stdscr.enclose(10, 10)
|
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, -400)
|
||||||
self.assertRaises(ValueError, stdscr.getstr, 2, 3, -400)
|
self.assertRaises(ValueError, stdscr.getstr, 2, 3, -400)
|
||||||
self.assertRaises(ValueError, stdscr.instr, -2)
|
self.assertRaises(ValueError, stdscr.instr, -2)
|
||||||
|
@ -262,20 +225,17 @@ class TestCurses(unittest.TestCase):
|
||||||
def test_module_funcs(self):
|
def test_module_funcs(self):
|
||||||
"Test module-level functions"
|
"Test module-level functions"
|
||||||
for func in [curses.baudrate, curses.beep, curses.can_change_color,
|
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.has_colors, curses.has_ic, curses.has_il,
|
||||||
curses.isendwin, curses.killchar, curses.longname,
|
curses.isendwin, curses.killchar, curses.longname,
|
||||||
curses.noecho, curses.nonl, curses.noqiflush,
|
curses.nocbreak, curses.noecho, curses.nonl,
|
||||||
curses.termattrs, curses.termname, curses.erasechar,
|
curses.noqiflush, curses.noraw,
|
||||||
|
curses.reset_prog_mode, curses.termattrs,
|
||||||
|
curses.termname, curses.erasechar,
|
||||||
curses.has_extended_color_support]:
|
curses.has_extended_color_support]:
|
||||||
with self.subTest(func=func.__qualname__):
|
with self.subTest(func=func.__qualname__):
|
||||||
func()
|
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'):
|
if hasattr(curses, 'filter'):
|
||||||
curses.filter()
|
curses.filter()
|
||||||
if hasattr(curses, 'getsyx'):
|
if hasattr(curses, 'getsyx'):
|
||||||
|
@ -287,9 +247,13 @@ class TestCurses(unittest.TestCase):
|
||||||
curses.delay_output(1)
|
curses.delay_output(1)
|
||||||
curses.echo() ; curses.echo(1)
|
curses.echo() ; curses.echo(1)
|
||||||
|
|
||||||
|
with tempfile.TemporaryFile() as f:
|
||||||
|
self.stdscr.putwin(f)
|
||||||
|
f.seek(0)
|
||||||
|
curses.getwin(f)
|
||||||
|
|
||||||
curses.halfdelay(1)
|
curses.halfdelay(1)
|
||||||
if self.isatty:
|
curses.intrflush(1)
|
||||||
curses.intrflush(1)
|
|
||||||
curses.meta(1)
|
curses.meta(1)
|
||||||
curses.napms(100)
|
curses.napms(100)
|
||||||
curses.newpad(50,50)
|
curses.newpad(50,50)
|
||||||
|
@ -298,8 +262,7 @@ class TestCurses(unittest.TestCase):
|
||||||
curses.nl() ; curses.nl(1)
|
curses.nl() ; curses.nl(1)
|
||||||
curses.putp(b'abc')
|
curses.putp(b'abc')
|
||||||
curses.qiflush()
|
curses.qiflush()
|
||||||
if self.isatty:
|
curses.raw() ; curses.raw(1)
|
||||||
curses.raw() ; curses.raw(1)
|
|
||||||
curses.set_escdelay(25)
|
curses.set_escdelay(25)
|
||||||
self.assertEqual(curses.get_escdelay(), 25)
|
self.assertEqual(curses.get_escdelay(), 25)
|
||||||
curses.set_tabsize(4)
|
curses.set_tabsize(4)
|
||||||
|
@ -318,127 +281,31 @@ class TestCurses(unittest.TestCase):
|
||||||
curses.use_env(1)
|
curses.use_env(1)
|
||||||
|
|
||||||
# Functions only available on a few platforms
|
# Functions only available on a few platforms
|
||||||
|
def test_colors_funcs(self):
|
||||||
def bad_colors(self):
|
|
||||||
return (-1, curses.COLORS, -2**31 - 1, 2**31, -2**63 - 1, 2**63, 2**64)
|
|
||||||
|
|
||||||
def bad_colors2(self):
|
|
||||||
return (curses.COLORS, 2**31, 2**63, 2**64)
|
|
||||||
|
|
||||||
def bad_pairs(self):
|
|
||||||
return (-1, -2**31 - 1, 2**31, -2**63 - 1, 2**63, 2**64)
|
|
||||||
|
|
||||||
def test_start_color(self):
|
|
||||||
if not curses.has_colors():
|
if not curses.has_colors():
|
||||||
self.skipTest('requires colors support')
|
self.skipTest('requires colors support')
|
||||||
curses.start_color()
|
curses.start_color()
|
||||||
if verbose:
|
curses.init_pair(2, 1,1)
|
||||||
print(f'COLORS = {curses.COLORS}', file=sys.stderr)
|
curses.color_content(1)
|
||||||
print(f'COLOR_PAIRS = {curses.COLOR_PAIRS}', file=sys.stderr)
|
curses.color_pair(2)
|
||||||
|
curses.pair_content(curses.COLOR_PAIRS - 1)
|
||||||
|
curses.pair_number(0)
|
||||||
|
|
||||||
@requires_colors
|
if hasattr(curses, 'use_default_colors'):
|
||||||
def test_color_content(self):
|
curses.use_default_colors()
|
||||||
self.assertEqual(curses.color_content(curses.COLOR_BLACK), (0, 0, 0))
|
|
||||||
curses.color_content(0)
|
|
||||||
maxcolor = curses.COLORS - 1
|
|
||||||
curses.color_content(maxcolor)
|
|
||||||
|
|
||||||
for color in self.bad_colors():
|
self.assertRaises(ValueError, curses.color_content, -1)
|
||||||
self.assertRaises(ValueError, curses.color_content, color)
|
self.assertRaises(ValueError, curses.color_content, curses.COLORS + 1)
|
||||||
|
self.assertRaises(ValueError, curses.color_content, -2**31 - 1)
|
||||||
@requires_colors
|
self.assertRaises(ValueError, curses.color_content, 2**31)
|
||||||
def test_init_color(self):
|
self.assertRaises(ValueError, curses.color_content, -2**63 - 1)
|
||||||
if not curses.can_change_color:
|
self.assertRaises(ValueError, curses.color_content, 2**63 - 1)
|
||||||
self.skipTest('cannot change color')
|
self.assertRaises(ValueError, curses.pair_content, -1)
|
||||||
|
self.assertRaises(ValueError, curses.pair_content, curses.COLOR_PAIRS)
|
||||||
old = curses.color_content(0)
|
self.assertRaises(ValueError, curses.pair_content, -2**31 - 1)
|
||||||
try:
|
self.assertRaises(ValueError, curses.pair_content, 2**31)
|
||||||
curses.init_color(0, *old)
|
self.assertRaises(ValueError, curses.pair_content, -2**63 - 1)
|
||||||
except curses.error:
|
self.assertRaises(ValueError, curses.pair_content, 2**63 - 1)
|
||||||
self.skipTest('cannot change color (init_color() failed)')
|
|
||||||
self.addCleanup(curses.init_color, 0, *old)
|
|
||||||
curses.init_color(0, 0, 0, 0)
|
|
||||||
self.assertEqual(curses.color_content(0), (0, 0, 0))
|
|
||||||
curses.init_color(0, 1000, 1000, 1000)
|
|
||||||
self.assertEqual(curses.color_content(0), (1000, 1000, 1000))
|
|
||||||
|
|
||||||
maxcolor = curses.COLORS - 1
|
|
||||||
old = curses.color_content(maxcolor)
|
|
||||||
curses.init_color(maxcolor, *old)
|
|
||||||
self.addCleanup(curses.init_color, maxcolor, *old)
|
|
||||||
curses.init_color(maxcolor, 0, 500, 1000)
|
|
||||||
self.assertEqual(curses.color_content(maxcolor), (0, 500, 1000))
|
|
||||||
|
|
||||||
for color in self.bad_colors():
|
|
||||||
self.assertRaises(ValueError, curses.init_color, color, 0, 0, 0)
|
|
||||||
for comp in (-1, 1001):
|
|
||||||
self.assertRaises(ValueError, curses.init_color, 0, comp, 0, 0)
|
|
||||||
self.assertRaises(ValueError, curses.init_color, 0, 0, comp, 0)
|
|
||||||
self.assertRaises(ValueError, curses.init_color, 0, 0, 0, comp)
|
|
||||||
|
|
||||||
def get_pair_limit(self):
|
|
||||||
pair_limit = curses.COLOR_PAIRS
|
|
||||||
if hasattr(curses, 'ncurses_version'):
|
|
||||||
if curses.has_extended_color_support():
|
|
||||||
pair_limit += 2*curses.COLORS + 1
|
|
||||||
if (not curses.has_extended_color_support()
|
|
||||||
or (6, 1) <= curses.ncurses_version < (6, 2)):
|
|
||||||
pair_limit = min(pair_limit, SHORT_MAX)
|
|
||||||
return pair_limit
|
|
||||||
|
|
||||||
@requires_colors
|
|
||||||
def test_pair_content(self):
|
|
||||||
if not hasattr(curses, 'use_default_colors'):
|
|
||||||
self.assertEqual(curses.pair_content(0),
|
|
||||||
(curses.COLOR_WHITE, curses.COLOR_BLACK))
|
|
||||||
curses.pair_content(0)
|
|
||||||
maxpair = self.get_pair_limit() - 1
|
|
||||||
if maxpair > 0:
|
|
||||||
curses.pair_content(maxpair)
|
|
||||||
|
|
||||||
for pair in self.bad_pairs():
|
|
||||||
self.assertRaises(ValueError, curses.pair_content, pair)
|
|
||||||
|
|
||||||
@requires_colors
|
|
||||||
def test_init_pair(self):
|
|
||||||
old = curses.pair_content(1)
|
|
||||||
curses.init_pair(1, *old)
|
|
||||||
self.addCleanup(curses.init_pair, 1, *old)
|
|
||||||
|
|
||||||
curses.init_pair(1, 0, 0)
|
|
||||||
self.assertEqual(curses.pair_content(1), (0, 0))
|
|
||||||
maxcolor = curses.COLORS - 1
|
|
||||||
curses.init_pair(1, maxcolor, 0)
|
|
||||||
self.assertEqual(curses.pair_content(1), (maxcolor, 0))
|
|
||||||
curses.init_pair(1, 0, maxcolor)
|
|
||||||
self.assertEqual(curses.pair_content(1), (0, maxcolor))
|
|
||||||
maxpair = self.get_pair_limit() - 1
|
|
||||||
if maxpair > 1:
|
|
||||||
curses.init_pair(maxpair, 0, 0)
|
|
||||||
self.assertEqual(curses.pair_content(maxpair), (0, 0))
|
|
||||||
|
|
||||||
for pair in self.bad_pairs():
|
|
||||||
self.assertRaises(ValueError, curses.init_pair, pair, 0, 0)
|
|
||||||
for color in self.bad_colors2():
|
|
||||||
self.assertRaises(ValueError, curses.init_pair, 1, color, 0)
|
|
||||||
self.assertRaises(ValueError, curses.init_pair, 1, 0, color)
|
|
||||||
|
|
||||||
@requires_colors
|
|
||||||
def test_color_attrs(self):
|
|
||||||
for pair in 0, 1, 255:
|
|
||||||
attr = curses.color_pair(pair)
|
|
||||||
self.assertEqual(curses.pair_number(attr), pair, attr)
|
|
||||||
self.assertEqual(curses.pair_number(attr | curses.A_BOLD), pair)
|
|
||||||
self.assertEqual(curses.color_pair(0), 0)
|
|
||||||
self.assertEqual(curses.pair_number(0), 0)
|
|
||||||
|
|
||||||
@requires_curses_func('use_default_colors')
|
|
||||||
@requires_colors
|
|
||||||
def test_use_default_colors(self):
|
|
||||||
self.assertIn(curses.pair_content(0),
|
|
||||||
((curses.COLOR_WHITE, curses.COLOR_BLACK), (-1, -1)))
|
|
||||||
curses.use_default_colors()
|
|
||||||
self.assertEqual(curses.pair_content(0), (-1, -1))
|
|
||||||
|
|
||||||
@requires_curses_func('keyname')
|
@requires_curses_func('keyname')
|
||||||
def test_keyname(self):
|
def test_keyname(self):
|
||||||
|
@ -506,6 +373,7 @@ class TestCurses(unittest.TestCase):
|
||||||
|
|
||||||
@requires_curses_func('resizeterm')
|
@requires_curses_func('resizeterm')
|
||||||
def test_resizeterm(self):
|
def test_resizeterm(self):
|
||||||
|
stdscr = self.stdscr
|
||||||
lines, cols = curses.LINES, curses.COLS
|
lines, cols = curses.LINES, curses.COLS
|
||||||
new_lines = lines - 1
|
new_lines = lines - 1
|
||||||
new_cols = cols + 1
|
new_cols = cols + 1
|
||||||
|
@ -609,8 +477,6 @@ class MiscTests(unittest.TestCase):
|
||||||
@requires_curses_func('ncurses_version')
|
@requires_curses_func('ncurses_version')
|
||||||
def test_ncurses_version(self):
|
def test_ncurses_version(self):
|
||||||
v = curses.ncurses_version
|
v = curses.ncurses_version
|
||||||
if verbose:
|
|
||||||
print(f'ncurses_version = {curses.ncurses_version}', flush=True)
|
|
||||||
self.assertIsInstance(v[:], tuple)
|
self.assertIsInstance(v[:], tuple)
|
||||||
self.assertEqual(len(v), 3)
|
self.assertEqual(len(v), 3)
|
||||||
self.assertIsInstance(v[0], int)
|
self.assertIsInstance(v[0], int)
|
||||||
|
|
|
@ -2119,7 +2119,7 @@ class TestEnum(unittest.TestCase):
|
||||||
one = '1'
|
one = '1'
|
||||||
two = b'2', 'ascii', 9
|
two = b'2', 'ascii', 9
|
||||||
|
|
||||||
def test_init_subclass_calling(self):
|
def test_init_subclass(self):
|
||||||
class MyEnum(Enum):
|
class MyEnum(Enum):
|
||||||
def __init_subclass__(cls, **kwds):
|
def __init_subclass__(cls, **kwds):
|
||||||
super(MyEnum, cls).__init_subclass__(**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('_test1', False))
|
||||||
self.assertFalse(NeverEnum.__dict__.get('_test2', 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(
|
@unittest.skipUnless(
|
||||||
sys.version_info[:2] == (3, 9),
|
sys.version_info[:2] == (3, 9),
|
||||||
|
|
|
@ -332,59 +332,6 @@ non-important content
|
||||||
self.assertEqual(binop.left.col_offset, 4)
|
self.assertEqual(binop.left.col_offset, 4)
|
||||||
self.assertEqual(binop.right.col_offset, 7)
|
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 test_docstring(self):
|
||||||
def f():
|
def f():
|
||||||
f'''Not a docstring'''
|
f'''Not a docstring'''
|
||||||
|
|
|
@ -27,7 +27,8 @@ import functools
|
||||||
|
|
||||||
py_functools = import_helper.import_fresh_module('functools',
|
py_functools = import_helper.import_fresh_module('functools',
|
||||||
blocked=['_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'])
|
decimal = import_helper.import_fresh_module('decimal', fresh=['_decimal'])
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,6 @@ import textwrap
|
||||||
import contextlib
|
import contextlib
|
||||||
|
|
||||||
from test.support.os_helper import FS_NONASCII
|
from test.support.os_helper import FS_NONASCII
|
||||||
from typing import Dict, Union
|
|
||||||
|
|
||||||
|
|
||||||
@contextlib.contextmanager
|
@contextlib.contextmanager
|
||||||
|
@ -72,13 +71,8 @@ class OnSysPath(Fixtures):
|
||||||
self.fixtures.enter_context(self.add_sys_path(self.site_dir))
|
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):
|
class DistInfoPkg(OnSysPath, SiteDir):
|
||||||
files: FilesDef = {
|
files = {
|
||||||
"distinfo_pkg-1.0.0.dist-info": {
|
"distinfo_pkg-1.0.0.dist-info": {
|
||||||
"METADATA": """
|
"METADATA": """
|
||||||
Name: distinfo-pkg
|
Name: distinfo-pkg
|
||||||
|
@ -92,55 +86,19 @@ class DistInfoPkg(OnSysPath, SiteDir):
|
||||||
[entries]
|
[entries]
|
||||||
main = mod:main
|
main = mod:main
|
||||||
ns:sub = mod:main
|
ns:sub = mod:main
|
||||||
""",
|
"""
|
||||||
},
|
},
|
||||||
"mod.py": """
|
"mod.py": """
|
||||||
def main():
|
def main():
|
||||||
print("hello world")
|
print("hello world")
|
||||||
""",
|
""",
|
||||||
}
|
}
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(DistInfoPkg, self).setUp()
|
super(DistInfoPkg, self).setUp()
|
||||||
build_files(DistInfoPkg.files, self.site_dir)
|
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):
|
class DistInfoPkgOffPath(SiteDir):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(DistInfoPkgOffPath, self).setUp()
|
super(DistInfoPkgOffPath, self).setUp()
|
||||||
|
@ -148,7 +106,7 @@ class DistInfoPkgOffPath(SiteDir):
|
||||||
|
|
||||||
|
|
||||||
class EggInfoPkg(OnSysPath, SiteDir):
|
class EggInfoPkg(OnSysPath, SiteDir):
|
||||||
files: FilesDef = {
|
files = {
|
||||||
"egginfo_pkg.egg-info": {
|
"egginfo_pkg.egg-info": {
|
||||||
"PKG-INFO": """
|
"PKG-INFO": """
|
||||||
Name: egginfo-pkg
|
Name: egginfo-pkg
|
||||||
|
@ -171,13 +129,13 @@ class EggInfoPkg(OnSysPath, SiteDir):
|
||||||
[test]
|
[test]
|
||||||
pytest
|
pytest
|
||||||
""",
|
""",
|
||||||
"top_level.txt": "mod\n",
|
"top_level.txt": "mod\n"
|
||||||
},
|
},
|
||||||
"mod.py": """
|
"mod.py": """
|
||||||
def main():
|
def main():
|
||||||
print("hello world")
|
print("hello world")
|
||||||
""",
|
""",
|
||||||
}
|
}
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(EggInfoPkg, self).setUp()
|
super(EggInfoPkg, self).setUp()
|
||||||
|
@ -185,7 +143,7 @@ class EggInfoPkg(OnSysPath, SiteDir):
|
||||||
|
|
||||||
|
|
||||||
class EggInfoFile(OnSysPath, SiteDir):
|
class EggInfoFile(OnSysPath, SiteDir):
|
||||||
files: FilesDef = {
|
files = {
|
||||||
"egginfo_file.egg-info": """
|
"egginfo_file.egg-info": """
|
||||||
Metadata-Version: 1.0
|
Metadata-Version: 1.0
|
||||||
Name: egginfo_file
|
Name: egginfo_file
|
||||||
|
@ -198,7 +156,7 @@ class EggInfoFile(OnSysPath, SiteDir):
|
||||||
Description: UNKNOWN
|
Description: UNKNOWN
|
||||||
Platform: UNKNOWN
|
Platform: UNKNOWN
|
||||||
""",
|
""",
|
||||||
}
|
}
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(EggInfoFile, self).setUp()
|
super(EggInfoFile, self).setUp()
|
||||||
|
@ -206,12 +164,12 @@ class EggInfoFile(OnSysPath, SiteDir):
|
||||||
|
|
||||||
|
|
||||||
class LocalPackage:
|
class LocalPackage:
|
||||||
files: FilesDef = {
|
files = {
|
||||||
"setup.py": """
|
"setup.py": """
|
||||||
import setuptools
|
import setuptools
|
||||||
setuptools.setup(name="local-pkg", version="2.0.1")
|
setuptools.setup(name="local-pkg", version="2.0.1")
|
||||||
""",
|
""",
|
||||||
}
|
}
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.fixtures = contextlib.ExitStack()
|
self.fixtures = contextlib.ExitStack()
|
||||||
|
@ -256,7 +214,8 @@ def build_files(file_defs, prefix=pathlib.Path()):
|
||||||
|
|
||||||
class FileBuilder:
|
class FileBuilder:
|
||||||
def unicode_filename(self):
|
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):
|
def DALS(str):
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
# coding: utf-8
|
||||||
|
|
||||||
import re
|
import re
|
||||||
import json
|
import json
|
||||||
import pickle
|
import pickle
|
||||||
|
@ -12,14 +14,10 @@ except ImportError:
|
||||||
|
|
||||||
from . import fixtures
|
from . import fixtures
|
||||||
from importlib.metadata import (
|
from importlib.metadata import (
|
||||||
Distribution,
|
Distribution, EntryPoint,
|
||||||
EntryPoint,
|
PackageNotFoundError, distributions,
|
||||||
PackageNotFoundError,
|
entry_points, metadata, version,
|
||||||
distributions,
|
)
|
||||||
entry_points,
|
|
||||||
metadata,
|
|
||||||
version,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class BasicTests(fixtures.DistInfoPkg, unittest.TestCase):
|
class BasicTests(fixtures.DistInfoPkg, unittest.TestCase):
|
||||||
|
@ -72,11 +70,12 @@ class ImportTests(fixtures.DistInfoPkg, unittest.TestCase):
|
||||||
name='ep',
|
name='ep',
|
||||||
value='importlib.metadata',
|
value='importlib.metadata',
|
||||||
group='grp',
|
group='grp',
|
||||||
)
|
)
|
||||||
assert ep.load() is importlib.metadata
|
assert ep.load() is importlib.metadata
|
||||||
|
|
||||||
|
|
||||||
class NameNormalizationTests(fixtures.OnSysPath, fixtures.SiteDir, unittest.TestCase):
|
class NameNormalizationTests(
|
||||||
|
fixtures.OnSysPath, fixtures.SiteDir, unittest.TestCase):
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def pkg_with_dashes(site_dir):
|
def pkg_with_dashes(site_dir):
|
||||||
"""
|
"""
|
||||||
|
@ -145,15 +144,11 @@ class NonASCIITests(fixtures.OnSysPath, fixtures.SiteDir, unittest.TestCase):
|
||||||
metadata_dir.mkdir()
|
metadata_dir.mkdir()
|
||||||
metadata = metadata_dir / 'METADATA'
|
metadata = metadata_dir / 'METADATA'
|
||||||
with metadata.open('w', encoding='utf-8') as fp:
|
with metadata.open('w', encoding='utf-8') as fp:
|
||||||
fp.write(
|
fp.write(textwrap.dedent("""
|
||||||
textwrap.dedent(
|
|
||||||
"""
|
|
||||||
Name: portend
|
Name: portend
|
||||||
|
|
||||||
pôrˈtend
|
pôrˈtend
|
||||||
"""
|
""").lstrip())
|
||||||
).lstrip()
|
|
||||||
)
|
|
||||||
return 'portend'
|
return 'portend'
|
||||||
|
|
||||||
def test_metadata_loads(self):
|
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'
|
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):
|
def test_package_discovery(self):
|
||||||
dists = list(distributions())
|
dists = list(distributions())
|
||||||
assert all(isinstance(dist, Distribution) for dist in dists)
|
assert all(
|
||||||
assert any(dist.metadata['Name'] == 'egginfo-pkg' for dist in dists)
|
isinstance(dist, Distribution)
|
||||||
assert any(dist.metadata['Name'] == 'distinfo-pkg' for dist in dists)
|
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):
|
def test_invalid_usage(self):
|
||||||
with self.assertRaises(ValueError):
|
with self.assertRaises(ValueError):
|
||||||
|
@ -258,21 +265,10 @@ class TestEntryPoints(unittest.TestCase):
|
||||||
def test_attr(self):
|
def test_attr(self):
|
||||||
assert self.ep.attr is None
|
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(
|
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):
|
def test_unicode_dir_on_sys_path(self):
|
||||||
"""
|
"""
|
||||||
Ensure a Unicode subdirectory of a directory on sys.path
|
Ensure a Unicode subdirectory of a directory on sys.path
|
||||||
|
@ -281,5 +277,5 @@ class FileSystem(
|
||||||
fixtures.build_files(
|
fixtures.build_files(
|
||||||
{self.unicode_filename(): {}},
|
{self.unicode_filename(): {}},
|
||||||
prefix=self.site_dir,
|
prefix=self.site_dir,
|
||||||
)
|
)
|
||||||
list(distributions())
|
list(distributions())
|
||||||
|
|
|
@ -2,26 +2,20 @@ import re
|
||||||
import textwrap
|
import textwrap
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
|
from collections.abc import Iterator
|
||||||
|
|
||||||
from . import fixtures
|
from . import fixtures
|
||||||
from importlib.metadata import (
|
from importlib.metadata import (
|
||||||
Distribution,
|
Distribution, PackageNotFoundError, distribution,
|
||||||
PackageNotFoundError,
|
entry_points, files, metadata, requires, version,
|
||||||
distribution,
|
)
|
||||||
entry_points,
|
|
||||||
files,
|
|
||||||
metadata,
|
|
||||||
requires,
|
|
||||||
version,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class APITests(
|
class APITests(
|
||||||
fixtures.EggInfoPkg,
|
fixtures.EggInfoPkg,
|
||||||
fixtures.DistInfoPkg,
|
fixtures.DistInfoPkg,
|
||||||
fixtures.DistInfoPkgWithDot,
|
fixtures.EggInfoFile,
|
||||||
fixtures.EggInfoFile,
|
unittest.TestCase):
|
||||||
unittest.TestCase,
|
|
||||||
):
|
|
||||||
|
|
||||||
version_pattern = r'\d+\.\d+(\.\d)?'
|
version_pattern = r'\d+\.\d+(\.\d)?'
|
||||||
|
|
||||||
|
@ -39,28 +33,16 @@ class APITests(
|
||||||
with self.assertRaises(PackageNotFoundError):
|
with self.assertRaises(PackageNotFoundError):
|
||||||
distribution('does-not-exist')
|
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):
|
def test_for_top_level(self):
|
||||||
self.assertEqual(
|
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):
|
def test_read_text(self):
|
||||||
top_level = [
|
top_level = [
|
||||||
path for path in files('egginfo-pkg') if path.name == 'top_level.txt'
|
path for path in files('egginfo-pkg')
|
||||||
][0]
|
if path.name == 'top_level.txt'
|
||||||
|
][0]
|
||||||
self.assertEqual(top_level.read_text(), 'mod\n')
|
self.assertEqual(top_level.read_text(), 'mod\n')
|
||||||
|
|
||||||
def test_entry_points(self):
|
def test_entry_points(self):
|
||||||
|
@ -69,13 +51,6 @@ class APITests(
|
||||||
self.assertEqual(ep.value, 'mod:main')
|
self.assertEqual(ep.value, 'mod:main')
|
||||||
self.assertEqual(ep.extras, [])
|
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):
|
def test_metadata_for_this_package(self):
|
||||||
md = metadata('egginfo-pkg')
|
md = metadata('egginfo-pkg')
|
||||||
assert md['author'] == 'Steven Ma'
|
assert md['author'] == 'Steven Ma'
|
||||||
|
@ -100,8 +75,13 @@ class APITests(
|
||||||
def test_file_hash_repr(self):
|
def test_file_hash_repr(self):
|
||||||
assertRegex = self.assertRegex
|
assertRegex = self.assertRegex
|
||||||
|
|
||||||
util = [p for p in files('distinfo-pkg') if p.name == 'mod.py'][0]
|
util = [
|
||||||
assertRegex(repr(util.hash), '<FileHash mode: sha256 value: .*>')
|
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):
|
def test_files_dist_info(self):
|
||||||
self._test_files(files('distinfo-pkg'))
|
self._test_files(files('distinfo-pkg'))
|
||||||
|
@ -119,7 +99,10 @@ class APITests(
|
||||||
def test_requires_egg_info(self):
|
def test_requires_egg_info(self):
|
||||||
deps = requires('egginfo-pkg')
|
deps = requires('egginfo-pkg')
|
||||||
assert len(deps) == 2
|
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):
|
def test_requires_dist_info(self):
|
||||||
deps = requires('distinfo-pkg')
|
deps = requires('distinfo-pkg')
|
||||||
|
@ -129,8 +112,7 @@ class APITests(
|
||||||
assert "pytest; extra == 'test'" in deps
|
assert "pytest; extra == 'test'" in deps
|
||||||
|
|
||||||
def test_more_complex_deps_requires_text(self):
|
def test_more_complex_deps_requires_text(self):
|
||||||
requires = textwrap.dedent(
|
requires = textwrap.dedent("""
|
||||||
"""
|
|
||||||
dep1
|
dep1
|
||||||
dep2
|
dep2
|
||||||
|
|
||||||
|
@ -142,8 +124,7 @@ class APITests(
|
||||||
|
|
||||||
[extra2:python_version < "3"]
|
[extra2:python_version < "3"]
|
||||||
dep5
|
dep5
|
||||||
"""
|
""")
|
||||||
)
|
|
||||||
deps = sorted(Distribution._deps_from_requires_text(requires))
|
deps = sorted(Distribution._deps_from_requires_text(requires))
|
||||||
expected = [
|
expected = [
|
||||||
'dep1',
|
'dep1',
|
||||||
|
@ -151,7 +132,7 @@ class APITests(
|
||||||
'dep3; python_version < "3"',
|
'dep3; python_version < "3"',
|
||||||
'dep4; extra == "extra1"',
|
'dep4; extra == "extra1"',
|
||||||
'dep5; (python_version < "3") and extra == "extra2"',
|
'dep5; (python_version < "3") and extra == "extra2"',
|
||||||
]
|
]
|
||||||
# It's important that the environment marker expression be
|
# It's important that the environment marker expression be
|
||||||
# wrapped in parentheses to avoid the following 'and' binding more
|
# wrapped in parentheses to avoid the following 'and' binding more
|
||||||
# tightly than some other part of the environment expression.
|
# tightly than some other part of the environment expression.
|
||||||
|
@ -159,27 +140,17 @@ class APITests(
|
||||||
assert deps == expected
|
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):
|
class OffSysPathTests(fixtures.DistInfoPkgOffPath, unittest.TestCase):
|
||||||
def test_find_distributions_specified_path(self):
|
def test_find_distributions_specified_path(self):
|
||||||
dists = Distribution.discover(path=[str(self.site_dir)])
|
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):
|
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_info_path = self.site_dir / 'distinfo_pkg-1.0.0.dist-info'
|
||||||
dist = Distribution.at(dist_info_path)
|
dist = Distribution.at(dist_info_path)
|
||||||
assert dist.version == '1.0.0'
|
assert dist.version == '1.0.0'
|
||||||
|
|
|
@ -3,12 +3,8 @@ import unittest
|
||||||
|
|
||||||
from contextlib import ExitStack
|
from contextlib import ExitStack
|
||||||
from importlib.metadata import (
|
from importlib.metadata import (
|
||||||
PackageNotFoundError,
|
distribution, entry_points, files, PackageNotFoundError,
|
||||||
distribution,
|
version, distributions,
|
||||||
distributions,
|
|
||||||
entry_points,
|
|
||||||
files,
|
|
||||||
version,
|
|
||||||
)
|
)
|
||||||
from importlib import resources
|
from importlib import resources
|
||||||
|
|
||||||
|
|
|
@ -82,7 +82,7 @@ class NetworkedNNTPTestsMixin:
|
||||||
desc = self.server.description(self.GROUP_NAME)
|
desc = self.server.description(self.GROUP_NAME)
|
||||||
_check_desc(desc)
|
_check_desc(desc)
|
||||||
# Another sanity check
|
# Another sanity check
|
||||||
self.assertIn(self.DESC, desc)
|
self.assertIn("Python", desc)
|
||||||
# With a pattern
|
# With a pattern
|
||||||
desc = self.server.description(self.GROUP_PAT)
|
desc = self.server.description(self.GROUP_PAT)
|
||||||
_check_desc(desc)
|
_check_desc(desc)
|
||||||
|
@ -309,7 +309,6 @@ class NetworkedNNTPTests(NetworkedNNTPTestsMixin, unittest.TestCase):
|
||||||
NNTP_HOST = 'news.trigofacile.com'
|
NNTP_HOST = 'news.trigofacile.com'
|
||||||
GROUP_NAME = 'fr.comp.lang.python'
|
GROUP_NAME = 'fr.comp.lang.python'
|
||||||
GROUP_PAT = 'fr.comp.lang.*'
|
GROUP_PAT = 'fr.comp.lang.*'
|
||||||
DESC = 'Python'
|
|
||||||
|
|
||||||
NNTP_CLASS = NNTP
|
NNTP_CLASS = NNTP
|
||||||
|
|
||||||
|
@ -344,11 +343,8 @@ class NetworkedNNTP_SSLTests(NetworkedNNTPTests):
|
||||||
# 400 connections per day are accepted from each IP address."
|
# 400 connections per day are accepted from each IP address."
|
||||||
|
|
||||||
NNTP_HOST = 'nntp.aioe.org'
|
NNTP_HOST = 'nntp.aioe.org'
|
||||||
# bpo-42794: aioe.test is one of the official groups on this server
|
GROUP_NAME = 'comp.lang.python'
|
||||||
# used for testing: https://news.aioe.org/manual/aioe-hierarchy/
|
GROUP_PAT = 'comp.lang.*'
|
||||||
GROUP_NAME = 'aioe.test'
|
|
||||||
GROUP_PAT = 'aioe.*'
|
|
||||||
DESC = 'test'
|
|
||||||
|
|
||||||
NNTP_CLASS = getattr(nntplib, 'NNTP_SSL', None)
|
NNTP_CLASS = getattr(nntplib, 'NNTP_SSL', None)
|
||||||
|
|
||||||
|
|
|
@ -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)
|
|
|
@ -1,6 +1,4 @@
|
||||||
import os
|
import os
|
||||||
import copy
|
|
||||||
import pickle
|
|
||||||
import platform
|
import platform
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
|
@ -236,38 +234,6 @@ class PlatformTest(unittest.TestCase):
|
||||||
)
|
)
|
||||||
self.assertEqual(tuple(res), expected)
|
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")
|
@unittest.skipIf(sys.platform in ['win32', 'OpenVMS'], "uname -p not used")
|
||||||
def test_uname_processor(self):
|
def test_uname_processor(self):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -204,16 +204,6 @@ class PropertyTests(unittest.TestCase):
|
||||||
return 'Second'
|
return 'Second'
|
||||||
self.assertEqual(A.__doc__, '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
|
# Issue 5890: subclasses of property do not preserve method __doc__ strings
|
||||||
class PropertySub(property):
|
class PropertySub(property):
|
||||||
|
@ -309,46 +299,6 @@ class PropertySubclassTests(unittest.TestCase):
|
||||||
self.assertEqual(Foo.spam.__doc__, "a new docstring")
|
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__':
|
if __name__ == '__main__':
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|
|
@ -542,34 +542,6 @@ class SystemRandom_TestBasicOps(TestBasicOps, unittest.TestCase):
|
||||||
raises(0, 42, 0)
|
raises(0, 42, 0)
|
||||||
raises(0, 42, 3.14159)
|
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):
|
def test_randbelow_logic(self, _log=log, int=int):
|
||||||
# check bitcount transition points: 2**i and 2**(i+1)-1
|
# check bitcount transition points: 2**i and 2**(i+1)-1
|
||||||
# show that: k = int(1.001 + _log(n, 2))
|
# show that: k = int(1.001 + _log(n, 2))
|
||||||
|
|
|
@ -165,17 +165,6 @@ class LMTPGeneralTests(GeneralTests, unittest.TestCase):
|
||||||
|
|
||||||
client = smtplib.LMTP
|
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):
|
def testTimeoutZero(self):
|
||||||
super().testTimeoutZero()
|
super().testTimeoutZero()
|
||||||
local_host = '/some/local/lmtp/delivery/program'
|
local_host = '/some/local/lmtp/delivery/program'
|
||||||
|
|
|
@ -1121,11 +1121,9 @@ class GeneralModuleTests(unittest.TestCase):
|
||||||
s_good_values = [0, 1, 2, 0xffff]
|
s_good_values = [0, 1, 2, 0xffff]
|
||||||
l_good_values = s_good_values + [0xffffffff]
|
l_good_values = s_good_values + [0xffffffff]
|
||||||
l_bad_values = [-1, -2, 1<<32, 1<<1000]
|
l_bad_values = [-1, -2, 1<<32, 1<<1000]
|
||||||
s_bad_values = (
|
s_bad_values = l_bad_values + [_testcapi.INT_MIN - 1,
|
||||||
l_bad_values +
|
_testcapi.INT_MAX + 1]
|
||||||
[_testcapi.INT_MIN-1, _testcapi.INT_MAX+1] +
|
s_deprecated_values = [1<<16, _testcapi.INT_MAX]
|
||||||
[1 << 16, _testcapi.INT_MAX]
|
|
||||||
)
|
|
||||||
for k in s_good_values:
|
for k in s_good_values:
|
||||||
socket.ntohs(k)
|
socket.ntohs(k)
|
||||||
socket.htons(k)
|
socket.htons(k)
|
||||||
|
@ -1138,6 +1136,9 @@ class GeneralModuleTests(unittest.TestCase):
|
||||||
for k in l_bad_values:
|
for k in l_bad_values:
|
||||||
self.assertRaises(OverflowError, socket.ntohl, k)
|
self.assertRaises(OverflowError, socket.ntohl, k)
|
||||||
self.assertRaises(OverflowError, socket.htonl, 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):
|
def testGetServBy(self):
|
||||||
eq = self.assertEqual
|
eq = self.assertEqual
|
||||||
|
|
|
@ -277,13 +277,6 @@ class SocketServerTest(unittest.TestCase):
|
||||||
t.join()
|
t.join()
|
||||||
s.server_close()
|
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):
|
def test_tcpserver_bind_leak(self):
|
||||||
# Issue #22435: the server socket wouldn't be closed if bind()/listen()
|
# Issue #22435: the server socket wouldn't be closed if bind()/listen()
|
||||||
# failed.
|
# failed.
|
||||||
|
@ -498,22 +491,6 @@ class MiscTestCase(unittest.TestCase):
|
||||||
self.assertEqual(server.shutdown_called, 1)
|
self.assertEqual(server.shutdown_called, 1)
|
||||||
server.server_close()
|
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__":
|
if __name__ == "__main__":
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|
|
@ -204,28 +204,6 @@ class ProcessTestCase(BaseTestCase):
|
||||||
input=b'pear')
|
input=b'pear')
|
||||||
self.assertIn(b'PEAR', output)
|
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):
|
def test_check_output_stdout_arg(self):
|
||||||
# check_output() refuses to accept 'stdout' argument
|
# check_output() refuses to accept 'stdout' argument
|
||||||
with self.assertRaises(ValueError) as c:
|
with self.assertRaises(ValueError) as c:
|
||||||
|
|
|
@ -1329,7 +1329,7 @@ class SizeofTest(unittest.TestCase):
|
||||||
def setx(self, value): self.__x = value
|
def setx(self, value): self.__x = value
|
||||||
def delx(self): del self.__x
|
def delx(self): del self.__x
|
||||||
x = property(getx, setx, delx, "")
|
x = property(getx, setx, delx, "")
|
||||||
check(x, size('5Pi'))
|
check(x, size('4Pi'))
|
||||||
# PyCapsule
|
# PyCapsule
|
||||||
# XXX
|
# XXX
|
||||||
# rangeiterator
|
# rangeiterator
|
||||||
|
|
|
@ -874,48 +874,6 @@ class TraceTestCase(unittest.TestCase):
|
||||||
(5, 'line'),
|
(5, 'line'),
|
||||||
(5, 'return')])
|
(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):
|
class SkipLineEventsTraceTestCase(TraceTestCase):
|
||||||
"""Repeat the trace tests, but with per-line events skipped"""
|
"""Repeat the trace tests, but with per-line events skipped"""
|
||||||
|
|
|
@ -138,14 +138,10 @@ class TclTest(unittest.TestCase):
|
||||||
|
|
||||||
def get_integers(self):
|
def get_integers(self):
|
||||||
integers = (0, 1, -1, 2**31-1, -2**31, 2**31, -2**31-1, 2**63-1, -2**63)
|
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.
|
# 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()
|
if (get_tk_patchlevel() >= (8, 6, 0, 'final') or
|
||||||
# is not reliable.
|
(8, 5, 8) <= get_tk_patchlevel() < (8, 6)):
|
||||||
# TODO: expose full static version.
|
integers += (2**63, -2**63-1, 2**1000, -2**1000)
|
||||||
if tcl_version >= (8, 5):
|
|
||||||
v = get_tk_patchlevel()
|
|
||||||
if v >= (8, 6, 0, 'final') or (8, 5, 8) <= v < (8, 6):
|
|
||||||
integers += (2**63, -2**63-1, 2**1000, -2**1000)
|
|
||||||
return integers
|
return integers
|
||||||
|
|
||||||
def test_getint(self):
|
def test_getint(self):
|
||||||
|
@ -449,7 +445,7 @@ class TclTest(unittest.TestCase):
|
||||||
else:
|
else:
|
||||||
self.assertEqual(result, str(i))
|
self.assertEqual(result, str(i))
|
||||||
self.assertIsInstance(result, str)
|
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))
|
self.assertRaises(TclError, tcl.call, 'expr', str(2**1000))
|
||||||
|
|
||||||
def test_passing_values(self):
|
def test_passing_values(self):
|
||||||
|
|
|
@ -737,16 +737,6 @@ class TypesTests(unittest.TestCase):
|
||||||
with self.assertRaises(ZeroDivisionError):
|
with self.assertRaises(ZeroDivisionError):
|
||||||
list[int] | list[bt]
|
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):
|
def test_ellipsis_type(self):
|
||||||
self.assertIsInstance(Ellipsis, types.EllipsisType)
|
self.assertIsInstance(Ellipsis, types.EllipsisType)
|
||||||
|
|
||||||
|
|
|
@ -3021,7 +3021,6 @@ class GetUtilitiesTestCase(TestCase):
|
||||||
self.assertIs(get_origin(Callable), collections.abc.Callable)
|
self.assertIs(get_origin(Callable), collections.abc.Callable)
|
||||||
self.assertIs(get_origin(list[int]), list)
|
self.assertIs(get_origin(list[int]), list)
|
||||||
self.assertIs(get_origin(list), None)
|
self.assertIs(get_origin(list), None)
|
||||||
self.assertIs(get_origin(list | str), types.Union)
|
|
||||||
|
|
||||||
def test_get_args(self):
|
def test_get_args(self):
|
||||||
T = TypeVar('T')
|
T = TypeVar('T')
|
||||||
|
@ -3049,16 +3048,6 @@ class GetUtilitiesTestCase(TestCase):
|
||||||
self.assertEqual(get_args(Callable), ())
|
self.assertEqual(get_args(Callable), ())
|
||||||
self.assertEqual(get_args(list[int]), (int,))
|
self.assertEqual(get_args(list[int]), (int,))
|
||||||
self.assertEqual(get_args(list), ())
|
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):
|
class CollectionsAbcTests(BaseTestCase):
|
||||||
|
|
|
@ -346,31 +346,6 @@ Now some general starred expressions (all fail).
|
||||||
...
|
...
|
||||||
SyntaxError: can't use starred expression here
|
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.)
|
Some size constraints (all fail.)
|
||||||
|
|
||||||
>>> s = ", ".join("a%d" % i for i in range(1<<8)) + ", *rest = range(1<<8 + 1)"
|
>>> s = ", ".join("a%d" % i for i in range(1<<8)) + ", *rest = range(1<<8 + 1)"
|
||||||
|
|
|
@ -1851,17 +1851,9 @@ class MiscTests(unittest.TestCase):
|
||||||
('ftp', 'joe', 'password', 'proxy.example.com')),
|
('ftp', 'joe', 'password', 'proxy.example.com')),
|
||||||
# Test for no trailing '/' case
|
# Test for no trailing '/' case
|
||||||
('http://joe:password@proxy.example.com',
|
('http://joe:password@proxy.example.com',
|
||||||
('http', 'joe', 'password', 'proxy.example.com')),
|
('http', 'joe', 'password', 'proxy.example.com'))
|
||||||
# Testcases with '/' character in username, password
|
|
||||||
('http://user/name:password@localhost:22',
|
|
||||||
('http', 'user/name', 'password', 'localhost:22')),
|
|
||||||
('http://username:pass/word@localhost:22',
|
|
||||||
('http', 'username', 'pass/word', 'localhost:22')),
|
|
||||||
('http://user/name:pass/word@localhost:22',
|
|
||||||
('http', 'user/name', 'pass/word', 'localhost:22')),
|
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
for tc, expected in parse_proxy_test_cases:
|
for tc, expected in parse_proxy_test_cases:
|
||||||
self.assertEqual(_parse_proxy(tc), expected)
|
self.assertEqual(_parse_proxy(tc), expected)
|
||||||
|
|
||||||
|
|
|
@ -292,7 +292,7 @@ def _get_default_root(what=None):
|
||||||
if not _support_default_root:
|
if not _support_default_root:
|
||||||
raise RuntimeError("No master specified and tkinter is "
|
raise RuntimeError("No master specified and tkinter is "
|
||||||
"configured to not support default root")
|
"configured to not support default root")
|
||||||
if _default_root is None:
|
if not _default_root:
|
||||||
if what:
|
if what:
|
||||||
raise RuntimeError(f"Too early to {what}: no default root window")
|
raise RuntimeError(f"Too early to {what}: no default root window")
|
||||||
root = Tk()
|
root = Tk()
|
||||||
|
@ -300,31 +300,6 @@ def _get_default_root(what=None):
|
||||||
return _default_root
|
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):
|
def _tkerror(err):
|
||||||
"""Internal function."""
|
"""Internal function."""
|
||||||
pass
|
pass
|
||||||
|
@ -367,7 +342,7 @@ class Variable:
|
||||||
if name is not None and not isinstance(name, str):
|
if name is not None and not isinstance(name, str):
|
||||||
raise TypeError("name must be a string")
|
raise TypeError("name must be a string")
|
||||||
global _varnum
|
global _varnum
|
||||||
if master is None:
|
if not master:
|
||||||
master = _get_default_root('create variable')
|
master = _get_default_root('create variable')
|
||||||
self._root = master._root()
|
self._root = master._root()
|
||||||
self._tk = master.tk
|
self._tk = master.tk
|
||||||
|
@ -516,11 +491,15 @@ class Variable:
|
||||||
self._tk.call("trace", "vinfo", self._name))]
|
self._tk.call("trace", "vinfo", self._name))]
|
||||||
|
|
||||||
def __eq__(self, other):
|
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):
|
if not isinstance(other, Variable):
|
||||||
return NotImplemented
|
return NotImplemented
|
||||||
return (self._name == other._name
|
return self.__class__.__name__ == other.__class__.__name__ \
|
||||||
and self.__class__.__name__ == other.__class__.__name__
|
and self._name == other._name
|
||||||
and self._tk == other._tk)
|
|
||||||
|
|
||||||
|
|
||||||
class StringVar(Variable):
|
class StringVar(Variable):
|
||||||
|
@ -829,7 +808,7 @@ class Misc:
|
||||||
function which shall be called. Additional parameters
|
function which shall be called. Additional parameters
|
||||||
are given as parameters to the function call. Return
|
are given as parameters to the function call. Return
|
||||||
identifier to cancel scheduling with after_cancel."""
|
identifier to cancel scheduling with after_cancel."""
|
||||||
if func is None:
|
if not func:
|
||||||
# I'd rather use time.sleep(ms*0.001)
|
# I'd rather use time.sleep(ms*0.001)
|
||||||
self.tk.call('after', ms)
|
self.tk.call('after', ms)
|
||||||
return None
|
return None
|
||||||
|
@ -1563,7 +1542,7 @@ class Misc:
|
||||||
def _root(self):
|
def _root(self):
|
||||||
"""Internal function."""
|
"""Internal function."""
|
||||||
w = self
|
w = self
|
||||||
while w.master is not None: w = w.master
|
while w.master: w = w.master
|
||||||
return w
|
return w
|
||||||
_subst_format = ('%#', '%b', '%f', '%h', '%k',
|
_subst_format = ('%#', '%b', '%f', '%h', '%k',
|
||||||
'%s', '%t', '%w', '%x', '%y',
|
'%s', '%t', '%w', '%x', '%y',
|
||||||
|
@ -2327,7 +2306,7 @@ class Tk(Misc, Wm):
|
||||||
self.tk.createcommand('exit', _exit)
|
self.tk.createcommand('exit', _exit)
|
||||||
self._tclCommands.append('tkerror')
|
self._tclCommands.append('tkerror')
|
||||||
self._tclCommands.append('exit')
|
self._tclCommands.append('exit')
|
||||||
if _support_default_root and _default_root is None:
|
if _support_default_root and not _default_root:
|
||||||
_default_root = self
|
_default_root = self
|
||||||
self.protocol("WM_DELETE_WINDOW", self.destroy)
|
self.protocol("WM_DELETE_WINDOW", self.destroy)
|
||||||
|
|
||||||
|
@ -2555,7 +2534,7 @@ class BaseWidget(Misc):
|
||||||
|
|
||||||
def _setup(self, master, cnf):
|
def _setup(self, master, cnf):
|
||||||
"""Internal function. Sets up information about children."""
|
"""Internal function. Sets up information about children."""
|
||||||
if master is None:
|
if not master:
|
||||||
master = _get_default_root()
|
master = _get_default_root()
|
||||||
self.master = master
|
self.master = master
|
||||||
self.tk = master.tk
|
self.tk = master.tk
|
||||||
|
@ -3970,7 +3949,7 @@ class _setit:
|
||||||
|
|
||||||
def __call__(self, *args):
|
def __call__(self, *args):
|
||||||
self.__var.set(self.__value)
|
self.__var.set(self.__value)
|
||||||
if self.__callback is not None:
|
if self.__callback:
|
||||||
self.__callback(self.__value, *args)
|
self.__callback(self.__value, *args)
|
||||||
|
|
||||||
|
|
||||||
|
@ -4019,7 +3998,7 @@ class Image:
|
||||||
|
|
||||||
def __init__(self, imgtype, name=None, cnf={}, master=None, **kw):
|
def __init__(self, imgtype, name=None, cnf={}, master=None, **kw):
|
||||||
self.name = None
|
self.name = None
|
||||||
if master is None:
|
if not master:
|
||||||
master = _get_default_root('create image')
|
master = _get_default_root('create image')
|
||||||
self.tk = getattr(master, 'tk', master)
|
self.tk = getattr(master, 'tk', master)
|
||||||
if not name:
|
if not name:
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
|
|
||||||
__all__ = ["Dialog"]
|
__all__ = ["Dialog"]
|
||||||
|
|
||||||
from tkinter import Frame, _get_temp_root, _destroy_temp_root
|
from tkinter import Frame
|
||||||
|
|
||||||
|
|
||||||
class Dialog:
|
class Dialog:
|
||||||
|
@ -18,7 +18,7 @@ class Dialog:
|
||||||
command = None
|
command = None
|
||||||
|
|
||||||
def __init__(self, master=None, **options):
|
def __init__(self, master=None, **options):
|
||||||
if master is None:
|
if not master:
|
||||||
master = options.get('parent')
|
master = options.get('parent')
|
||||||
self.master = master
|
self.master = master
|
||||||
self.options = options
|
self.options = options
|
||||||
|
@ -37,17 +37,22 @@ class Dialog:
|
||||||
|
|
||||||
self._fixoptions()
|
self._fixoptions()
|
||||||
|
|
||||||
master = self.master
|
# we need a dummy widget to properly process the options
|
||||||
if master is None:
|
# (at least as long as we use Tkinter 1.63)
|
||||||
master = _get_temp_root()
|
w = Frame(self.master)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self._test_callback(master) # The function below is replaced for some tests.
|
|
||||||
s = master.tk.call(self.command, *master._options(self.options))
|
s = w.tk.call(self.command, *w._options(self.options))
|
||||||
s = self._fixresult(master, s)
|
|
||||||
|
s = self._fixresult(w, s)
|
||||||
|
|
||||||
finally:
|
finally:
|
||||||
_destroy_temp_root(master)
|
|
||||||
|
try:
|
||||||
|
# get rid of the widget
|
||||||
|
w.destroy()
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
return s
|
return s
|
||||||
|
|
||||||
def _test_callback(self, master):
|
|
||||||
pass
|
|
||||||
|
|
|
@ -108,7 +108,7 @@ __all__ = ["dnd_start", "DndHandler"]
|
||||||
|
|
||||||
def dnd_start(source, event):
|
def dnd_start(source, event):
|
||||||
h = DndHandler(source, event)
|
h = DndHandler(source, event)
|
||||||
if h.root is not None:
|
if h.root:
|
||||||
return h
|
return h
|
||||||
else:
|
else:
|
||||||
return None
|
return None
|
||||||
|
@ -143,7 +143,7 @@ class DndHandler:
|
||||||
def __del__(self):
|
def __del__(self):
|
||||||
root = self.root
|
root = self.root
|
||||||
self.root = None
|
self.root = None
|
||||||
if root is not None:
|
if root:
|
||||||
try:
|
try:
|
||||||
del root.__dnd
|
del root.__dnd
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
|
@ -154,25 +154,25 @@ class DndHandler:
|
||||||
target_widget = self.initial_widget.winfo_containing(x, y)
|
target_widget = self.initial_widget.winfo_containing(x, y)
|
||||||
source = self.source
|
source = self.source
|
||||||
new_target = None
|
new_target = None
|
||||||
while target_widget is not None:
|
while target_widget:
|
||||||
try:
|
try:
|
||||||
attr = target_widget.dnd_accept
|
attr = target_widget.dnd_accept
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
new_target = attr(source, event)
|
new_target = attr(source, event)
|
||||||
if new_target is not None:
|
if new_target:
|
||||||
break
|
break
|
||||||
target_widget = target_widget.master
|
target_widget = target_widget.master
|
||||||
old_target = self.target
|
old_target = self.target
|
||||||
if old_target is new_target:
|
if old_target is new_target:
|
||||||
if old_target is not None:
|
if old_target:
|
||||||
old_target.dnd_motion(source, event)
|
old_target.dnd_motion(source, event)
|
||||||
else:
|
else:
|
||||||
if old_target is not None:
|
if old_target:
|
||||||
self.target = None
|
self.target = None
|
||||||
old_target.dnd_leave(source, event)
|
old_target.dnd_leave(source, event)
|
||||||
if new_target is not None:
|
if new_target:
|
||||||
new_target.dnd_enter(source, event)
|
new_target.dnd_enter(source, event)
|
||||||
self.target = new_target
|
self.target = new_target
|
||||||
|
|
||||||
|
@ -193,7 +193,7 @@ class DndHandler:
|
||||||
self.initial_widget.unbind("<Motion>")
|
self.initial_widget.unbind("<Motion>")
|
||||||
widget['cursor'] = self.save_cursor
|
widget['cursor'] = self.save_cursor
|
||||||
self.target = self.source = self.initial_widget = self.root = None
|
self.target = self.source = self.initial_widget = self.root = None
|
||||||
if target is not None:
|
if target:
|
||||||
if commit:
|
if commit:
|
||||||
target.dnd_commit(source, event)
|
target.dnd_commit(source, event)
|
||||||
else:
|
else:
|
||||||
|
@ -215,9 +215,9 @@ class Icon:
|
||||||
if canvas is self.canvas:
|
if canvas is self.canvas:
|
||||||
self.canvas.coords(self.id, x, y)
|
self.canvas.coords(self.id, x, y)
|
||||||
return
|
return
|
||||||
if self.canvas is not None:
|
if self.canvas:
|
||||||
self.detach()
|
self.detach()
|
||||||
if canvas is None:
|
if not canvas:
|
||||||
return
|
return
|
||||||
label = tkinter.Label(canvas, text=self.name,
|
label = tkinter.Label(canvas, text=self.name,
|
||||||
borderwidth=2, relief="raised")
|
borderwidth=2, relief="raised")
|
||||||
|
@ -229,7 +229,7 @@ class Icon:
|
||||||
|
|
||||||
def detach(self):
|
def detach(self):
|
||||||
canvas = self.canvas
|
canvas = self.canvas
|
||||||
if canvas is None:
|
if not canvas:
|
||||||
return
|
return
|
||||||
id = self.id
|
id = self.id
|
||||||
label = self.label
|
label = self.label
|
||||||
|
|
|
@ -17,10 +17,10 @@ BOLD = "bold"
|
||||||
ITALIC = "italic"
|
ITALIC = "italic"
|
||||||
|
|
||||||
|
|
||||||
def nametofont(name, root=None):
|
def nametofont(name):
|
||||||
"""Given the name of a tk named font, returns a Font representation.
|
"""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:
|
class Font:
|
||||||
|
@ -68,7 +68,7 @@ class Font:
|
||||||
|
|
||||||
def __init__(self, root=None, font=None, name=None, exists=False,
|
def __init__(self, root=None, font=None, name=None, exists=False,
|
||||||
**options):
|
**options):
|
||||||
if root is None:
|
if not root:
|
||||||
root = tkinter._get_default_root('use font')
|
root = tkinter._get_default_root('use font')
|
||||||
tk = getattr(root, 'tk', root)
|
tk = getattr(root, 'tk', root)
|
||||||
if font:
|
if font:
|
||||||
|
@ -107,7 +107,7 @@ class Font:
|
||||||
def __eq__(self, other):
|
def __eq__(self, other):
|
||||||
if not isinstance(other, Font):
|
if not isinstance(other, Font):
|
||||||
return NotImplemented
|
return NotImplemented
|
||||||
return self.name == other.name and self._tk == other._tk
|
return self.name == other.name
|
||||||
|
|
||||||
def __getitem__(self, key):
|
def __getitem__(self, key):
|
||||||
return self.cget(key)
|
return self.cget(key)
|
||||||
|
@ -183,7 +183,7 @@ class Font:
|
||||||
|
|
||||||
def families(root=None, displayof=None):
|
def families(root=None, displayof=None):
|
||||||
"Get font families (as a tuple)"
|
"Get font families (as a tuple)"
|
||||||
if root is None:
|
if not root:
|
||||||
root = tkinter._get_default_root('use font.families()')
|
root = tkinter._get_default_root('use font.families()')
|
||||||
args = ()
|
args = ()
|
||||||
if displayof:
|
if displayof:
|
||||||
|
@ -193,7 +193,7 @@ def families(root=None, displayof=None):
|
||||||
|
|
||||||
def names(root=None):
|
def names(root=None):
|
||||||
"Get names of defined fonts (as a tuple)"
|
"Get names of defined fonts (as a tuple)"
|
||||||
if root is None:
|
if not root:
|
||||||
root = tkinter._get_default_root('use font.names()')
|
root = tkinter._get_default_root('use font.names()')
|
||||||
return root.tk.splitlist(root.tk.call("font", "names"))
|
return root.tk.splitlist(root.tk.call("font", "names"))
|
||||||
|
|
||||||
|
|
|
@ -24,8 +24,7 @@ askstring -- get a string from the user
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from tkinter import *
|
from tkinter import *
|
||||||
from tkinter import _get_temp_root, _destroy_temp_root
|
from tkinter import messagebox, _get_default_root
|
||||||
from tkinter import messagebox
|
|
||||||
|
|
||||||
|
|
||||||
class SimpleDialog:
|
class SimpleDialog:
|
||||||
|
@ -56,8 +55,36 @@ class SimpleDialog:
|
||||||
b.config(relief=RIDGE, borderwidth=8)
|
b.config(relief=RIDGE, borderwidth=8)
|
||||||
b.pack(side=LEFT, fill=BOTH, expand=1)
|
b.pack(side=LEFT, fill=BOTH, expand=1)
|
||||||
self.root.protocol('WM_DELETE_WINDOW', self.wm_delete_window)
|
self.root.protocol('WM_DELETE_WINDOW', self.wm_delete_window)
|
||||||
self.root.transient(master)
|
self._set_transient(master)
|
||||||
_place_window(self.root, 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):
|
def go(self):
|
||||||
self.root.wait_visibility()
|
self.root.wait_visibility()
|
||||||
|
@ -100,8 +127,8 @@ class Dialog(Toplevel):
|
||||||
title -- the dialog title
|
title -- the dialog title
|
||||||
'''
|
'''
|
||||||
master = parent
|
master = parent
|
||||||
if master is None:
|
if not master:
|
||||||
master = _get_temp_root()
|
master = _get_default_root('create dialog window')
|
||||||
|
|
||||||
Toplevel.__init__(self, master)
|
Toplevel.__init__(self, master)
|
||||||
|
|
||||||
|
@ -125,12 +152,16 @@ class Dialog(Toplevel):
|
||||||
|
|
||||||
self.buttonbox()
|
self.buttonbox()
|
||||||
|
|
||||||
if self.initial_focus is None:
|
if not self.initial_focus:
|
||||||
self.initial_focus = self
|
self.initial_focus = self
|
||||||
|
|
||||||
self.protocol("WM_DELETE_WINDOW", self.cancel)
|
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()
|
self.initial_focus.focus_set()
|
||||||
|
|
||||||
|
@ -143,7 +174,6 @@ class Dialog(Toplevel):
|
||||||
'''Destroy the window'''
|
'''Destroy the window'''
|
||||||
self.initial_focus = None
|
self.initial_focus = None
|
||||||
Toplevel.destroy(self)
|
Toplevel.destroy(self)
|
||||||
_destroy_temp_root(self.master)
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# construction hooks
|
# construction hooks
|
||||||
|
@ -221,37 +251,6 @@ class Dialog(Toplevel):
|
||||||
pass # override
|
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
|
# convenience dialogues
|
||||||
|
|
||||||
|
|
|
@ -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)
|
|
|
@ -63,22 +63,15 @@ class FontTest(AbstractTkTest, unittest.TestCase):
|
||||||
self.assertEqual(self.font.name, fontname)
|
self.assertEqual(self.font.name, fontname)
|
||||||
self.assertEqual(str(self.font), 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)
|
font1 = font.Font(root=self.root, name=fontname, exists=True)
|
||||||
font2 = font.Font(root=self.root, name=fontname, exists=True)
|
font2 = font.Font(root=self.root, name=fontname, exists=True)
|
||||||
self.assertIsNot(font1, font2)
|
self.assertIsNot(font1, font2)
|
||||||
self.assertEqual(font1, font2)
|
self.assertEqual(font1, font2)
|
||||||
self.assertNotEqual(font1, font1.copy())
|
self.assertNotEqual(font1, font1.copy())
|
||||||
|
|
||||||
self.assertNotEqual(font1, 0)
|
self.assertNotEqual(font1, 0)
|
||||||
self.assertEqual(font1, ALWAYS_EQ)
|
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):
|
def test_measure(self):
|
||||||
self.assertIsInstance(self.font.measure('abc'), int)
|
self.assertIsInstance(self.font.measure('abc'), int)
|
||||||
|
|
||||||
|
@ -108,11 +101,6 @@ class FontTest(AbstractTkTest, unittest.TestCase):
|
||||||
self.assertTrue(name)
|
self.assertTrue(name)
|
||||||
self.assertIn(fontname, names)
|
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):
|
def test_repr(self):
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
repr(self.font), f'<tkinter.font.Font object {fontname!r}>'
|
repr(self.font), f'<tkinter.font.Font object {fontname!r}>'
|
||||||
|
@ -148,16 +136,6 @@ class DefaultRootTest(AbstractDefaultRootTest, unittest.TestCase):
|
||||||
tkinter.NoDefaultRoot()
|
tkinter.NoDefaultRoot()
|
||||||
self.assertRaises(RuntimeError, font.names)
|
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)
|
tests_gui = (FontTest, DefaultRootTest)
|
||||||
|
|
||||||
|
|
|
@ -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)
|
|
|
@ -10,25 +10,13 @@ requires('gui')
|
||||||
class DefaultRootTest(AbstractDefaultRootTest, unittest.TestCase):
|
class DefaultRootTest(AbstractDefaultRootTest, unittest.TestCase):
|
||||||
|
|
||||||
def test_askinteger(self):
|
def test_askinteger(self):
|
||||||
@staticmethod
|
self.assertRaises(RuntimeError, askinteger, "Go To Line", "Line number")
|
||||||
def mock_wait_window(w):
|
root = tkinter.Tk()
|
||||||
nonlocal ismapped
|
with swap_attr(Dialog, 'wait_window', lambda self, w: w.destroy()):
|
||||||
ismapped = w.master.winfo_ismapped()
|
|
||||||
w.destroy()
|
|
||||||
|
|
||||||
with swap_attr(Dialog, 'wait_window', mock_wait_window):
|
|
||||||
ismapped = None
|
|
||||||
askinteger("Go To Line", "Line number")
|
askinteger("Go To Line", "Line number")
|
||||||
self.assertEqual(ismapped, False)
|
root.destroy()
|
||||||
|
tkinter.NoDefaultRoot()
|
||||||
root = tkinter.Tk()
|
self.assertRaises(RuntimeError, askinteger, "Go To Line", "Line number")
|
||||||
ismapped = None
|
|
||||||
askinteger("Go To Line", "Line number")
|
|
||||||
self.assertEqual(ismapped, True)
|
|
||||||
root.destroy()
|
|
||||||
|
|
||||||
tkinter.NoDefaultRoot()
|
|
||||||
self.assertRaises(RuntimeError, askinteger, "Go To Line", "Line number")
|
|
||||||
|
|
||||||
|
|
||||||
tests_gui = (DefaultRootTest,)
|
tests_gui = (DefaultRootTest,)
|
||||||
|
|
|
@ -58,32 +58,22 @@ class TestVariable(TestBase):
|
||||||
del v2
|
del v2
|
||||||
self.assertFalse(self.info_exists("name"))
|
self.assertFalse(self.info_exists("name"))
|
||||||
|
|
||||||
def test_equality(self):
|
def test___eq__(self):
|
||||||
# values doesn't matter, only class and name are checked
|
# values doesn't matter, only class and name are checked
|
||||||
v1 = Variable(self.root, name="abc")
|
v1 = Variable(self.root, name="abc")
|
||||||
v2 = Variable(self.root, name="abc")
|
v2 = Variable(self.root, name="abc")
|
||||||
self.assertIsNot(v1, v2)
|
self.assertIsNot(v1, v2)
|
||||||
self.assertEqual(v1, v2)
|
self.assertEqual(v1, v2)
|
||||||
|
|
||||||
v3 = Variable(self.root, name="cba")
|
v3 = StringVar(self.root, name="abc")
|
||||||
self.assertNotEqual(v1, v3)
|
self.assertNotEqual(v1, v3)
|
||||||
|
|
||||||
v4 = StringVar(self.root, name="abc")
|
|
||||||
self.assertEqual(str(v1), str(v4))
|
|
||||||
self.assertNotEqual(v1, v4)
|
|
||||||
|
|
||||||
V = type('Variable', (), {})
|
V = type('Variable', (), {})
|
||||||
self.assertNotEqual(v1, V())
|
self.assertNotEqual(v1, V())
|
||||||
|
|
||||||
self.assertNotEqual(v1, object())
|
self.assertNotEqual(v1, object())
|
||||||
self.assertEqual(v1, ALWAYS_EQ)
|
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):
|
def test_invalid_name(self):
|
||||||
with self.assertRaises(TypeError):
|
with self.assertRaises(TypeError):
|
||||||
Variable(self.root, name=123)
|
Variable(self.root, name=123)
|
||||||
|
|
|
@ -22,7 +22,7 @@ def float_round(x):
|
||||||
class AbstractToplevelTest(AbstractWidgetTest, PixelSizeTests):
|
class AbstractToplevelTest(AbstractWidgetTest, PixelSizeTests):
|
||||||
_conv_pad_pixels = noconv
|
_conv_pad_pixels = noconv
|
||||||
|
|
||||||
def test_configure_class(self):
|
def test_class(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.assertEqual(widget['class'],
|
self.assertEqual(widget['class'],
|
||||||
widget.__class__.__name__.title())
|
widget.__class__.__name__.title())
|
||||||
|
@ -31,7 +31,7 @@ class AbstractToplevelTest(AbstractWidgetTest, PixelSizeTests):
|
||||||
widget2 = self.create(class_='Foo')
|
widget2 = self.create(class_='Foo')
|
||||||
self.assertEqual(widget2['class'], 'Foo')
|
self.assertEqual(widget2['class'], 'Foo')
|
||||||
|
|
||||||
def test_configure_colormap(self):
|
def test_colormap(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.assertEqual(widget['colormap'], '')
|
self.assertEqual(widget['colormap'], '')
|
||||||
self.checkInvalidParam(widget, 'colormap', 'new',
|
self.checkInvalidParam(widget, 'colormap', 'new',
|
||||||
|
@ -39,7 +39,7 @@ class AbstractToplevelTest(AbstractWidgetTest, PixelSizeTests):
|
||||||
widget2 = self.create(colormap='new')
|
widget2 = self.create(colormap='new')
|
||||||
self.assertEqual(widget2['colormap'], 'new')
|
self.assertEqual(widget2['colormap'], 'new')
|
||||||
|
|
||||||
def test_configure_container(self):
|
def test_container(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.assertEqual(widget['container'], 0 if self.wantobjects else '0')
|
self.assertEqual(widget['container'], 0 if self.wantobjects else '0')
|
||||||
self.checkInvalidParam(widget, 'container', 1,
|
self.checkInvalidParam(widget, 'container', 1,
|
||||||
|
@ -47,7 +47,7 @@ class AbstractToplevelTest(AbstractWidgetTest, PixelSizeTests):
|
||||||
widget2 = self.create(container=True)
|
widget2 = self.create(container=True)
|
||||||
self.assertEqual(widget2['container'], 1 if self.wantobjects else '1')
|
self.assertEqual(widget2['container'], 1 if self.wantobjects else '1')
|
||||||
|
|
||||||
def test_configure_visual(self):
|
def test_visual(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.assertEqual(widget['visual'], '')
|
self.assertEqual(widget['visual'], '')
|
||||||
self.checkInvalidParam(widget, 'visual', 'default',
|
self.checkInvalidParam(widget, 'visual', 'default',
|
||||||
|
@ -69,13 +69,13 @@ class ToplevelTest(AbstractToplevelTest, unittest.TestCase):
|
||||||
def create(self, **kwargs):
|
def create(self, **kwargs):
|
||||||
return tkinter.Toplevel(self.root, **kwargs)
|
return tkinter.Toplevel(self.root, **kwargs)
|
||||||
|
|
||||||
def test_configure_menu(self):
|
def test_menu(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
menu = tkinter.Menu(self.root)
|
menu = tkinter.Menu(self.root)
|
||||||
self.checkParam(widget, 'menu', menu, eq=widget_eq)
|
self.checkParam(widget, 'menu', menu, eq=widget_eq)
|
||||||
self.checkParam(widget, 'menu', '')
|
self.checkParam(widget, 'menu', '')
|
||||||
|
|
||||||
def test_configure_screen(self):
|
def test_screen(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.assertEqual(widget['screen'], '')
|
self.assertEqual(widget['screen'], '')
|
||||||
try:
|
try:
|
||||||
|
@ -87,7 +87,7 @@ class ToplevelTest(AbstractToplevelTest, unittest.TestCase):
|
||||||
widget2 = self.create(screen=display)
|
widget2 = self.create(screen=display)
|
||||||
self.assertEqual(widget2['screen'], display)
|
self.assertEqual(widget2['screen'], display)
|
||||||
|
|
||||||
def test_configure_use(self):
|
def test_use(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.assertEqual(widget['use'], '')
|
self.assertEqual(widget['use'], '')
|
||||||
parent = self.create(container=True)
|
parent = self.create(container=True)
|
||||||
|
@ -124,14 +124,14 @@ class LabelFrameTest(AbstractToplevelTest, unittest.TestCase):
|
||||||
def create(self, **kwargs):
|
def create(self, **kwargs):
|
||||||
return tkinter.LabelFrame(self.root, **kwargs)
|
return tkinter.LabelFrame(self.root, **kwargs)
|
||||||
|
|
||||||
def test_configure_labelanchor(self):
|
def test_labelanchor(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkEnumParam(widget, 'labelanchor',
|
self.checkEnumParam(widget, 'labelanchor',
|
||||||
'e', 'en', 'es', 'n', 'ne', 'nw',
|
'e', 'en', 'es', 'n', 'ne', 'nw',
|
||||||
's', 'se', 'sw', 'w', 'wn', 'ws')
|
's', 'se', 'sw', 'w', 'wn', 'ws')
|
||||||
self.checkInvalidParam(widget, 'labelanchor', 'center')
|
self.checkInvalidParam(widget, 'labelanchor', 'center')
|
||||||
|
|
||||||
def test_configure_labelwidget(self):
|
def test_labelwidget(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
label = tkinter.Label(self.root, text='Mupp', name='foo')
|
label = tkinter.Label(self.root, text='Mupp', name='foo')
|
||||||
self.checkParam(widget, 'labelwidget', label, expected='.foo')
|
self.checkParam(widget, 'labelwidget', label, expected='.foo')
|
||||||
|
@ -141,7 +141,7 @@ class LabelFrameTest(AbstractToplevelTest, unittest.TestCase):
|
||||||
class AbstractLabelTest(AbstractWidgetTest, IntegerSizeTests):
|
class AbstractLabelTest(AbstractWidgetTest, IntegerSizeTests):
|
||||||
_conv_pixels = noconv
|
_conv_pixels = noconv
|
||||||
|
|
||||||
def test_configure_highlightthickness(self):
|
def test_highlightthickness(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkPixelsParam(widget, 'highlightthickness',
|
self.checkPixelsParam(widget, 'highlightthickness',
|
||||||
0, 1.3, 2.6, 6, -2, '10p')
|
0, 1.3, 2.6, 6, -2, '10p')
|
||||||
|
@ -179,7 +179,7 @@ class ButtonTest(AbstractLabelTest, unittest.TestCase):
|
||||||
def create(self, **kwargs):
|
def create(self, **kwargs):
|
||||||
return tkinter.Button(self.root, **kwargs)
|
return tkinter.Button(self.root, **kwargs)
|
||||||
|
|
||||||
def test_configure_default(self):
|
def test_default(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkEnumParam(widget, 'default', 'active', 'disabled', 'normal')
|
self.checkEnumParam(widget, 'default', 'active', 'disabled', 'normal')
|
||||||
|
|
||||||
|
@ -204,11 +204,11 @@ class CheckbuttonTest(AbstractLabelTest, unittest.TestCase):
|
||||||
return tkinter.Checkbutton(self.root, **kwargs)
|
return tkinter.Checkbutton(self.root, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
def test_configure_offvalue(self):
|
def test_offvalue(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkParams(widget, 'offvalue', 1, 2.3, '', 'any string')
|
self.checkParams(widget, 'offvalue', 1, 2.3, '', 'any string')
|
||||||
|
|
||||||
def test_configure_onvalue(self):
|
def test_onvalue(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkParams(widget, 'onvalue', 1, 2.3, '', 'any string')
|
self.checkParams(widget, 'onvalue', 1, 2.3, '', 'any string')
|
||||||
|
|
||||||
|
@ -231,7 +231,7 @@ class RadiobuttonTest(AbstractLabelTest, unittest.TestCase):
|
||||||
def create(self, **kwargs):
|
def create(self, **kwargs):
|
||||||
return tkinter.Radiobutton(self.root, **kwargs)
|
return tkinter.Radiobutton(self.root, **kwargs)
|
||||||
|
|
||||||
def test_configure_value(self):
|
def test_value(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkParams(widget, 'value', 1, 2.3, '', 'any string')
|
self.checkParams(widget, 'value', 1, 2.3, '', 'any string')
|
||||||
|
|
||||||
|
@ -254,19 +254,18 @@ class MenubuttonTest(AbstractLabelTest, unittest.TestCase):
|
||||||
def create(self, **kwargs):
|
def create(self, **kwargs):
|
||||||
return tkinter.Menubutton(self.root, **kwargs)
|
return tkinter.Menubutton(self.root, **kwargs)
|
||||||
|
|
||||||
def test_configure_direction(self):
|
def test_direction(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkEnumParam(widget, 'direction',
|
self.checkEnumParam(widget, 'direction',
|
||||||
'above', 'below', 'flush', 'left', 'right')
|
'above', 'below', 'flush', 'left', 'right')
|
||||||
|
|
||||||
def test_configure_height(self):
|
def test_height(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkIntegerParam(widget, 'height', 100, -100, 0, conv=str)
|
self.checkIntegerParam(widget, 'height', 100, -100, 0, conv=str)
|
||||||
|
|
||||||
test_configure_highlightthickness = \
|
test_highlightthickness = StandardOptionsTests.test_highlightthickness
|
||||||
StandardOptionsTests.test_configure_highlightthickness
|
|
||||||
|
|
||||||
def test_configure_image(self):
|
def test_image(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
image = tkinter.PhotoImage(master=self.root, name='image1')
|
image = tkinter.PhotoImage(master=self.root, name='image1')
|
||||||
self.checkParam(widget, 'image', image, conv=str)
|
self.checkParam(widget, 'image', image, conv=str)
|
||||||
|
@ -280,23 +279,23 @@ class MenubuttonTest(AbstractLabelTest, unittest.TestCase):
|
||||||
if errmsg is not None:
|
if errmsg is not None:
|
||||||
self.assertEqual(str(cm.exception), errmsg)
|
self.assertEqual(str(cm.exception), errmsg)
|
||||||
|
|
||||||
def test_configure_menu(self):
|
def test_menu(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
menu = tkinter.Menu(widget, name='menu')
|
menu = tkinter.Menu(widget, name='menu')
|
||||||
self.checkParam(widget, 'menu', menu, eq=widget_eq)
|
self.checkParam(widget, 'menu', menu, eq=widget_eq)
|
||||||
menu.destroy()
|
menu.destroy()
|
||||||
|
|
||||||
def test_configure_padx(self):
|
def test_padx(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkPixelsParam(widget, 'padx', 3, 4.4, 5.6, '12m')
|
self.checkPixelsParam(widget, 'padx', 3, 4.4, 5.6, '12m')
|
||||||
self.checkParam(widget, 'padx', -2, expected=0)
|
self.checkParam(widget, 'padx', -2, expected=0)
|
||||||
|
|
||||||
def test_configure_pady(self):
|
def test_pady(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkPixelsParam(widget, 'pady', 3, 4.4, 5.6, '12m')
|
self.checkPixelsParam(widget, 'pady', 3, 4.4, 5.6, '12m')
|
||||||
self.checkParam(widget, 'pady', -2, expected=0)
|
self.checkParam(widget, 'pady', -2, expected=0)
|
||||||
|
|
||||||
def test_configure_width(self):
|
def test_width(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkIntegerParam(widget, 'width', 402, -402, 0, conv=str)
|
self.checkIntegerParam(widget, 'width', 402, -402, 0, conv=str)
|
||||||
|
|
||||||
|
@ -329,18 +328,18 @@ class EntryTest(AbstractWidgetTest, unittest.TestCase):
|
||||||
def create(self, **kwargs):
|
def create(self, **kwargs):
|
||||||
return tkinter.Entry(self.root, **kwargs)
|
return tkinter.Entry(self.root, **kwargs)
|
||||||
|
|
||||||
def test_configure_disabledbackground(self):
|
def test_disabledbackground(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkColorParam(widget, 'disabledbackground')
|
self.checkColorParam(widget, 'disabledbackground')
|
||||||
|
|
||||||
def test_configure_insertborderwidth(self):
|
def test_insertborderwidth(self):
|
||||||
widget = self.create(insertwidth=100)
|
widget = self.create(insertwidth=100)
|
||||||
self.checkPixelsParam(widget, 'insertborderwidth',
|
self.checkPixelsParam(widget, 'insertborderwidth',
|
||||||
0, 1.3, 2.6, 6, -2, '10p')
|
0, 1.3, 2.6, 6, -2, '10p')
|
||||||
# insertborderwidth is bounded above by a half of insertwidth.
|
# insertborderwidth is bounded above by a half of insertwidth.
|
||||||
self.checkParam(widget, 'insertborderwidth', 60, expected=100//2)
|
self.checkParam(widget, 'insertborderwidth', 60, expected=100//2)
|
||||||
|
|
||||||
def test_configure_insertwidth(self):
|
def test_insertwidth(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkPixelsParam(widget, 'insertwidth', 1.3, 3.6, '10p')
|
self.checkPixelsParam(widget, 'insertwidth', 1.3, 3.6, '10p')
|
||||||
self.checkParam(widget, 'insertwidth', 0.1, expected=2)
|
self.checkParam(widget, 'insertwidth', 0.1, expected=2)
|
||||||
|
@ -350,32 +349,32 @@ class EntryTest(AbstractWidgetTest, unittest.TestCase):
|
||||||
else:
|
else:
|
||||||
self.checkParam(widget, 'insertwidth', 0.9, expected=1)
|
self.checkParam(widget, 'insertwidth', 0.9, expected=1)
|
||||||
|
|
||||||
def test_configure_invalidcommand(self):
|
def test_invalidcommand(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkCommandParam(widget, 'invalidcommand')
|
self.checkCommandParam(widget, 'invalidcommand')
|
||||||
self.checkCommandParam(widget, 'invcmd')
|
self.checkCommandParam(widget, 'invcmd')
|
||||||
|
|
||||||
def test_configure_readonlybackground(self):
|
def test_readonlybackground(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkColorParam(widget, 'readonlybackground')
|
self.checkColorParam(widget, 'readonlybackground')
|
||||||
|
|
||||||
def test_configure_show(self):
|
def test_show(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkParam(widget, 'show', '*')
|
self.checkParam(widget, 'show', '*')
|
||||||
self.checkParam(widget, 'show', '')
|
self.checkParam(widget, 'show', '')
|
||||||
self.checkParam(widget, 'show', ' ')
|
self.checkParam(widget, 'show', ' ')
|
||||||
|
|
||||||
def test_configure_state(self):
|
def test_state(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkEnumParam(widget, 'state',
|
self.checkEnumParam(widget, 'state',
|
||||||
'disabled', 'normal', 'readonly')
|
'disabled', 'normal', 'readonly')
|
||||||
|
|
||||||
def test_configure_validate(self):
|
def test_validate(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkEnumParam(widget, 'validate',
|
self.checkEnumParam(widget, 'validate',
|
||||||
'all', 'key', 'focus', 'focusin', 'focusout', 'none')
|
'all', 'key', 'focus', 'focusin', 'focusout', 'none')
|
||||||
|
|
||||||
def test_configure_validatecommand(self):
|
def test_validatecommand(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkCommandParam(widget, 'validatecommand')
|
self.checkCommandParam(widget, 'validatecommand')
|
||||||
self.checkCommandParam(widget, 'vcmd')
|
self.checkCommandParam(widget, 'vcmd')
|
||||||
|
@ -428,25 +427,25 @@ class SpinboxTest(EntryTest, unittest.TestCase):
|
||||||
def create(self, **kwargs):
|
def create(self, **kwargs):
|
||||||
return tkinter.Spinbox(self.root, **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()
|
widget = self.create()
|
||||||
self.checkColorParam(widget, 'buttonbackground')
|
self.checkColorParam(widget, 'buttonbackground')
|
||||||
|
|
||||||
def test_configure_buttoncursor(self):
|
def test_buttoncursor(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkCursorParam(widget, 'buttoncursor')
|
self.checkCursorParam(widget, 'buttoncursor')
|
||||||
|
|
||||||
def test_configure_buttondownrelief(self):
|
def test_buttondownrelief(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkReliefParam(widget, 'buttondownrelief')
|
self.checkReliefParam(widget, 'buttondownrelief')
|
||||||
|
|
||||||
def test_configure_buttonuprelief(self):
|
def test_buttonuprelief(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkReliefParam(widget, 'buttonuprelief')
|
self.checkReliefParam(widget, 'buttonuprelief')
|
||||||
|
|
||||||
def test_configure_format(self):
|
def test_format(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkParam(widget, 'format', '%2f')
|
self.checkParam(widget, 'format', '%2f')
|
||||||
self.checkParam(widget, 'format', '%2.2f')
|
self.checkParam(widget, 'format', '%2.2f')
|
||||||
|
@ -461,25 +460,25 @@ class SpinboxTest(EntryTest, unittest.TestCase):
|
||||||
self.checkParam(widget, 'format', '%09.200f')
|
self.checkParam(widget, 'format', '%09.200f')
|
||||||
self.checkInvalidParam(widget, 'format', '%d')
|
self.checkInvalidParam(widget, 'format', '%d')
|
||||||
|
|
||||||
def test_configure_from(self):
|
def test_from(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkParam(widget, 'to', 100.0)
|
self.checkParam(widget, 'to', 100.0)
|
||||||
self.checkFloatParam(widget, 'from', -10, 10.2, 11.7)
|
self.checkFloatParam(widget, 'from', -10, 10.2, 11.7)
|
||||||
self.checkInvalidParam(widget, 'from', 200,
|
self.checkInvalidParam(widget, 'from', 200,
|
||||||
errmsg='-to value must be greater than -from value')
|
errmsg='-to value must be greater than -from value')
|
||||||
|
|
||||||
def test_configure_increment(self):
|
def test_increment(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkFloatParam(widget, 'increment', -1, 1, 10.2, 12.8, 0)
|
self.checkFloatParam(widget, 'increment', -1, 1, 10.2, 12.8, 0)
|
||||||
|
|
||||||
def test_configure_to(self):
|
def test_to(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkParam(widget, 'from', -100.0)
|
self.checkParam(widget, 'from', -100.0)
|
||||||
self.checkFloatParam(widget, 'to', -10, 10.2, 11.7)
|
self.checkFloatParam(widget, 'to', -10, 10.2, 11.7)
|
||||||
self.checkInvalidParam(widget, 'to', -200,
|
self.checkInvalidParam(widget, 'to', -200,
|
||||||
errmsg='-to value must be greater than -from value')
|
errmsg='-to value must be greater than -from value')
|
||||||
|
|
||||||
def test_configure_values(self):
|
def test_values(self):
|
||||||
# XXX
|
# XXX
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.assertEqual(widget['values'], '')
|
self.assertEqual(widget['values'], '')
|
||||||
|
@ -490,7 +489,7 @@ class SpinboxTest(EntryTest, unittest.TestCase):
|
||||||
expected='42 3.14 {} {any string}')
|
expected='42 3.14 {} {any string}')
|
||||||
self.checkParam(widget, 'values', '')
|
self.checkParam(widget, 'values', '')
|
||||||
|
|
||||||
def test_configure_wrap(self):
|
def test_wrap(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkBooleanParam(widget, 'wrap')
|
self.checkBooleanParam(widget, 'wrap')
|
||||||
|
|
||||||
|
@ -556,17 +555,17 @@ class TextTest(AbstractWidgetTest, unittest.TestCase):
|
||||||
def create(self, **kwargs):
|
def create(self, **kwargs):
|
||||||
return tkinter.Text(self.root, **kwargs)
|
return tkinter.Text(self.root, **kwargs)
|
||||||
|
|
||||||
def test_configure_autoseparators(self):
|
def test_autoseparators(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkBooleanParam(widget, 'autoseparators')
|
self.checkBooleanParam(widget, 'autoseparators')
|
||||||
|
|
||||||
@requires_tcl(8, 5)
|
@requires_tcl(8, 5)
|
||||||
def test_configure_blockcursor(self):
|
def test_blockcursor(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkBooleanParam(widget, 'blockcursor')
|
self.checkBooleanParam(widget, 'blockcursor')
|
||||||
|
|
||||||
@requires_tcl(8, 5)
|
@requires_tcl(8, 5)
|
||||||
def test_configure_endline(self):
|
def test_endline(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
text = '\n'.join('Line %d' for i in range(100))
|
text = '\n'.join('Line %d' for i in range(100))
|
||||||
widget.insert('end', text)
|
widget.insert('end', text)
|
||||||
|
@ -579,50 +578,50 @@ class TextTest(AbstractWidgetTest, unittest.TestCase):
|
||||||
self.checkInvalidParam(widget, 'endline', 10,
|
self.checkInvalidParam(widget, 'endline', 10,
|
||||||
errmsg='-startline must be less than or equal to -endline')
|
errmsg='-startline must be less than or equal to -endline')
|
||||||
|
|
||||||
def test_configure_height(self):
|
def test_height(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkPixelsParam(widget, 'height', 100, 101.2, 102.6, '3c')
|
self.checkPixelsParam(widget, 'height', 100, 101.2, 102.6, '3c')
|
||||||
self.checkParam(widget, 'height', -100, expected=1)
|
self.checkParam(widget, 'height', -100, expected=1)
|
||||||
self.checkParam(widget, 'height', 0, expected=1)
|
self.checkParam(widget, 'height', 0, expected=1)
|
||||||
|
|
||||||
def test_configure_maxundo(self):
|
def test_maxundo(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkIntegerParam(widget, 'maxundo', 0, 5, -1)
|
self.checkIntegerParam(widget, 'maxundo', 0, 5, -1)
|
||||||
|
|
||||||
@requires_tcl(8, 5)
|
@requires_tcl(8, 5)
|
||||||
def test_configure_inactiveselectbackground(self):
|
def test_inactiveselectbackground(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkColorParam(widget, 'inactiveselectbackground')
|
self.checkColorParam(widget, 'inactiveselectbackground')
|
||||||
|
|
||||||
@requires_tcl(8, 6)
|
@requires_tcl(8, 6)
|
||||||
def test_configure_insertunfocussed(self):
|
def test_insertunfocussed(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkEnumParam(widget, 'insertunfocussed',
|
self.checkEnumParam(widget, 'insertunfocussed',
|
||||||
'hollow', 'none', 'solid')
|
'hollow', 'none', 'solid')
|
||||||
|
|
||||||
def test_configure_selectborderwidth(self):
|
def test_selectborderwidth(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkPixelsParam(widget, 'selectborderwidth',
|
self.checkPixelsParam(widget, 'selectborderwidth',
|
||||||
1.3, 2.6, -2, '10p', conv=noconv,
|
1.3, 2.6, -2, '10p', conv=noconv,
|
||||||
keep_orig=tcl_version >= (8, 5))
|
keep_orig=tcl_version >= (8, 5))
|
||||||
|
|
||||||
def test_configure_spacing1(self):
|
def test_spacing1(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkPixelsParam(widget, 'spacing1', 20, 21.4, 22.6, '0.5c')
|
self.checkPixelsParam(widget, 'spacing1', 20, 21.4, 22.6, '0.5c')
|
||||||
self.checkParam(widget, 'spacing1', -5, expected=0)
|
self.checkParam(widget, 'spacing1', -5, expected=0)
|
||||||
|
|
||||||
def test_configure_spacing2(self):
|
def test_spacing2(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkPixelsParam(widget, 'spacing2', 5, 6.4, 7.6, '0.1c')
|
self.checkPixelsParam(widget, 'spacing2', 5, 6.4, 7.6, '0.1c')
|
||||||
self.checkParam(widget, 'spacing2', -1, expected=0)
|
self.checkParam(widget, 'spacing2', -1, expected=0)
|
||||||
|
|
||||||
def test_configure_spacing3(self):
|
def test_spacing3(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkPixelsParam(widget, 'spacing3', 20, 21.4, 22.6, '0.5c')
|
self.checkPixelsParam(widget, 'spacing3', 20, 21.4, 22.6, '0.5c')
|
||||||
self.checkParam(widget, 'spacing3', -10, expected=0)
|
self.checkParam(widget, 'spacing3', -10, expected=0)
|
||||||
|
|
||||||
@requires_tcl(8, 5)
|
@requires_tcl(8, 5)
|
||||||
def test_configure_startline(self):
|
def test_startline(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
text = '\n'.join('Line %d' for i in range(100))
|
text = '\n'.join('Line %d' for i in range(100))
|
||||||
widget.insert('end', text)
|
widget.insert('end', text)
|
||||||
|
@ -635,14 +634,14 @@ class TextTest(AbstractWidgetTest, unittest.TestCase):
|
||||||
self.checkInvalidParam(widget, 'startline', 70,
|
self.checkInvalidParam(widget, 'startline', 70,
|
||||||
errmsg='-startline must be less than or equal to -endline')
|
errmsg='-startline must be less than or equal to -endline')
|
||||||
|
|
||||||
def test_configure_state(self):
|
def test_state(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
if tcl_version < (8, 5):
|
if tcl_version < (8, 5):
|
||||||
self.checkParams(widget, 'state', 'disabled', 'normal')
|
self.checkParams(widget, 'state', 'disabled', 'normal')
|
||||||
else:
|
else:
|
||||||
self.checkEnumParam(widget, 'state', 'disabled', 'normal')
|
self.checkEnumParam(widget, 'state', 'disabled', 'normal')
|
||||||
|
|
||||||
def test_configure_tabs(self):
|
def test_tabs(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
if get_tk_patchlevel() < (8, 5, 11):
|
if get_tk_patchlevel() < (8, 5, 11):
|
||||||
self.checkParam(widget, 'tabs', (10.2, 20.7, '1i', '2i'),
|
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))
|
keep_orig=tcl_version >= (8, 5))
|
||||||
|
|
||||||
@requires_tcl(8, 5)
|
@requires_tcl(8, 5)
|
||||||
def test_configure_tabstyle(self):
|
def test_tabstyle(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkEnumParam(widget, 'tabstyle', 'tabular', 'wordprocessor')
|
self.checkEnumParam(widget, 'tabstyle', 'tabular', 'wordprocessor')
|
||||||
|
|
||||||
def test_configure_undo(self):
|
def test_undo(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkBooleanParam(widget, 'undo')
|
self.checkBooleanParam(widget, 'undo')
|
||||||
|
|
||||||
def test_configure_width(self):
|
def test_width(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkIntegerParam(widget, 'width', 402)
|
self.checkIntegerParam(widget, 'width', 402)
|
||||||
self.checkParam(widget, 'width', -402, expected=1)
|
self.checkParam(widget, 'width', -402, expected=1)
|
||||||
self.checkParam(widget, 'width', 0, expected=1)
|
self.checkParam(widget, 'width', 0, expected=1)
|
||||||
|
|
||||||
def test_configure_wrap(self):
|
def test_wrap(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
if tcl_version < (8, 5):
|
if tcl_version < (8, 5):
|
||||||
self.checkParams(widget, 'wrap', 'char', 'none', 'word')
|
self.checkParams(widget, 'wrap', 'char', 'none', 'word')
|
||||||
|
@ -710,16 +709,16 @@ class CanvasTest(AbstractWidgetTest, unittest.TestCase):
|
||||||
def create(self, **kwargs):
|
def create(self, **kwargs):
|
||||||
return tkinter.Canvas(self.root, **kwargs)
|
return tkinter.Canvas(self.root, **kwargs)
|
||||||
|
|
||||||
def test_configure_closeenough(self):
|
def test_closeenough(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkFloatParam(widget, 'closeenough', 24, 2.4, 3.6, -3,
|
self.checkFloatParam(widget, 'closeenough', 24, 2.4, 3.6, -3,
|
||||||
conv=float)
|
conv=float)
|
||||||
|
|
||||||
def test_configure_confine(self):
|
def test_confine(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkBooleanParam(widget, 'confine')
|
self.checkBooleanParam(widget, 'confine')
|
||||||
|
|
||||||
def test_configure_offset(self):
|
def test_offset(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.assertEqual(widget['offset'], '0,0')
|
self.assertEqual(widget['offset'], '0,0')
|
||||||
self.checkParams(widget, 'offset',
|
self.checkParams(widget, 'offset',
|
||||||
|
@ -728,7 +727,7 @@ class CanvasTest(AbstractWidgetTest, unittest.TestCase):
|
||||||
self.checkParam(widget, 'offset', '#5,6')
|
self.checkParam(widget, 'offset', '#5,6')
|
||||||
self.checkInvalidParam(widget, 'offset', 'spam')
|
self.checkInvalidParam(widget, 'offset', 'spam')
|
||||||
|
|
||||||
def test_configure_scrollregion(self):
|
def test_scrollregion(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkParam(widget, 'scrollregion', '0 0 200 150')
|
self.checkParam(widget, 'scrollregion', '0 0 200 150')
|
||||||
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))
|
||||||
self.checkInvalidParam(widget, 'scrollregion', (0, 0, 200, 150, 0))
|
self.checkInvalidParam(widget, 'scrollregion', (0, 0, 200, 150, 0))
|
||||||
|
|
||||||
def test_configure_state(self):
|
def test_state(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkEnumParam(widget, 'state', 'disabled', 'normal',
|
self.checkEnumParam(widget, 'state', 'disabled', 'normal',
|
||||||
errmsg='bad state value "{}": must be normal or disabled')
|
errmsg='bad state value "{}": must be normal or disabled')
|
||||||
|
|
||||||
def test_configure_xscrollincrement(self):
|
def test_xscrollincrement(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkPixelsParam(widget, 'xscrollincrement',
|
self.checkPixelsParam(widget, 'xscrollincrement',
|
||||||
40, 0, 41.2, 43.6, -40, '0.5i')
|
40, 0, 41.2, 43.6, -40, '0.5i')
|
||||||
|
|
||||||
def test_configure_yscrollincrement(self):
|
def test_yscrollincrement(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkPixelsParam(widget, 'yscrollincrement',
|
self.checkPixelsParam(widget, 'yscrollincrement',
|
||||||
10, 0, 11.2, 13.6, -10, '0.1i')
|
10, 0, 11.2, 13.6, -10, '0.1i')
|
||||||
|
@ -795,26 +794,26 @@ class ListboxTest(AbstractWidgetTest, unittest.TestCase):
|
||||||
def create(self, **kwargs):
|
def create(self, **kwargs):
|
||||||
return tkinter.Listbox(self.root, **kwargs)
|
return tkinter.Listbox(self.root, **kwargs)
|
||||||
|
|
||||||
def test_configure_activestyle(self):
|
def test_activestyle(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkEnumParam(widget, 'activestyle',
|
self.checkEnumParam(widget, 'activestyle',
|
||||||
'dotbox', 'none', 'underline')
|
'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()
|
widget = self.create()
|
||||||
var = tkinter.DoubleVar(self.root)
|
var = tkinter.DoubleVar(self.root)
|
||||||
self.checkVariableParam(widget, 'listvariable', var)
|
self.checkVariableParam(widget, 'listvariable', var)
|
||||||
|
|
||||||
def test_configure_selectmode(self):
|
def test_selectmode(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkParam(widget, 'selectmode', 'single')
|
self.checkParam(widget, 'selectmode', 'single')
|
||||||
self.checkParam(widget, 'selectmode', 'browse')
|
self.checkParam(widget, 'selectmode', 'browse')
|
||||||
self.checkParam(widget, 'selectmode', 'multiple')
|
self.checkParam(widget, 'selectmode', 'multiple')
|
||||||
self.checkParam(widget, 'selectmode', 'extended')
|
self.checkParam(widget, 'selectmode', 'extended')
|
||||||
|
|
||||||
def test_configure_state(self):
|
def test_state(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkEnumParam(widget, 'state', 'disabled', 'normal')
|
self.checkEnumParam(widget, 'state', 'disabled', 'normal')
|
||||||
|
|
||||||
|
@ -929,53 +928,53 @@ class ScaleTest(AbstractWidgetTest, unittest.TestCase):
|
||||||
def create(self, **kwargs):
|
def create(self, **kwargs):
|
||||||
return tkinter.Scale(self.root, **kwargs)
|
return tkinter.Scale(self.root, **kwargs)
|
||||||
|
|
||||||
def test_configure_bigincrement(self):
|
def test_bigincrement(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkFloatParam(widget, 'bigincrement', 12.4, 23.6, -5)
|
self.checkFloatParam(widget, 'bigincrement', 12.4, 23.6, -5)
|
||||||
|
|
||||||
def test_configure_digits(self):
|
def test_digits(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkIntegerParam(widget, 'digits', 5, 0)
|
self.checkIntegerParam(widget, 'digits', 5, 0)
|
||||||
|
|
||||||
def test_configure_from(self):
|
def test_from(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
conv = False if get_tk_patchlevel() >= (8, 6, 10) else float_round
|
conv = False if get_tk_patchlevel() >= (8, 6, 10) else float_round
|
||||||
self.checkFloatParam(widget, 'from', 100, 14.9, 15.1, conv=conv)
|
self.checkFloatParam(widget, 'from', 100, 14.9, 15.1, conv=conv)
|
||||||
|
|
||||||
def test_configure_label(self):
|
def test_label(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkParam(widget, 'label', 'any string')
|
self.checkParam(widget, 'label', 'any string')
|
||||||
self.checkParam(widget, 'label', '')
|
self.checkParam(widget, 'label', '')
|
||||||
|
|
||||||
def test_configure_length(self):
|
def test_length(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkPixelsParam(widget, 'length', 130, 131.2, 135.6, '5i')
|
self.checkPixelsParam(widget, 'length', 130, 131.2, 135.6, '5i')
|
||||||
|
|
||||||
def test_configure_resolution(self):
|
def test_resolution(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkFloatParam(widget, 'resolution', 4.2, 0, 6.7, -2)
|
self.checkFloatParam(widget, 'resolution', 4.2, 0, 6.7, -2)
|
||||||
|
|
||||||
def test_configure_showvalue(self):
|
def test_showvalue(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkBooleanParam(widget, 'showvalue')
|
self.checkBooleanParam(widget, 'showvalue')
|
||||||
|
|
||||||
def test_configure_sliderlength(self):
|
def test_sliderlength(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkPixelsParam(widget, 'sliderlength',
|
self.checkPixelsParam(widget, 'sliderlength',
|
||||||
10, 11.2, 15.6, -3, '3m')
|
10, 11.2, 15.6, -3, '3m')
|
||||||
|
|
||||||
def test_configure_sliderrelief(self):
|
def test_sliderrelief(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkReliefParam(widget, 'sliderrelief')
|
self.checkReliefParam(widget, 'sliderrelief')
|
||||||
|
|
||||||
def test_configure_tickinterval(self):
|
def test_tickinterval(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkFloatParam(widget, 'tickinterval', 1, 4.3, 7.6, 0,
|
self.checkFloatParam(widget, 'tickinterval', 1, 4.3, 7.6, 0,
|
||||||
conv=float_round)
|
conv=float_round)
|
||||||
self.checkParam(widget, 'tickinterval', -2, expected=2,
|
self.checkParam(widget, 'tickinterval', -2, expected=2,
|
||||||
conv=float_round)
|
conv=float_round)
|
||||||
|
|
||||||
def test_configure_to(self):
|
def test_to(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkFloatParam(widget, 'to', 300, 14.9, 15.1, -10,
|
self.checkFloatParam(widget, 'to', 300, 14.9, 15.1, -10,
|
||||||
conv=float_round)
|
conv=float_round)
|
||||||
|
@ -999,15 +998,15 @@ class ScrollbarTest(AbstractWidgetTest, unittest.TestCase):
|
||||||
def create(self, **kwargs):
|
def create(self, **kwargs):
|
||||||
return tkinter.Scrollbar(self.root, **kwargs)
|
return tkinter.Scrollbar(self.root, **kwargs)
|
||||||
|
|
||||||
def test_configure_activerelief(self):
|
def test_activerelief(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkReliefParam(widget, 'activerelief')
|
self.checkReliefParam(widget, 'activerelief')
|
||||||
|
|
||||||
def test_configure_elementborderwidth(self):
|
def test_elementborderwidth(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkPixelsParam(widget, 'elementborderwidth', 4.3, 5.6, -2, '1m')
|
self.checkPixelsParam(widget, 'elementborderwidth', 4.3, 5.6, -2, '1m')
|
||||||
|
|
||||||
def test_configure_orient(self):
|
def test_orient(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkEnumParam(widget, 'orient', 'vertical', 'horizontal',
|
self.checkEnumParam(widget, 'orient', 'vertical', 'horizontal',
|
||||||
errmsg='bad orientation "{}": must be vertical or horizontal')
|
errmsg='bad orientation "{}": must be vertical or horizontal')
|
||||||
|
@ -1048,63 +1047,63 @@ class PanedWindowTest(AbstractWidgetTest, unittest.TestCase):
|
||||||
def create(self, **kwargs):
|
def create(self, **kwargs):
|
||||||
return tkinter.PanedWindow(self.root, **kwargs)
|
return tkinter.PanedWindow(self.root, **kwargs)
|
||||||
|
|
||||||
def test_configure_handlepad(self):
|
def test_handlepad(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkPixelsParam(widget, 'handlepad', 5, 6.4, 7.6, -3, '1m')
|
self.checkPixelsParam(widget, 'handlepad', 5, 6.4, 7.6, -3, '1m')
|
||||||
|
|
||||||
def test_configure_handlesize(self):
|
def test_handlesize(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkPixelsParam(widget, 'handlesize', 8, 9.4, 10.6, -3, '2m',
|
self.checkPixelsParam(widget, 'handlesize', 8, 9.4, 10.6, -3, '2m',
|
||||||
conv=noconv)
|
conv=noconv)
|
||||||
|
|
||||||
def test_configure_height(self):
|
def test_height(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkPixelsParam(widget, 'height', 100, 101.2, 102.6, -100, 0, '1i',
|
self.checkPixelsParam(widget, 'height', 100, 101.2, 102.6, -100, 0, '1i',
|
||||||
conv=noconv)
|
conv=noconv)
|
||||||
|
|
||||||
def test_configure_opaqueresize(self):
|
def test_opaqueresize(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkBooleanParam(widget, 'opaqueresize')
|
self.checkBooleanParam(widget, 'opaqueresize')
|
||||||
|
|
||||||
@requires_tcl(8, 6, 5)
|
@requires_tcl(8, 6, 5)
|
||||||
def test_configure_proxybackground(self):
|
def test_proxybackground(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkColorParam(widget, 'proxybackground')
|
self.checkColorParam(widget, 'proxybackground')
|
||||||
|
|
||||||
@requires_tcl(8, 6, 5)
|
@requires_tcl(8, 6, 5)
|
||||||
def test_configure_proxyborderwidth(self):
|
def test_proxyborderwidth(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkPixelsParam(widget, 'proxyborderwidth',
|
self.checkPixelsParam(widget, 'proxyborderwidth',
|
||||||
0, 1.3, 2.9, 6, -2, '10p',
|
0, 1.3, 2.9, 6, -2, '10p',
|
||||||
conv=noconv)
|
conv=noconv)
|
||||||
|
|
||||||
@requires_tcl(8, 6, 5)
|
@requires_tcl(8, 6, 5)
|
||||||
def test_configure_proxyrelief(self):
|
def test_proxyrelief(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkReliefParam(widget, 'proxyrelief')
|
self.checkReliefParam(widget, 'proxyrelief')
|
||||||
|
|
||||||
def test_configure_sashcursor(self):
|
def test_sashcursor(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkCursorParam(widget, 'sashcursor')
|
self.checkCursorParam(widget, 'sashcursor')
|
||||||
|
|
||||||
def test_configure_sashpad(self):
|
def test_sashpad(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkPixelsParam(widget, 'sashpad', 8, 1.3, 2.6, -2, '2m')
|
self.checkPixelsParam(widget, 'sashpad', 8, 1.3, 2.6, -2, '2m')
|
||||||
|
|
||||||
def test_configure_sashrelief(self):
|
def test_sashrelief(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkReliefParam(widget, 'sashrelief')
|
self.checkReliefParam(widget, 'sashrelief')
|
||||||
|
|
||||||
def test_configure_sashwidth(self):
|
def test_sashwidth(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkPixelsParam(widget, 'sashwidth', 10, 11.1, 15.6, -3, '1m',
|
self.checkPixelsParam(widget, 'sashwidth', 10, 11.1, 15.6, -3, '1m',
|
||||||
conv=noconv)
|
conv=noconv)
|
||||||
|
|
||||||
def test_configure_showhandle(self):
|
def test_showhandle(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkBooleanParam(widget, 'showhandle')
|
self.checkBooleanParam(widget, 'showhandle')
|
||||||
|
|
||||||
def test_configure_width(self):
|
def test_width(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkPixelsParam(widget, 'width', 402, 403.4, 404.6, -402, 0, '5i',
|
self.checkPixelsParam(widget, 'width', 402, 403.4, 404.6, -402, 0, '5i',
|
||||||
conv=noconv)
|
conv=noconv)
|
||||||
|
@ -1223,23 +1222,23 @@ class MenuTest(AbstractWidgetTest, unittest.TestCase):
|
||||||
def create(self, **kwargs):
|
def create(self, **kwargs):
|
||||||
return tkinter.Menu(self.root, **kwargs)
|
return tkinter.Menu(self.root, **kwargs)
|
||||||
|
|
||||||
def test_configure_postcommand(self):
|
def test_postcommand(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkCommandParam(widget, 'postcommand')
|
self.checkCommandParam(widget, 'postcommand')
|
||||||
|
|
||||||
def test_configure_tearoff(self):
|
def test_tearoff(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkBooleanParam(widget, 'tearoff')
|
self.checkBooleanParam(widget, 'tearoff')
|
||||||
|
|
||||||
def test_configure_tearoffcommand(self):
|
def test_tearoffcommand(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkCommandParam(widget, 'tearoffcommand')
|
self.checkCommandParam(widget, 'tearoffcommand')
|
||||||
|
|
||||||
def test_configure_title(self):
|
def test_title(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkParam(widget, 'title', 'any string')
|
self.checkParam(widget, 'title', 'any string')
|
||||||
|
|
||||||
def test_configure_type(self):
|
def test_type(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkEnumParam(widget, 'type',
|
self.checkEnumParam(widget, 'type',
|
||||||
'normal', 'tearoff', 'menubar')
|
'normal', 'tearoff', 'menubar')
|
||||||
|
@ -1292,7 +1291,7 @@ class MessageTest(AbstractWidgetTest, unittest.TestCase):
|
||||||
def create(self, **kwargs):
|
def create(self, **kwargs):
|
||||||
return tkinter.Message(self.root, **kwargs)
|
return tkinter.Message(self.root, **kwargs)
|
||||||
|
|
||||||
def test_configure_aspect(self):
|
def test_aspect(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkIntegerParam(widget, 'aspect', 250, 0, -300)
|
self.checkIntegerParam(widget, 'aspect', 250, 0, -300)
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,7 @@ requires('gui')
|
||||||
|
|
||||||
class StandardTtkOptionsTests(StandardOptionsTests):
|
class StandardTtkOptionsTests(StandardOptionsTests):
|
||||||
|
|
||||||
def test_configure_class(self):
|
def test_class(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.assertEqual(widget['class'], '')
|
self.assertEqual(widget['class'], '')
|
||||||
errmsg='attempt to change read-only option'
|
errmsg='attempt to change read-only option'
|
||||||
|
@ -26,7 +26,7 @@ class StandardTtkOptionsTests(StandardOptionsTests):
|
||||||
widget2 = self.create(class_='Foo')
|
widget2 = self.create(class_='Foo')
|
||||||
self.assertEqual(widget2['class'], 'Foo')
|
self.assertEqual(widget2['class'], 'Foo')
|
||||||
|
|
||||||
def test_configure_padding(self):
|
def test_padding(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkParam(widget, 'padding', 0, expected=('0',))
|
self.checkParam(widget, 'padding', 0, expected=('0',))
|
||||||
self.checkParam(widget, 'padding', 5, expected=('5',))
|
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', ('5p', '6p', '7p', '8p'))
|
||||||
self.checkParam(widget, 'padding', (), expected='')
|
self.checkParam(widget, 'padding', (), expected='')
|
||||||
|
|
||||||
def test_configure_style(self):
|
def test_style(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.assertEqual(widget['style'], '')
|
self.assertEqual(widget['style'], '')
|
||||||
errmsg = 'Layout Foo not found'
|
errmsg = 'Layout Foo not found'
|
||||||
|
@ -139,14 +139,14 @@ class LabelFrameTest(AbstractToplevelTest, unittest.TestCase):
|
||||||
def create(self, **kwargs):
|
def create(self, **kwargs):
|
||||||
return ttk.LabelFrame(self.root, **kwargs)
|
return ttk.LabelFrame(self.root, **kwargs)
|
||||||
|
|
||||||
def test_configure_labelanchor(self):
|
def test_labelanchor(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkEnumParam(widget, 'labelanchor',
|
self.checkEnumParam(widget, 'labelanchor',
|
||||||
'e', 'en', 'es', 'n', 'ne', 'nw', 's', 'se', 'sw', 'w', 'wn', 'ws',
|
'e', 'en', 'es', 'n', 'ne', 'nw', 's', 'se', 'sw', 'w', 'wn', 'ws',
|
||||||
errmsg='Bad label anchor specification {}')
|
errmsg='Bad label anchor specification {}')
|
||||||
self.checkInvalidParam(widget, 'labelanchor', 'center')
|
self.checkInvalidParam(widget, 'labelanchor', 'center')
|
||||||
|
|
||||||
def test_configure_labelwidget(self):
|
def test_labelwidget(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
label = ttk.Label(self.root, text='Mupp', name='foo')
|
label = ttk.Label(self.root, text='Mupp', name='foo')
|
||||||
self.checkParam(widget, 'labelwidget', label, expected='.foo')
|
self.checkParam(widget, 'labelwidget', label, expected='.foo')
|
||||||
|
@ -168,17 +168,17 @@ class AbstractLabelTest(AbstractWidgetTest):
|
||||||
self.checkInvalidParam(widget, name, 'spam',
|
self.checkInvalidParam(widget, name, 'spam',
|
||||||
errmsg='image "spam" doesn\'t exist')
|
errmsg='image "spam" doesn\'t exist')
|
||||||
|
|
||||||
def test_configure_compound(self):
|
def test_compound(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkEnumParam(widget, 'compound',
|
self.checkEnumParam(widget, 'compound',
|
||||||
'none', 'text', 'image', 'center',
|
'none', 'text', 'image', 'center',
|
||||||
'top', 'bottom', 'left', 'right')
|
'top', 'bottom', 'left', 'right')
|
||||||
|
|
||||||
def test_configure_state(self):
|
def test_state(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkParams(widget, 'state', 'active', 'disabled', 'normal')
|
self.checkParams(widget, 'state', 'active', 'disabled', 'normal')
|
||||||
|
|
||||||
def test_configure_width(self):
|
def test_width(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkParams(widget, 'width', 402, -402, 0)
|
self.checkParams(widget, 'width', 402, -402, 0)
|
||||||
|
|
||||||
|
@ -197,7 +197,7 @@ class LabelTest(AbstractLabelTest, unittest.TestCase):
|
||||||
def create(self, **kwargs):
|
def create(self, **kwargs):
|
||||||
return ttk.Label(self.root, **kwargs)
|
return ttk.Label(self.root, **kwargs)
|
||||||
|
|
||||||
def test_configure_font(self):
|
def test_font(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkParam(widget, 'font',
|
self.checkParam(widget, 'font',
|
||||||
'-Adobe-Helvetica-Medium-R-Normal--*-120-*-*-*-*-*-*')
|
'-Adobe-Helvetica-Medium-R-Normal--*-120-*-*-*-*-*-*')
|
||||||
|
@ -215,7 +215,7 @@ class ButtonTest(AbstractLabelTest, unittest.TestCase):
|
||||||
def create(self, **kwargs):
|
def create(self, **kwargs):
|
||||||
return ttk.Button(self.root, **kwargs)
|
return ttk.Button(self.root, **kwargs)
|
||||||
|
|
||||||
def test_configure_default(self):
|
def test_default(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkEnumParam(widget, 'default', 'normal', 'active', 'disabled')
|
self.checkEnumParam(widget, 'default', 'normal', 'active', 'disabled')
|
||||||
|
|
||||||
|
@ -240,11 +240,11 @@ class CheckbuttonTest(AbstractLabelTest, unittest.TestCase):
|
||||||
def create(self, **kwargs):
|
def create(self, **kwargs):
|
||||||
return ttk.Checkbutton(self.root, **kwargs)
|
return ttk.Checkbutton(self.root, **kwargs)
|
||||||
|
|
||||||
def test_configure_offvalue(self):
|
def test_offvalue(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkParams(widget, 'offvalue', 1, 2.3, '', 'any string')
|
self.checkParams(widget, 'offvalue', 1, 2.3, '', 'any string')
|
||||||
|
|
||||||
def test_configure_onvalue(self):
|
def test_onvalue(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkParams(widget, 'onvalue', 1, 2.3, '', 'any string')
|
self.checkParams(widget, 'onvalue', 1, 2.3, '', 'any string')
|
||||||
|
|
||||||
|
@ -292,27 +292,27 @@ class EntryTest(AbstractWidgetTest, unittest.TestCase):
|
||||||
def create(self, **kwargs):
|
def create(self, **kwargs):
|
||||||
return ttk.Entry(self.root, **kwargs)
|
return ttk.Entry(self.root, **kwargs)
|
||||||
|
|
||||||
def test_configure_invalidcommand(self):
|
def test_invalidcommand(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkCommandParam(widget, 'invalidcommand')
|
self.checkCommandParam(widget, 'invalidcommand')
|
||||||
|
|
||||||
def test_configure_show(self):
|
def test_show(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkParam(widget, 'show', '*')
|
self.checkParam(widget, 'show', '*')
|
||||||
self.checkParam(widget, 'show', '')
|
self.checkParam(widget, 'show', '')
|
||||||
self.checkParam(widget, 'show', ' ')
|
self.checkParam(widget, 'show', ' ')
|
||||||
|
|
||||||
def test_configure_state(self):
|
def test_state(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkParams(widget, 'state',
|
self.checkParams(widget, 'state',
|
||||||
'disabled', 'normal', 'readonly')
|
'disabled', 'normal', 'readonly')
|
||||||
|
|
||||||
def test_configure_validate(self):
|
def test_validate(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkEnumParam(widget, 'validate',
|
self.checkEnumParam(widget, 'validate',
|
||||||
'all', 'key', 'focus', 'focusin', 'focusout', 'none')
|
'all', 'key', 'focus', 'focusin', 'focusout', 'none')
|
||||||
|
|
||||||
def test_configure_validatecommand(self):
|
def test_validatecommand(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkCommandParam(widget, 'validatecommand')
|
self.checkCommandParam(widget, 'validatecommand')
|
||||||
|
|
||||||
|
@ -429,7 +429,7 @@ class ComboboxTest(EntryTest, unittest.TestCase):
|
||||||
def create(self, **kwargs):
|
def create(self, **kwargs):
|
||||||
return ttk.Combobox(self.root, **kwargs)
|
return ttk.Combobox(self.root, **kwargs)
|
||||||
|
|
||||||
def test_configure_height(self):
|
def test_height(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkParams(widget, 'height', 100, 101.2, 102.6, -100, 0, '1i')
|
self.checkParams(widget, 'height', 100, 101.2, 102.6, -100, 0, '1i')
|
||||||
|
|
||||||
|
@ -459,7 +459,7 @@ class ComboboxTest(EntryTest, unittest.TestCase):
|
||||||
self.assertTrue(success)
|
self.assertTrue(success)
|
||||||
|
|
||||||
|
|
||||||
def test_configure_postcommand(self):
|
def test_postcommand(self):
|
||||||
success = []
|
success = []
|
||||||
|
|
||||||
self.combo['postcommand'] = lambda: success.append(True)
|
self.combo['postcommand'] = lambda: success.append(True)
|
||||||
|
@ -475,7 +475,7 @@ class ComboboxTest(EntryTest, unittest.TestCase):
|
||||||
self.assertEqual(len(success), 1)
|
self.assertEqual(len(success), 1)
|
||||||
|
|
||||||
|
|
||||||
def test_configure_values(self):
|
def test_values(self):
|
||||||
def check_get_current(getval, currval):
|
def check_get_current(getval, currval):
|
||||||
self.assertEqual(self.combo.get(), getval)
|
self.assertEqual(self.combo.get(), getval)
|
||||||
self.assertEqual(self.combo.current(), currval)
|
self.assertEqual(self.combo.current(), currval)
|
||||||
|
@ -551,7 +551,7 @@ class PanedWindowTest(AbstractWidgetTest, unittest.TestCase):
|
||||||
def create(self, **kwargs):
|
def create(self, **kwargs):
|
||||||
return ttk.PanedWindow(self.root, **kwargs)
|
return ttk.PanedWindow(self.root, **kwargs)
|
||||||
|
|
||||||
def test_configure_orient(self):
|
def test_orient(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.assertEqual(str(widget['orient']), 'vertical')
|
self.assertEqual(str(widget['orient']), 'vertical')
|
||||||
errmsg='attempt to change read-only option'
|
errmsg='attempt to change read-only option'
|
||||||
|
@ -684,11 +684,11 @@ class RadiobuttonTest(AbstractLabelTest, unittest.TestCase):
|
||||||
def create(self, **kwargs):
|
def create(self, **kwargs):
|
||||||
return ttk.Radiobutton(self.root, **kwargs)
|
return ttk.Radiobutton(self.root, **kwargs)
|
||||||
|
|
||||||
def test_configure_value(self):
|
def test_value(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkParams(widget, 'value', 1, 2.3, '', 'any string')
|
self.checkParams(widget, 'value', 1, 2.3, '', 'any string')
|
||||||
|
|
||||||
def test_configure_invoke(self):
|
def test_invoke(self):
|
||||||
success = []
|
success = []
|
||||||
def cb_test():
|
def cb_test():
|
||||||
success.append(1)
|
success.append(1)
|
||||||
|
@ -739,7 +739,7 @@ class MenubuttonTest(AbstractLabelTest, unittest.TestCase):
|
||||||
self.checkEnumParam(widget, 'direction',
|
self.checkEnumParam(widget, 'direction',
|
||||||
'above', 'below', 'left', 'right', 'flush')
|
'above', 'below', 'left', 'right', 'flush')
|
||||||
|
|
||||||
def test_configure_menu(self):
|
def test_menu(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
menu = tkinter.Menu(widget, name='menu')
|
menu = tkinter.Menu(widget, name='menu')
|
||||||
self.checkParam(widget, 'menu', menu, conv=str)
|
self.checkParam(widget, 'menu', menu, conv=str)
|
||||||
|
@ -764,19 +764,19 @@ class ScaleTest(AbstractWidgetTest, unittest.TestCase):
|
||||||
def create(self, **kwargs):
|
def create(self, **kwargs):
|
||||||
return ttk.Scale(self.root, **kwargs)
|
return ttk.Scale(self.root, **kwargs)
|
||||||
|
|
||||||
def test_configure_from(self):
|
def test_from(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkFloatParam(widget, 'from', 100, 14.9, 15.1, conv=False)
|
self.checkFloatParam(widget, 'from', 100, 14.9, 15.1, conv=False)
|
||||||
|
|
||||||
def test_configure_length(self):
|
def test_length(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkPixelsParam(widget, 'length', 130, 131.2, 135.6, '5i')
|
self.checkPixelsParam(widget, 'length', 130, 131.2, 135.6, '5i')
|
||||||
|
|
||||||
def test_configure_to(self):
|
def test_to(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkFloatParam(widget, 'to', 300, 14.9, 15.1, -10, conv=False)
|
self.checkFloatParam(widget, 'to', 300, 14.9, 15.1, -10, conv=False)
|
||||||
|
|
||||||
def test_configure_value(self):
|
def test_value(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkFloatParam(widget, 'value', 300, 14.9, 15.1, -10, conv=False)
|
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):
|
def create(self, **kwargs):
|
||||||
return ttk.Progressbar(self.root, **kwargs)
|
return ttk.Progressbar(self.root, **kwargs)
|
||||||
|
|
||||||
def test_configure_length(self):
|
def test_length(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkPixelsParam(widget, 'length', 100.1, 56.7, '2i')
|
self.checkPixelsParam(widget, 'length', 100.1, 56.7, '2i')
|
||||||
|
|
||||||
def test_configure_maximum(self):
|
def test_maximum(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkFloatParam(widget, 'maximum', 150.2, 77.7, 0, -10, conv=False)
|
self.checkFloatParam(widget, 'maximum', 150.2, 77.7, 0, -10, conv=False)
|
||||||
|
|
||||||
def test_configure_mode(self):
|
def test_mode(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkEnumParam(widget, 'mode', 'determinate', 'indeterminate')
|
self.checkEnumParam(widget, 'mode', 'determinate', 'indeterminate')
|
||||||
|
|
||||||
def test_configure_phase(self):
|
def test_phase(self):
|
||||||
# XXX
|
# XXX
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def test_configure_value(self):
|
def test_value(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkFloatParam(widget, 'value', 150.2, 77.7, 0, -10,
|
self.checkFloatParam(widget, 'value', 150.2, 77.7, 0, -10,
|
||||||
conv=False)
|
conv=False)
|
||||||
|
@ -1071,7 +1071,7 @@ class NotebookTest(AbstractWidgetTest, unittest.TestCase):
|
||||||
self.assertEqual(self.nb.tab(self.child1, 'text'), 'abc')
|
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.assertEqual(len(self.nb.tabs()), 2)
|
||||||
|
|
||||||
self.nb.forget(self.child1)
|
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.event_generate('<ButtonRelease-1>', x=x, y=y)
|
||||||
self.spin.update_idletasks()
|
self.spin.update_idletasks()
|
||||||
|
|
||||||
def test_configure_command(self):
|
def test_command(self):
|
||||||
success = []
|
success = []
|
||||||
|
|
||||||
self.spin['command'] = lambda: success.append(True)
|
self.spin['command'] = lambda: success.append(True)
|
||||||
|
@ -1167,7 +1167,7 @@ class SpinboxTest(EntryTest, unittest.TestCase):
|
||||||
self.spin.update()
|
self.spin.update()
|
||||||
self.assertEqual(len(success), 2)
|
self.assertEqual(len(success), 2)
|
||||||
|
|
||||||
def test_configure_to(self):
|
def test_to(self):
|
||||||
self.spin['from'] = 0
|
self.spin['from'] = 0
|
||||||
self.spin['to'] = 5
|
self.spin['to'] = 5
|
||||||
self.spin.set(4)
|
self.spin.set(4)
|
||||||
|
@ -1179,7 +1179,7 @@ class SpinboxTest(EntryTest, unittest.TestCase):
|
||||||
self._click_increment_arrow() # 5
|
self._click_increment_arrow() # 5
|
||||||
self.assertEqual(self.spin.get(), '5')
|
self.assertEqual(self.spin.get(), '5')
|
||||||
|
|
||||||
def test_configure_from(self):
|
def test_from(self):
|
||||||
self.spin['from'] = 1
|
self.spin['from'] = 1
|
||||||
self.spin['to'] = 10
|
self.spin['to'] = 10
|
||||||
self.spin.set(2)
|
self.spin.set(2)
|
||||||
|
@ -1189,7 +1189,7 @@ class SpinboxTest(EntryTest, unittest.TestCase):
|
||||||
self._click_decrement_arrow() # 1
|
self._click_decrement_arrow() # 1
|
||||||
self.assertEqual(self.spin.get(), '1')
|
self.assertEqual(self.spin.get(), '1')
|
||||||
|
|
||||||
def test_configure_increment(self):
|
def test_increment(self):
|
||||||
self.spin['from'] = 0
|
self.spin['from'] = 0
|
||||||
self.spin['to'] = 10
|
self.spin['to'] = 10
|
||||||
self.spin['increment'] = 4
|
self.spin['increment'] = 4
|
||||||
|
@ -1203,7 +1203,7 @@ class SpinboxTest(EntryTest, unittest.TestCase):
|
||||||
self._click_decrement_arrow() # 3
|
self._click_decrement_arrow() # 3
|
||||||
self.assertEqual(self.spin.get(), '3')
|
self.assertEqual(self.spin.get(), '3')
|
||||||
|
|
||||||
def test_configure_format(self):
|
def test_format(self):
|
||||||
self.spin.set(1)
|
self.spin.set(1)
|
||||||
self.spin['format'] = '%10.3f'
|
self.spin['format'] = '%10.3f'
|
||||||
self.spin.update()
|
self.spin.update()
|
||||||
|
@ -1220,7 +1220,7 @@ class SpinboxTest(EntryTest, unittest.TestCase):
|
||||||
self.assertTrue('.' not in value)
|
self.assertTrue('.' not in value)
|
||||||
self.assertEqual(len(value), 1)
|
self.assertEqual(len(value), 1)
|
||||||
|
|
||||||
def test_configure_wrap(self):
|
def test_wrap(self):
|
||||||
self.spin['to'] = 10
|
self.spin['to'] = 10
|
||||||
self.spin['from'] = 1
|
self.spin['from'] = 1
|
||||||
self.spin.set(1)
|
self.spin.set(1)
|
||||||
|
@ -1239,7 +1239,7 @@ class SpinboxTest(EntryTest, unittest.TestCase):
|
||||||
self._click_decrement_arrow()
|
self._click_decrement_arrow()
|
||||||
self.assertEqual(self.spin.get(), '1')
|
self.assertEqual(self.spin.get(), '1')
|
||||||
|
|
||||||
def test_configure_values(self):
|
def test_values(self):
|
||||||
self.assertEqual(self.spin['values'],
|
self.assertEqual(self.spin['values'],
|
||||||
() if tcl_version < (8, 5) else '')
|
() if tcl_version < (8, 5) else '')
|
||||||
self.checkParam(self.spin, 'values', 'mon tue wed thur',
|
self.checkParam(self.spin, 'values', 'mon tue wed thur',
|
||||||
|
@ -1299,14 +1299,14 @@ class TreeviewTest(AbstractWidgetTest, unittest.TestCase):
|
||||||
def create(self, **kwargs):
|
def create(self, **kwargs):
|
||||||
return ttk.Treeview(self.root, **kwargs)
|
return ttk.Treeview(self.root, **kwargs)
|
||||||
|
|
||||||
def test_configure_columns(self):
|
def test_columns(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkParam(widget, 'columns', 'a b c',
|
self.checkParam(widget, 'columns', 'a b c',
|
||||||
expected=('a', 'b', 'c'))
|
expected=('a', 'b', 'c'))
|
||||||
self.checkParam(widget, 'columns', ('a', 'b', 'c'))
|
self.checkParam(widget, 'columns', ('a', 'b', 'c'))
|
||||||
self.checkParam(widget, 'columns', '')
|
self.checkParam(widget, 'columns', '')
|
||||||
|
|
||||||
def test_configure_displaycolumns(self):
|
def test_displaycolumns(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
widget['columns'] = ('a', 'b', 'c')
|
widget['columns'] = ('a', 'b', 'c')
|
||||||
self.checkParam(widget, 'displaycolumns', 'b a c',
|
self.checkParam(widget, 'displaycolumns', 'b a c',
|
||||||
|
@ -1322,17 +1322,17 @@ class TreeviewTest(AbstractWidgetTest, unittest.TestCase):
|
||||||
self.checkInvalidParam(widget, 'displaycolumns', (1, -2),
|
self.checkInvalidParam(widget, 'displaycolumns', (1, -2),
|
||||||
errmsg='Column index -2 out of bounds')
|
errmsg='Column index -2 out of bounds')
|
||||||
|
|
||||||
def test_configure_height(self):
|
def test_height(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkPixelsParam(widget, 'height', 100, -100, 0, '3c', conv=False)
|
self.checkPixelsParam(widget, 'height', 100, -100, 0, '3c', conv=False)
|
||||||
self.checkPixelsParam(widget, 'height', 101.2, 102.6, conv=noconv)
|
self.checkPixelsParam(widget, 'height', 101.2, 102.6, conv=noconv)
|
||||||
|
|
||||||
def test_configure_selectmode(self):
|
def test_selectmode(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkEnumParam(widget, 'selectmode',
|
self.checkEnumParam(widget, 'selectmode',
|
||||||
'none', 'browse', 'extended')
|
'none', 'browse', 'extended')
|
||||||
|
|
||||||
def test_configure_show(self):
|
def test_show(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkParam(widget, 'show', 'tree headings',
|
self.checkParam(widget, 'show', 'tree headings',
|
||||||
expected=('tree', 'headings'))
|
expected=('tree', 'headings'))
|
||||||
|
|
|
@ -242,31 +242,31 @@ class StandardOptionsTests:
|
||||||
'underline', 'wraplength', 'xscrollcommand', 'yscrollcommand',
|
'underline', 'wraplength', 'xscrollcommand', 'yscrollcommand',
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_configure_activebackground(self):
|
def test_activebackground(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkColorParam(widget, 'activebackground')
|
self.checkColorParam(widget, 'activebackground')
|
||||||
|
|
||||||
def test_configure_activeborderwidth(self):
|
def test_activeborderwidth(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkPixelsParam(widget, 'activeborderwidth',
|
self.checkPixelsParam(widget, 'activeborderwidth',
|
||||||
0, 1.3, 2.9, 6, -2, '10p')
|
0, 1.3, 2.9, 6, -2, '10p')
|
||||||
|
|
||||||
def test_configure_activeforeground(self):
|
def test_activeforeground(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkColorParam(widget, 'activeforeground')
|
self.checkColorParam(widget, 'activeforeground')
|
||||||
|
|
||||||
def test_configure_anchor(self):
|
def test_anchor(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkEnumParam(widget, 'anchor',
|
self.checkEnumParam(widget, 'anchor',
|
||||||
'n', 'ne', 'e', 'se', 's', 'sw', 'w', 'nw', 'center')
|
'n', 'ne', 'e', 'se', 's', 'sw', 'w', 'nw', 'center')
|
||||||
|
|
||||||
def test_configure_background(self):
|
def test_background(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkColorParam(widget, 'background')
|
self.checkColorParam(widget, 'background')
|
||||||
if 'bg' in self.OPTIONS:
|
if 'bg' in self.OPTIONS:
|
||||||
self.checkColorParam(widget, 'bg')
|
self.checkColorParam(widget, 'bg')
|
||||||
|
|
||||||
def test_configure_bitmap(self):
|
def test_bitmap(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkParam(widget, 'bitmap', 'questhead')
|
self.checkParam(widget, 'bitmap', 'questhead')
|
||||||
self.checkParam(widget, 'bitmap', 'gray50')
|
self.checkParam(widget, 'bitmap', 'gray50')
|
||||||
|
@ -279,88 +279,88 @@ class StandardOptionsTests:
|
||||||
self.checkInvalidParam(widget, 'bitmap', 'spam',
|
self.checkInvalidParam(widget, 'bitmap', 'spam',
|
||||||
errmsg='bitmap "spam" not defined')
|
errmsg='bitmap "spam" not defined')
|
||||||
|
|
||||||
def test_configure_borderwidth(self):
|
def test_borderwidth(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkPixelsParam(widget, 'borderwidth',
|
self.checkPixelsParam(widget, 'borderwidth',
|
||||||
0, 1.3, 2.6, 6, -2, '10p')
|
0, 1.3, 2.6, 6, -2, '10p')
|
||||||
if 'bd' in self.OPTIONS:
|
if 'bd' in self.OPTIONS:
|
||||||
self.checkPixelsParam(widget, 'bd', 0, 1.3, 2.6, 6, -2, '10p')
|
self.checkPixelsParam(widget, 'bd', 0, 1.3, 2.6, 6, -2, '10p')
|
||||||
|
|
||||||
def test_configure_compound(self):
|
def test_compound(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkEnumParam(widget, 'compound',
|
self.checkEnumParam(widget, 'compound',
|
||||||
'bottom', 'center', 'left', 'none', 'right', 'top')
|
'bottom', 'center', 'left', 'none', 'right', 'top')
|
||||||
|
|
||||||
def test_configure_cursor(self):
|
def test_cursor(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkCursorParam(widget, 'cursor')
|
self.checkCursorParam(widget, 'cursor')
|
||||||
|
|
||||||
def test_configure_disabledforeground(self):
|
def test_disabledforeground(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkColorParam(widget, 'disabledforeground')
|
self.checkColorParam(widget, 'disabledforeground')
|
||||||
|
|
||||||
def test_configure_exportselection(self):
|
def test_exportselection(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkBooleanParam(widget, 'exportselection')
|
self.checkBooleanParam(widget, 'exportselection')
|
||||||
|
|
||||||
def test_configure_font(self):
|
def test_font(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkParam(widget, 'font',
|
self.checkParam(widget, 'font',
|
||||||
'-Adobe-Helvetica-Medium-R-Normal--*-120-*-*-*-*-*-*')
|
'-Adobe-Helvetica-Medium-R-Normal--*-120-*-*-*-*-*-*')
|
||||||
self.checkInvalidParam(widget, 'font', '',
|
self.checkInvalidParam(widget, 'font', '',
|
||||||
errmsg='font "" doesn\'t exist')
|
errmsg='font "" doesn\'t exist')
|
||||||
|
|
||||||
def test_configure_foreground(self):
|
def test_foreground(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkColorParam(widget, 'foreground')
|
self.checkColorParam(widget, 'foreground')
|
||||||
if 'fg' in self.OPTIONS:
|
if 'fg' in self.OPTIONS:
|
||||||
self.checkColorParam(widget, 'fg')
|
self.checkColorParam(widget, 'fg')
|
||||||
|
|
||||||
def test_configure_highlightbackground(self):
|
def test_highlightbackground(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkColorParam(widget, 'highlightbackground')
|
self.checkColorParam(widget, 'highlightbackground')
|
||||||
|
|
||||||
def test_configure_highlightcolor(self):
|
def test_highlightcolor(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkColorParam(widget, 'highlightcolor')
|
self.checkColorParam(widget, 'highlightcolor')
|
||||||
|
|
||||||
def test_configure_highlightthickness(self):
|
def test_highlightthickness(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkPixelsParam(widget, 'highlightthickness',
|
self.checkPixelsParam(widget, 'highlightthickness',
|
||||||
0, 1.3, 2.6, 6, '10p')
|
0, 1.3, 2.6, 6, '10p')
|
||||||
self.checkParam(widget, 'highlightthickness', -2, expected=0,
|
self.checkParam(widget, 'highlightthickness', -2, expected=0,
|
||||||
conv=self._conv_pixels)
|
conv=self._conv_pixels)
|
||||||
|
|
||||||
def test_configure_image(self):
|
def test_image(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkImageParam(widget, 'image')
|
self.checkImageParam(widget, 'image')
|
||||||
|
|
||||||
def test_configure_insertbackground(self):
|
def test_insertbackground(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkColorParam(widget, 'insertbackground')
|
self.checkColorParam(widget, 'insertbackground')
|
||||||
|
|
||||||
def test_configure_insertborderwidth(self):
|
def test_insertborderwidth(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkPixelsParam(widget, 'insertborderwidth',
|
self.checkPixelsParam(widget, 'insertborderwidth',
|
||||||
0, 1.3, 2.6, 6, -2, '10p')
|
0, 1.3, 2.6, 6, -2, '10p')
|
||||||
|
|
||||||
def test_configure_insertofftime(self):
|
def test_insertofftime(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkIntegerParam(widget, 'insertofftime', 100)
|
self.checkIntegerParam(widget, 'insertofftime', 100)
|
||||||
|
|
||||||
def test_configure_insertontime(self):
|
def test_insertontime(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkIntegerParam(widget, 'insertontime', 100)
|
self.checkIntegerParam(widget, 'insertontime', 100)
|
||||||
|
|
||||||
def test_configure_insertwidth(self):
|
def test_insertwidth(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkPixelsParam(widget, 'insertwidth', 1.3, 2.6, -2, '10p')
|
self.checkPixelsParam(widget, 'insertwidth', 1.3, 2.6, -2, '10p')
|
||||||
|
|
||||||
def test_configure_jump(self):
|
def test_jump(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkBooleanParam(widget, 'jump')
|
self.checkBooleanParam(widget, 'jump')
|
||||||
|
|
||||||
def test_configure_justify(self):
|
def test_justify(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkEnumParam(widget, 'justify', 'left', 'right', 'center',
|
self.checkEnumParam(widget, 'justify', 'left', 'right', 'center',
|
||||||
errmsg='bad justification "{}": must be '
|
errmsg='bad justification "{}": must be '
|
||||||
|
@ -369,155 +369,154 @@ class StandardOptionsTests:
|
||||||
errmsg='ambiguous justification "": must be '
|
errmsg='ambiguous justification "": must be '
|
||||||
'left, right, or center')
|
'left, right, or center')
|
||||||
|
|
||||||
def test_configure_orient(self):
|
def test_orient(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.assertEqual(str(widget['orient']), self.default_orient)
|
self.assertEqual(str(widget['orient']), self.default_orient)
|
||||||
self.checkEnumParam(widget, 'orient', 'horizontal', 'vertical')
|
self.checkEnumParam(widget, 'orient', 'horizontal', 'vertical')
|
||||||
|
|
||||||
def test_configure_padx(self):
|
def test_padx(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkPixelsParam(widget, 'padx', 3, 4.4, 5.6, -2, '12m',
|
self.checkPixelsParam(widget, 'padx', 3, 4.4, 5.6, -2, '12m',
|
||||||
conv=self._conv_pad_pixels)
|
conv=self._conv_pad_pixels)
|
||||||
|
|
||||||
def test_configure_pady(self):
|
def test_pady(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkPixelsParam(widget, 'pady', 3, 4.4, 5.6, -2, '12m',
|
self.checkPixelsParam(widget, 'pady', 3, 4.4, 5.6, -2, '12m',
|
||||||
conv=self._conv_pad_pixels)
|
conv=self._conv_pad_pixels)
|
||||||
|
|
||||||
def test_configure_relief(self):
|
def test_relief(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkReliefParam(widget, 'relief')
|
self.checkReliefParam(widget, 'relief')
|
||||||
|
|
||||||
def test_configure_repeatdelay(self):
|
def test_repeatdelay(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkIntegerParam(widget, 'repeatdelay', -500, 500)
|
self.checkIntegerParam(widget, 'repeatdelay', -500, 500)
|
||||||
|
|
||||||
def test_configure_repeatinterval(self):
|
def test_repeatinterval(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkIntegerParam(widget, 'repeatinterval', -500, 500)
|
self.checkIntegerParam(widget, 'repeatinterval', -500, 500)
|
||||||
|
|
||||||
def test_configure_selectbackground(self):
|
def test_selectbackground(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkColorParam(widget, 'selectbackground')
|
self.checkColorParam(widget, 'selectbackground')
|
||||||
|
|
||||||
def test_configure_selectborderwidth(self):
|
def test_selectborderwidth(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkPixelsParam(widget, 'selectborderwidth', 1.3, 2.6, -2, '10p')
|
self.checkPixelsParam(widget, 'selectborderwidth', 1.3, 2.6, -2, '10p')
|
||||||
|
|
||||||
def test_configure_selectforeground(self):
|
def test_selectforeground(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkColorParam(widget, 'selectforeground')
|
self.checkColorParam(widget, 'selectforeground')
|
||||||
|
|
||||||
def test_configure_setgrid(self):
|
def test_setgrid(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkBooleanParam(widget, 'setgrid')
|
self.checkBooleanParam(widget, 'setgrid')
|
||||||
|
|
||||||
def test_configure_state(self):
|
def test_state(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkEnumParam(widget, 'state', 'active', 'disabled', 'normal')
|
self.checkEnumParam(widget, 'state', 'active', 'disabled', 'normal')
|
||||||
|
|
||||||
def test_configure_takefocus(self):
|
def test_takefocus(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkParams(widget, 'takefocus', '0', '1', '')
|
self.checkParams(widget, 'takefocus', '0', '1', '')
|
||||||
|
|
||||||
def test_configure_text(self):
|
def test_text(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkParams(widget, 'text', '', 'any string')
|
self.checkParams(widget, 'text', '', 'any string')
|
||||||
|
|
||||||
def test_configure_textvariable(self):
|
def test_textvariable(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
var = tkinter.StringVar(self.root)
|
var = tkinter.StringVar(self.root)
|
||||||
self.checkVariableParam(widget, 'textvariable', var)
|
self.checkVariableParam(widget, 'textvariable', var)
|
||||||
|
|
||||||
def test_configure_troughcolor(self):
|
def test_troughcolor(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkColorParam(widget, 'troughcolor')
|
self.checkColorParam(widget, 'troughcolor')
|
||||||
|
|
||||||
def test_configure_underline(self):
|
def test_underline(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkIntegerParam(widget, 'underline', 0, 1, 10)
|
self.checkIntegerParam(widget, 'underline', 0, 1, 10)
|
||||||
|
|
||||||
def test_configure_wraplength(self):
|
def test_wraplength(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkPixelsParam(widget, 'wraplength', 100)
|
self.checkPixelsParam(widget, 'wraplength', 100)
|
||||||
|
|
||||||
def test_configure_xscrollcommand(self):
|
def test_xscrollcommand(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkCommandParam(widget, 'xscrollcommand')
|
self.checkCommandParam(widget, 'xscrollcommand')
|
||||||
|
|
||||||
def test_configure_yscrollcommand(self):
|
def test_yscrollcommand(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkCommandParam(widget, 'yscrollcommand')
|
self.checkCommandParam(widget, 'yscrollcommand')
|
||||||
|
|
||||||
# non-standard but common options
|
# non-standard but common options
|
||||||
|
|
||||||
def test_configure_command(self):
|
def test_command(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkCommandParam(widget, 'command')
|
self.checkCommandParam(widget, 'command')
|
||||||
|
|
||||||
def test_configure_indicatoron(self):
|
def test_indicatoron(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkBooleanParam(widget, 'indicatoron')
|
self.checkBooleanParam(widget, 'indicatoron')
|
||||||
|
|
||||||
def test_configure_offrelief(self):
|
def test_offrelief(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkReliefParam(widget, 'offrelief')
|
self.checkReliefParam(widget, 'offrelief')
|
||||||
|
|
||||||
def test_configure_overrelief(self):
|
def test_overrelief(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkReliefParam(widget, 'overrelief')
|
self.checkReliefParam(widget, 'overrelief')
|
||||||
|
|
||||||
def test_configure_selectcolor(self):
|
def test_selectcolor(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkColorParam(widget, 'selectcolor')
|
self.checkColorParam(widget, 'selectcolor')
|
||||||
|
|
||||||
def test_configure_selectimage(self):
|
def test_selectimage(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkImageParam(widget, 'selectimage')
|
self.checkImageParam(widget, 'selectimage')
|
||||||
|
|
||||||
@requires_tcl(8, 5)
|
@requires_tcl(8, 5)
|
||||||
def test_configure_tristateimage(self):
|
def test_tristateimage(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkImageParam(widget, 'tristateimage')
|
self.checkImageParam(widget, 'tristateimage')
|
||||||
|
|
||||||
@requires_tcl(8, 5)
|
@requires_tcl(8, 5)
|
||||||
def test_configure_tristatevalue(self):
|
def test_tristatevalue(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkParam(widget, 'tristatevalue', 'unknowable')
|
self.checkParam(widget, 'tristatevalue', 'unknowable')
|
||||||
|
|
||||||
def test_configure_variable(self):
|
def test_variable(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
var = tkinter.DoubleVar(self.root)
|
var = tkinter.DoubleVar(self.root)
|
||||||
self.checkVariableParam(widget, 'variable', var)
|
self.checkVariableParam(widget, 'variable', var)
|
||||||
|
|
||||||
|
|
||||||
class IntegerSizeTests:
|
class IntegerSizeTests:
|
||||||
def test_configure_height(self):
|
def test_height(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkIntegerParam(widget, 'height', 100, -100, 0)
|
self.checkIntegerParam(widget, 'height', 100, -100, 0)
|
||||||
|
|
||||||
def test_configure_width(self):
|
def test_width(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkIntegerParam(widget, 'width', 402, -402, 0)
|
self.checkIntegerParam(widget, 'width', 402, -402, 0)
|
||||||
|
|
||||||
|
|
||||||
class PixelSizeTests:
|
class PixelSizeTests:
|
||||||
def test_configure_height(self):
|
def test_height(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkPixelsParam(widget, 'height', 100, 101.2, 102.6, -100, 0, '3c')
|
self.checkPixelsParam(widget, 'height', 100, 101.2, 102.6, -100, 0, '3c')
|
||||||
|
|
||||||
def test_configure_width(self):
|
def test_width(self):
|
||||||
widget = self.create()
|
widget = self.create()
|
||||||
self.checkPixelsParam(widget, 'width', 402, 403.4, 404.6, -402, 0, '5i')
|
self.checkPixelsParam(widget, 'width', 402, 403.4, 404.6, -402, 0, '5i')
|
||||||
|
|
||||||
|
|
||||||
def add_standard_options(*source_classes):
|
def add_standard_options(*source_classes):
|
||||||
# This decorator adds test_configure_xxx methods from source classes for
|
# This decorator adds test_xxx methods from source classes for every xxx
|
||||||
# every xxx option in the OPTIONS class attribute if they are not defined
|
# option in the OPTIONS class attribute if they are not defined explicitly.
|
||||||
# explicitly.
|
|
||||||
def decorator(cls):
|
def decorator(cls):
|
||||||
for option in cls.OPTIONS:
|
for option in cls.OPTIONS:
|
||||||
methodname = 'test_configure_' + option
|
methodname = 'test_' + option
|
||||||
if not hasattr(cls, methodname):
|
if not hasattr(cls, methodname):
|
||||||
for source_class in source_classes:
|
for source_class in source_classes:
|
||||||
if hasattr(source_class, methodname):
|
if hasattr(source_class, methodname):
|
||||||
|
|
|
@ -386,7 +386,7 @@ class TixWidget(tkinter.Widget):
|
||||||
self.tk.call(name, 'configure', '-' + option, value)
|
self.tk.call(name, 'configure', '-' + option, value)
|
||||||
# These are missing from Tkinter
|
# These are missing from Tkinter
|
||||||
def image_create(self, imgtype, cnf={}, master=None, **kw):
|
def image_create(self, imgtype, cnf={}, master=None, **kw):
|
||||||
if master is None:
|
if not master:
|
||||||
master = self
|
master = self
|
||||||
if kw and cnf: cnf = _cnfmerge((cnf, kw))
|
if kw and cnf: cnf = _cnfmerge((cnf, kw))
|
||||||
elif kw: cnf = kw
|
elif kw: cnf = kw
|
||||||
|
@ -467,7 +467,7 @@ class DisplayStyle:
|
||||||
(multiple) Display Items"""
|
(multiple) Display Items"""
|
||||||
|
|
||||||
def __init__(self, itemtype, cnf={}, *, master=None, **kw):
|
def __init__(self, itemtype, cnf={}, *, master=None, **kw):
|
||||||
if master is None:
|
if not master:
|
||||||
if 'refwindow' in kw:
|
if 'refwindow' in kw:
|
||||||
master = kw['refwindow']
|
master = kw['refwindow']
|
||||||
elif 'refwindow' in cnf:
|
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))
|
return self.tk.call(self._w, 'add', entry, *self._options(cnf, kw))
|
||||||
|
|
||||||
def add_child(self, parent=None, cnf={}, **kw):
|
def add_child(self, parent=None, cnf={}, **kw):
|
||||||
if parent is None:
|
if not parent:
|
||||||
parent = ''
|
parent = ''
|
||||||
return self.tk.call(
|
return self.tk.call(
|
||||||
self._w, 'addchild', parent, *self._options(cnf, kw))
|
self._w, 'addchild', parent, *self._options(cnf, kw))
|
||||||
|
|
|
@ -569,7 +569,7 @@ class Widget(tkinter.Widget):
|
||||||
matches statespec. statespec is expected to be a sequence."""
|
matches statespec. statespec is expected to be a sequence."""
|
||||||
ret = self.tk.getboolean(
|
ret = self.tk.getboolean(
|
||||||
self.tk.call(self._w, "instate", ' '.join(statespec)))
|
self.tk.call(self._w, "instate", ' '.join(statespec)))
|
||||||
if ret and callback is not None:
|
if ret and callback:
|
||||||
return callback(*args, **kw)
|
return callback(*args, **kw)
|
||||||
|
|
||||||
return ret
|
return ret
|
||||||
|
|
|
@ -544,9 +544,8 @@ def TypeAlias(self, parameters):
|
||||||
|
|
||||||
@_SpecialForm
|
@_SpecialForm
|
||||||
def Concatenate(self, parameters):
|
def Concatenate(self, parameters):
|
||||||
"""Used in conjunction with ``ParamSpec`` and ``Callable`` to represent a
|
"""Used in conjunction with ParamSpec and Callable to represent a higher
|
||||||
higher order function which adds, removes or transforms parameters of a
|
order function which adds, removes or transforms parameters of a Callable.
|
||||||
callable.
|
|
||||||
|
|
||||||
For example::
|
For example::
|
||||||
|
|
||||||
|
@ -736,11 +735,11 @@ class ParamSpec(_Final, _Immutable, _TypeVarLike, _root=True):
|
||||||
|
|
||||||
Parameter specification variables exist primarily for the benefit of static
|
Parameter specification variables exist primarily for the benefit of static
|
||||||
type checkers. They are used to forward the parameter types of one
|
type checkers. They are used to forward the parameter types of one
|
||||||
callable to another callable, a pattern commonly found in higher order
|
Callable to another Callable, a pattern commonly found in higher order
|
||||||
functions and decorators. They are only valid when used in ``Concatenate``,
|
functions and decorators. They are only valid when used in Concatenate, or
|
||||||
or s the first argument to ``Callable``, or as parameters for user-defined
|
as the first argument to Callable, or as parameters for user-defined Generics.
|
||||||
Generics. See class Generic for more information on generic types. An
|
See class Generic for more information on generic types. An example for
|
||||||
example for annotating a decorator::
|
annotating a decorator::
|
||||||
|
|
||||||
T = TypeVar('T')
|
T = TypeVar('T')
|
||||||
P = ParamSpec('P')
|
P = ParamSpec('P')
|
||||||
|
@ -1250,7 +1249,7 @@ def _no_init(self, *args, **kwargs):
|
||||||
raise TypeError('Protocols cannot be instantiated')
|
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.
|
"""Allow instance and class checks for special stdlib modules.
|
||||||
|
|
||||||
The abc and functools modules indiscriminately call isinstance() and
|
The abc and functools modules indiscriminately call isinstance() and
|
||||||
|
@ -1339,12 +1338,12 @@ class Protocol(Generic, metaclass=_ProtocolMeta):
|
||||||
|
|
||||||
# First, perform various sanity checks.
|
# First, perform various sanity checks.
|
||||||
if not getattr(cls, '_is_runtime_protocol', False):
|
if not getattr(cls, '_is_runtime_protocol', False):
|
||||||
if _allow_reckless_class_checks():
|
if _allow_reckless_class_cheks():
|
||||||
return NotImplemented
|
return NotImplemented
|
||||||
raise TypeError("Instance and class checks can only be used with"
|
raise TypeError("Instance and class checks can only be used with"
|
||||||
" @runtime_checkable protocols")
|
" @runtime_checkable protocols")
|
||||||
if not _is_callable_members_only(cls):
|
if not _is_callable_members_only(cls):
|
||||||
if _allow_reckless_class_checks():
|
if _allow_reckless_class_cheks():
|
||||||
return NotImplemented
|
return NotImplemented
|
||||||
raise TypeError("Protocols with non-method members"
|
raise TypeError("Protocols with non-method members"
|
||||||
" don't support issubclass()")
|
" don't support issubclass()")
|
||||||
|
@ -1669,8 +1668,6 @@ def get_origin(tp):
|
||||||
return tp.__origin__
|
return tp.__origin__
|
||||||
if tp is Generic:
|
if tp is Generic:
|
||||||
return Generic
|
return Generic
|
||||||
if isinstance(tp, types.Union):
|
|
||||||
return types.Union
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
@ -1687,14 +1684,12 @@ def get_args(tp):
|
||||||
"""
|
"""
|
||||||
if isinstance(tp, _AnnotatedAlias):
|
if isinstance(tp, _AnnotatedAlias):
|
||||||
return (tp.__origin__,) + tp.__metadata__
|
return (tp.__origin__,) + tp.__metadata__
|
||||||
if isinstance(tp, (_GenericAlias, GenericAlias)):
|
if isinstance(tp, _GenericAlias):
|
||||||
res = tp.__args__
|
res = tp.__args__
|
||||||
if (tp.__origin__ is collections.abc.Callable
|
if tp.__origin__ is collections.abc.Callable and res[0] is not Ellipsis:
|
||||||
and not (res[0] is Ellipsis
|
|
||||||
or isinstance(res[0], (ParamSpec, _ConcatenateGenericAlias)))):
|
|
||||||
res = (list(res[:-1]), res[-1])
|
res = (list(res[:-1]), res[-1])
|
||||||
return res
|
return res
|
||||||
if isinstance(tp, types.Union):
|
if isinstance(tp, GenericAlias):
|
||||||
return tp.__args__
|
return tp.__args__
|
||||||
return ()
|
return ()
|
||||||
|
|
||||||
|
|
|
@ -773,11 +773,7 @@ def _parse_proxy(proxy):
|
||||||
raise ValueError("proxy URL with no authority: %r" % proxy)
|
raise ValueError("proxy URL with no authority: %r" % proxy)
|
||||||
# We have an authority, so for RFC 3986-compliant URLs (by ss 3.
|
# We have an authority, so for RFC 3986-compliant URLs (by ss 3.
|
||||||
# and 3.3.), path is empty or starts with '/'
|
# and 3.3.), path is empty or starts with '/'
|
||||||
if '@' in r_scheme:
|
end = r_scheme.find("/", 2)
|
||||||
host_separator = r_scheme.find('@')
|
|
||||||
end = r_scheme.find("/", host_separator)
|
|
||||||
else:
|
|
||||||
end = r_scheme.find("/", 2)
|
|
||||||
if end == -1:
|
if end == -1:
|
||||||
end = None
|
end = None
|
||||||
authority = r_scheme[2:end]
|
authority = r_scheme[2:end]
|
||||||
|
|
|
@ -242,12 +242,15 @@ def library_recipes():
|
||||||
|
|
||||||
result.extend([
|
result.extend([
|
||||||
dict(
|
dict(
|
||||||
name="OpenSSL 1.1.1i",
|
name="OpenSSL 1.1.1g",
|
||||||
url="https://www.openssl.org/source/openssl-1.1.1i.tar.gz",
|
url="https://www.openssl.org/source/openssl-1.1.1g.tar.gz",
|
||||||
checksum='08987c3cf125202e2b0840035efb392c',
|
checksum='76766e98997660138cdaf13a187bd234',
|
||||||
buildrecipe=build_universal_openssl,
|
buildrecipe=build_universal_openssl,
|
||||||
configure=None,
|
configure=None,
|
||||||
install=None,
|
install=None,
|
||||||
|
patches=[
|
||||||
|
"openssl-mac-arm64.patch",
|
||||||
|
],
|
||||||
),
|
),
|
||||||
])
|
])
|
||||||
|
|
||||||
|
@ -260,10 +263,10 @@ def library_recipes():
|
||||||
tk_patches = ['tk868_on_10_8_10_9.patch']
|
tk_patches = ['tk868_on_10_8_10_9.patch']
|
||||||
|
|
||||||
else:
|
else:
|
||||||
tcl_tk_ver='8.6.11'
|
tcl_tk_ver='8.6.10'
|
||||||
tcl_checksum='8a4c004f48984a03a7747e9ba06e4da4'
|
tcl_checksum='97c55573f8520bcab74e21bfd8d0aadc'
|
||||||
|
|
||||||
tk_checksum='c7ee71a2d05bba78dfffd76528dc17c6'
|
tk_checksum='602a47ad9ecac7bf655ada729d140a94'
|
||||||
tk_patches = [ ]
|
tk_patches = [ ]
|
||||||
|
|
||||||
|
|
||||||
|
@ -354,9 +357,9 @@ def library_recipes():
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
dict(
|
dict(
|
||||||
name="SQLite 3.34.0",
|
name="SQLite 3.33.0",
|
||||||
url="https://sqlite.org/2020/sqlite-autoconf-3340000.tar.gz",
|
url="https://sqlite.org/2020/sqlite-autoconf-3330000.tar.gz",
|
||||||
checksum='7f33c9db7b713957fcb9271fe9049fef',
|
checksum='842a8a100d7b01b09e543deb2b7951dd',
|
||||||
extra_cflags=('-Os '
|
extra_cflags=('-Os '
|
||||||
'-DSQLITE_ENABLE_FTS5 '
|
'-DSQLITE_ENABLE_FTS5 '
|
||||||
'-DSQLITE_ENABLE_FTS4 '
|
'-DSQLITE_ENABLE_FTS4 '
|
||||||
|
@ -1135,6 +1138,7 @@ def buildPythonDocs():
|
||||||
if not os.path.exists(htmlDir):
|
if not os.path.exists(htmlDir):
|
||||||
# Create virtual environment for docs builds with blurb and sphinx
|
# Create virtual environment for docs builds with blurb and sphinx
|
||||||
runCommand('make venv')
|
runCommand('make venv')
|
||||||
|
runCommand('venv/bin/python3 -m pip install -U Sphinx==2.3.1')
|
||||||
runCommand('make html PYTHON=venv/bin/python')
|
runCommand('make html PYTHON=venv/bin/python')
|
||||||
os.rename(htmlDir, docdir)
|
os.rename(htmlDir, docdir)
|
||||||
os.chdir(curDir)
|
os.chdir(curDir)
|
||||||
|
@ -1611,7 +1615,7 @@ def buildDMG():
|
||||||
if os.path.exists(outdir):
|
if os.path.exists(outdir):
|
||||||
shutil.rmtree(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
|
# installer file name. With the introduction of weaklinked installer
|
||||||
# variants, we may have two variants with the same file name, i.e.
|
# 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
|
# both ending in '10.9'. To avoid this, we now use the major/minor
|
||||||
|
|
|
@ -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"
|
|
@ -20,7 +20,7 @@ fi
|
||||||
# Make sure the directory ${PYTHON_ROOT}/bin is on the users PATH.
|
# Make sure the directory ${PYTHON_ROOT}/bin is on the users PATH.
|
||||||
BSH="`basename "${theShell}"`"
|
BSH="`basename "${theShell}"`"
|
||||||
case "${BSH}" in
|
case "${BSH}" in
|
||||||
bash|ksh|sh|*csh|zsh|fish)
|
bash|ksh|sh|*csh|zsh)
|
||||||
if [ `id -ur` = 0 ]; then
|
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'`
|
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
|
else
|
||||||
|
@ -76,22 +76,6 @@ bash)
|
||||||
PR="${HOME}/.bash_profile"
|
PR="${HOME}/.bash_profile"
|
||||||
fi
|
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)
|
zsh)
|
||||||
PR="${HOME}/.zprofile"
|
PR="${HOME}/.zprofile"
|
||||||
;;
|
;;
|
||||||
|
|
|
@ -36,7 +36,7 @@
|
||||||
<key>CFBundleExecutable</key>
|
<key>CFBundleExecutable</key>
|
||||||
<string>IDLE</string>
|
<string>IDLE</string>
|
||||||
<key>CFBundleGetInfoString</key>
|
<key>CFBundleGetInfoString</key>
|
||||||
<string>%version%, © 2001-2021 Python Software Foundation</string>
|
<string>%version%, © 2001-2020 Python Software Foundation</string>
|
||||||
<key>CFBundleIconFile</key>
|
<key>CFBundleIconFile</key>
|
||||||
<string>IDLE.icns</string>
|
<string>IDLE.icns</string>
|
||||||
<key>CFBundleIdentifier</key>
|
<key>CFBundleIdentifier</key>
|
||||||
|
|
|
@ -40,7 +40,7 @@
|
||||||
<key>CFBundleExecutable</key>
|
<key>CFBundleExecutable</key>
|
||||||
<string>Python Launcher</string>
|
<string>Python Launcher</string>
|
||||||
<key>CFBundleGetInfoString</key>
|
<key>CFBundleGetInfoString</key>
|
||||||
<string>%VERSION%, © 2001-2021 Python Software Foundation</string>
|
<string>%VERSION%, © 2001-2020 Python Software Foundation</string>
|
||||||
<key>CFBundleIconFile</key>
|
<key>CFBundleIconFile</key>
|
||||||
<string>PythonLauncher.icns</string>
|
<string>PythonLauncher.icns</string>
|
||||||
<key>CFBundleIdentifier</key>
|
<key>CFBundleIdentifier</key>
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue