mirror of https://github.com/python/cpython.git
Merge
This commit is contained in:
commit
24aa693c7e
|
@ -55,6 +55,8 @@ PC/python_nt*.h
|
||||||
PC/pythonnt_rc*.h
|
PC/pythonnt_rc*.h
|
||||||
PC/*.obj
|
PC/*.obj
|
||||||
PC/*.exe
|
PC/*.exe
|
||||||
|
PC/*/*.exe
|
||||||
|
PC/*/*.pdb
|
||||||
PC/*/*.user
|
PC/*/*.user
|
||||||
PC/*/*.ncb
|
PC/*/*.ncb
|
||||||
PC/*/*.suo
|
PC/*/*.suo
|
||||||
|
|
|
@ -1437,9 +1437,8 @@ The type constructor is responsible for initializing the weak reference list to
|
||||||
}
|
}
|
||||||
|
|
||||||
The only further addition is that the destructor needs to call the weak
|
The only further addition is that the destructor needs to call the weak
|
||||||
reference manager to clear any weak references. This should be done before any
|
reference manager to clear any weak references. This is only required if the
|
||||||
other parts of the destruction have occurred, but is only required if the weak
|
weak reference list is non-*NULL*::
|
||||||
reference list is non-*NULL*::
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
instance_dealloc(PyInstanceObject *inst)
|
instance_dealloc(PyInstanceObject *inst)
|
||||||
|
|
|
@ -42,8 +42,8 @@ An HMAC object has the following methods:
|
||||||
|
|
||||||
When comparing the output of :meth:`digest` to an externally-supplied
|
When comparing the output of :meth:`digest` to an externally-supplied
|
||||||
digest during a verification routine, it is recommended to use the
|
digest during a verification routine, it is recommended to use the
|
||||||
:func:`hmac.secure_compare` function instead of the ``==`` operator
|
:func:`compare_digest` function instead of the ``==`` operator
|
||||||
to avoid potential timing attacks.
|
to reduce the vulnerability to timing attacks.
|
||||||
|
|
||||||
|
|
||||||
.. method:: HMAC.hexdigest()
|
.. method:: HMAC.hexdigest()
|
||||||
|
@ -54,10 +54,11 @@ An HMAC object has the following methods:
|
||||||
|
|
||||||
.. warning::
|
.. warning::
|
||||||
|
|
||||||
When comparing the output of :meth:`hexdigest` to an externally-supplied
|
The output of :meth:`hexdigest` should not be compared directly to an
|
||||||
digest during a verification routine, it is recommended to use the
|
externally-supplied digest during a verification routine. Instead, the
|
||||||
:func:`hmac.secure_compare` function instead of the ``==`` operator
|
externally supplied digest should be converted to a :class:`bytes`
|
||||||
to avoid potential timing attacks.
|
value and compared to the output of :meth:`digest` with
|
||||||
|
:func:`compare_digest`.
|
||||||
|
|
||||||
|
|
||||||
.. method:: HMAC.copy()
|
.. method:: HMAC.copy()
|
||||||
|
@ -68,20 +69,28 @@ An HMAC object has the following methods:
|
||||||
|
|
||||||
This module also provides the following helper function:
|
This module also provides the following helper function:
|
||||||
|
|
||||||
.. function:: secure_compare(a, b)
|
.. function:: compare_digest(a, b)
|
||||||
|
|
||||||
Returns the equivalent of ``a == b``, but using a time-independent
|
Returns the equivalent of ``a == b``, but avoids content based
|
||||||
comparison method. Comparing the full lengths of the inputs *a* and *b*,
|
short circuiting behaviour to reduce the vulnerability to timing
|
||||||
instead of short-circuiting the comparison upon the first unequal byte,
|
analysis. The inputs must be :class:`bytes` instances.
|
||||||
prevents leaking information about the inputs being compared and mitigates
|
|
||||||
potential timing attacks. The inputs must be either :class:`str` or
|
Using a short circuiting comparison (that is, one that terminates as soon
|
||||||
:class:`bytes` instances.
|
as it finds any difference between the values) to check digests for
|
||||||
|
correctness can be problematic, as it introduces a potential
|
||||||
|
vulnerability when an attacker can control both the message to be checked
|
||||||
|
*and* the purported signature value. By keeping the plaintext consistent
|
||||||
|
and supplying different signature values, an attacker may be able to use
|
||||||
|
timing variations to search the signature space for the expected value in
|
||||||
|
O(n) time rather than the desired O(2**n).
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
|
|
||||||
While the :func:`hmac.secure_compare` function prevents leaking the
|
While this function reduces the likelihood of leaking the contents of
|
||||||
contents of the inputs via a timing attack, it does leak the length
|
the expected digest via a timing attack, it still uses short circuiting
|
||||||
of the inputs. However, this generally is not a security risk.
|
behaviour based on the *length* of the inputs. It is assumed that the
|
||||||
|
expected length of the digest is not a secret, as it is typically
|
||||||
|
published as part of a file format, network protocol or API definition.
|
||||||
|
|
||||||
.. versionadded:: 3.3
|
.. versionadded:: 3.3
|
||||||
|
|
||||||
|
|
|
@ -226,11 +226,11 @@ However, if you really do need to use some shared data then
|
||||||
holds Python objects and allows other processes to manipulate them using
|
holds Python objects and allows other processes to manipulate them using
|
||||||
proxies.
|
proxies.
|
||||||
|
|
||||||
A manager returned by :func:`Manager` will support types :class:`list`,
|
A manager returned by :func:`Manager` will support types
|
||||||
:class:`dict`, :class:`Namespace`, :class:`Lock`, :class:`RLock`,
|
:class:`list`, :class:`dict`, :class:`Namespace`, :class:`Lock`,
|
||||||
:class:`Semaphore`, :class:`BoundedSemaphore`, :class:`Condition`,
|
:class:`RLock`, :class:`Semaphore`, :class:`BoundedSemaphore`,
|
||||||
:class:`Event`, :class:`Queue`, :class:`Value` and :class:`Array`. For
|
:class:`Condition`, :class:`Event`, :class:`Barrier`,
|
||||||
example, ::
|
:class:`Queue`, :class:`Value` and :class:`Array`. For example, ::
|
||||||
|
|
||||||
from multiprocessing import Process, Manager
|
from multiprocessing import Process, Manager
|
||||||
|
|
||||||
|
@ -885,6 +885,12 @@ program as they are in a multithreaded program. See the documentation for
|
||||||
Note that one can also create synchronization primitives by using a manager
|
Note that one can also create synchronization primitives by using a manager
|
||||||
object -- see :ref:`multiprocessing-managers`.
|
object -- see :ref:`multiprocessing-managers`.
|
||||||
|
|
||||||
|
.. class:: Barrier(parties[, action[, timeout]])
|
||||||
|
|
||||||
|
A barrier object: a clone of :class:`threading.Barrier`.
|
||||||
|
|
||||||
|
.. versionadded:: 3.3
|
||||||
|
|
||||||
.. class:: BoundedSemaphore([value])
|
.. class:: BoundedSemaphore([value])
|
||||||
|
|
||||||
A bounded semaphore object: a clone of :class:`threading.BoundedSemaphore`.
|
A bounded semaphore object: a clone of :class:`threading.BoundedSemaphore`.
|
||||||
|
@ -1236,9 +1242,10 @@ their parent process exits. The manager classes are defined in the
|
||||||
type of shared object. This must be a string.
|
type of shared object. This must be a string.
|
||||||
|
|
||||||
*callable* is a callable used for creating objects for this type
|
*callable* is a callable used for creating objects for this type
|
||||||
identifier. If a manager instance will be created using the
|
identifier. If a manager instance will be connected to the
|
||||||
:meth:`from_address` classmethod or if the *create_method* argument is
|
server using the :meth:`connect` method, or if the
|
||||||
``False`` then this can be left as ``None``.
|
*create_method* argument is ``False`` then this can be left as
|
||||||
|
``None``.
|
||||||
|
|
||||||
*proxytype* is a subclass of :class:`BaseProxy` which is used to create
|
*proxytype* is a subclass of :class:`BaseProxy` which is used to create
|
||||||
proxies for shared objects with this *typeid*. If ``None`` then a proxy
|
proxies for shared objects with this *typeid*. If ``None`` then a proxy
|
||||||
|
@ -1279,6 +1286,13 @@ their parent process exits. The manager classes are defined in the
|
||||||
|
|
||||||
It also supports creation of shared lists and dictionaries.
|
It also supports creation of shared lists and dictionaries.
|
||||||
|
|
||||||
|
.. method:: Barrier(parties[, action[, timeout]])
|
||||||
|
|
||||||
|
Create a shared :class:`threading.Barrier` object and return a
|
||||||
|
proxy for it.
|
||||||
|
|
||||||
|
.. versionadded:: 3.3
|
||||||
|
|
||||||
.. method:: BoundedSemaphore([value])
|
.. method:: BoundedSemaphore([value])
|
||||||
|
|
||||||
Create a shared :class:`threading.BoundedSemaphore` object and return a
|
Create a shared :class:`threading.BoundedSemaphore` object and return a
|
||||||
|
|
|
@ -61,7 +61,7 @@ created. Socket addresses are represented as follows:
|
||||||
- A pair ``(host, port)`` is used for the :const:`AF_INET` address family,
|
- A pair ``(host, port)`` is used for the :const:`AF_INET` address family,
|
||||||
where *host* is a string representing either a hostname in Internet domain
|
where *host* is a string representing either a hostname in Internet domain
|
||||||
notation like ``'daring.cwi.nl'`` or an IPv4 address like ``'100.50.200.5'``,
|
notation like ``'daring.cwi.nl'`` or an IPv4 address like ``'100.50.200.5'``,
|
||||||
and *port* is an integral port number.
|
and *port* is an integer.
|
||||||
|
|
||||||
- For :const:`AF_INET6` address family, a four-tuple ``(host, port, flowinfo,
|
- For :const:`AF_INET6` address family, a four-tuple ``(host, port, flowinfo,
|
||||||
scopeid)`` is used, where *flowinfo* and *scopeid* represent the ``sin6_flowinfo``
|
scopeid)`` is used, where *flowinfo* and *scopeid* represent the ``sin6_flowinfo``
|
||||||
|
|
|
@ -77,6 +77,12 @@ An explanation of some terminology and conventions is in order.
|
||||||
|
|
||||||
See :class:`struct_time` for a description of these objects.
|
See :class:`struct_time` for a description of these objects.
|
||||||
|
|
||||||
|
.. versionchanged:: 3.3
|
||||||
|
|
||||||
|
The :class:`struct_time` type was extended to provide the
|
||||||
|
:attr:`tm_gmtoff` and :attr:`tm_zone` attributes when platform
|
||||||
|
supports corresponding ``struct tm`` members.
|
||||||
|
|
||||||
* Use the following functions to convert between time representations:
|
* Use the following functions to convert between time representations:
|
||||||
|
|
||||||
+-------------------------+-------------------------+-------------------------+
|
+-------------------------+-------------------------+-------------------------+
|
||||||
|
@ -160,30 +166,6 @@ The module defines the following functions and data items:
|
||||||
.. versionadded:: 3.3
|
.. versionadded:: 3.3
|
||||||
|
|
||||||
|
|
||||||
.. class:: clock_info
|
|
||||||
|
|
||||||
Clock information object returned by :func:`get_clock_info`.
|
|
||||||
|
|
||||||
.. attribute:: implementation
|
|
||||||
|
|
||||||
The name of the underlying C function used to get the clock value.
|
|
||||||
|
|
||||||
.. attribute:: monotonic
|
|
||||||
|
|
||||||
``True`` if the clock cannot go backward, ``False`` otherwise.
|
|
||||||
|
|
||||||
.. attribute:: adjusted
|
|
||||||
|
|
||||||
``True`` if the clock can be adjusted (e.g. by a NTP daemon), ``False``
|
|
||||||
otherwise.
|
|
||||||
|
|
||||||
.. attribute:: resolution
|
|
||||||
|
|
||||||
The resolution of the clock in seconds (:class:`float`).
|
|
||||||
|
|
||||||
.. versionadded:: 3.3
|
|
||||||
|
|
||||||
|
|
||||||
.. function:: clock_settime(clk_id, time)
|
.. function:: clock_settime(clk_id, time)
|
||||||
|
|
||||||
Set the time of the specified clock *clk_id*.
|
Set the time of the specified clock *clk_id*.
|
||||||
|
@ -267,7 +249,7 @@ The module defines the following functions and data items:
|
||||||
|
|
||||||
.. function:: get_clock_info(name)
|
.. function:: get_clock_info(name)
|
||||||
|
|
||||||
Get information on the specified clock as a :class:`clock_info` object.
|
Get information on the specified clock as a namespace object.
|
||||||
Supported clock names and the corresponding functions to read their value
|
Supported clock names and the corresponding functions to read their value
|
||||||
are:
|
are:
|
||||||
|
|
||||||
|
@ -277,6 +259,16 @@ The module defines the following functions and data items:
|
||||||
* ``'process_time'``: :func:`time.process_time`
|
* ``'process_time'``: :func:`time.process_time`
|
||||||
* ``'time'``: :func:`time.time`
|
* ``'time'``: :func:`time.time`
|
||||||
|
|
||||||
|
The result has the following attributes:
|
||||||
|
|
||||||
|
- *adjustable*: ``True`` if the clock can be changed automatically (e.g. by
|
||||||
|
a NTP daemon) or manually by the system administrator, ``False`` otherwise
|
||||||
|
- *implementation*: The name of the underlying C function used to get
|
||||||
|
the clock value
|
||||||
|
- *monotonic*: ``True`` if the clock cannot go backward,
|
||||||
|
``False`` otherwise
|
||||||
|
- *resolution*: The resolution of the clock in seconds (:class:`float`)
|
||||||
|
|
||||||
.. versionadded:: 3.3
|
.. versionadded:: 3.3
|
||||||
|
|
||||||
|
|
||||||
|
@ -350,7 +342,6 @@ The module defines the following functions and data items:
|
||||||
|
|
||||||
.. versionadded:: 3.3
|
.. versionadded:: 3.3
|
||||||
|
|
||||||
|
|
||||||
.. function:: sleep(secs)
|
.. function:: sleep(secs)
|
||||||
|
|
||||||
Suspend execution for the given number of seconds. The argument may be a
|
Suspend execution for the given number of seconds. The argument may be a
|
||||||
|
@ -447,6 +438,12 @@ The module defines the following functions and data items:
|
||||||
| ``%Y`` | Year with century as a decimal number. | |
|
| ``%Y`` | Year with century as a decimal number. | |
|
||||||
| | | |
|
| | | |
|
||||||
+-----------+------------------------------------------------+-------+
|
+-----------+------------------------------------------------+-------+
|
||||||
|
| ``%z`` | Time zone offset indicating a positive or | |
|
||||||
|
| | negative time difference from UTC/GMT of the | |
|
||||||
|
| | form +HHMM or -HHMM, where H represents decimal| |
|
||||||
|
| | hour digits and M represents decimal minute | |
|
||||||
|
| | digits [-23:59, +23:59]. | |
|
||||||
|
+-----------+------------------------------------------------+-------+
|
||||||
| ``%Z`` | Time zone name (no characters if no time zone | |
|
| ``%Z`` | Time zone name (no characters if no time zone | |
|
||||||
| | exists). | |
|
| | exists). | |
|
||||||
+-----------+------------------------------------------------+-------+
|
+-----------+------------------------------------------------+-------+
|
||||||
|
@ -546,6 +543,10 @@ The module defines the following functions and data items:
|
||||||
+-------+-------------------+---------------------------------+
|
+-------+-------------------+---------------------------------+
|
||||||
| 8 | :attr:`tm_isdst` | 0, 1 or -1; see below |
|
| 8 | :attr:`tm_isdst` | 0, 1 or -1; see below |
|
||||||
+-------+-------------------+---------------------------------+
|
+-------+-------------------+---------------------------------+
|
||||||
|
| N/A | :attr:`tm_zone` | abbreviation of timezone name |
|
||||||
|
+-------+-------------------+---------------------------------+
|
||||||
|
| N/A | :attr:`tm_gmtoff` | offset from UTC in seconds |
|
||||||
|
+-------+-------------------+---------------------------------+
|
||||||
|
|
||||||
Note that unlike the C structure, the month value is a range of [1, 12], not
|
Note that unlike the C structure, the month value is a range of [1, 12], not
|
||||||
[0, 11]. A ``-1`` argument as the daylight
|
[0, 11]. A ``-1`` argument as the daylight
|
||||||
|
@ -556,6 +557,11 @@ The module defines the following functions and data items:
|
||||||
:class:`struct_time`, or having elements of the wrong type, a
|
:class:`struct_time`, or having elements of the wrong type, a
|
||||||
:exc:`TypeError` is raised.
|
:exc:`TypeError` is raised.
|
||||||
|
|
||||||
|
.. versionchanged:: 3.3
|
||||||
|
|
||||||
|
:attr:`tm_gmtoff` and :attr:`tm_zone` attributes are avaliable on
|
||||||
|
platforms with C library supporting the corresponding fields in
|
||||||
|
``struct tm``.
|
||||||
|
|
||||||
.. function:: time()
|
.. function:: time()
|
||||||
|
|
||||||
|
@ -566,7 +572,6 @@ The module defines the following functions and data items:
|
||||||
lower value than a previous call if the system clock has been set back between
|
lower value than a previous call if the system clock has been set back between
|
||||||
the two calls.
|
the two calls.
|
||||||
|
|
||||||
|
|
||||||
.. data:: timezone
|
.. data:: timezone
|
||||||
|
|
||||||
The offset of the local (non-DST) timezone, in seconds west of UTC (negative in
|
The offset of the local (non-DST) timezone, in seconds west of UTC (negative in
|
||||||
|
|
|
@ -1484,9 +1484,11 @@ Major performance enhancements have been added:
|
||||||
* repeating a single ASCII letter and getting a substring of a ASCII strings
|
* repeating a single ASCII letter and getting a substring of a ASCII strings
|
||||||
is 4 times faster
|
is 4 times faster
|
||||||
|
|
||||||
* UTF-8 and UTF-16 decoding is now 2x to 4x faster.
|
* UTF-8 and UTF-16 decoding is now 2x to 4x faster. UTF-16 encoding is now
|
||||||
|
up to 10x faster.
|
||||||
|
|
||||||
(contributed by Serhiy Storchaka, :issue:`14624` and :issue:`14738`.)
|
(contributed by Serhiy Storchaka, :issue:`14624`, :issue:`14738` and
|
||||||
|
:issue:`15026`.)
|
||||||
|
|
||||||
|
|
||||||
Build and C API Changes
|
Build and C API Changes
|
||||||
|
|
|
@ -26,7 +26,7 @@ typedef struct {
|
||||||
typedef struct {
|
typedef struct {
|
||||||
const char *implementation;
|
const char *implementation;
|
||||||
int monotonic;
|
int monotonic;
|
||||||
int adjusted;
|
int adjustable;
|
||||||
double resolution;
|
double resolution;
|
||||||
} _Py_clock_info_t;
|
} _Py_clock_info_t;
|
||||||
|
|
||||||
|
|
|
@ -188,9 +188,9 @@ typedef unsigned char Py_UCS1;
|
||||||
(((((Py_UCS4)(high) & 0x03FF) << 10) | \
|
(((((Py_UCS4)(high) & 0x03FF) << 10) | \
|
||||||
((Py_UCS4)(low) & 0x03FF)) + 0x10000)
|
((Py_UCS4)(low) & 0x03FF)) + 0x10000)
|
||||||
/* high surrogate = top 10 bits added to D800 */
|
/* high surrogate = top 10 bits added to D800 */
|
||||||
#define Py_UNICODE_HIGH_SURROGATE(ch) (0xD800 | (((ch) - 0x10000) >> 10))
|
#define Py_UNICODE_HIGH_SURROGATE(ch) (0xD800 - (0x10000 >> 10) + ((ch) >> 10))
|
||||||
/* low surrogate = bottom 10 bits added to DC00 */
|
/* low surrogate = bottom 10 bits added to DC00 */
|
||||||
#define Py_UNICODE_LOW_SURROGATE(ch) (0xDC00 | (((ch) - 0x10000) & 0x3FF))
|
#define Py_UNICODE_LOW_SURROGATE(ch) (0xDC00 + ((ch) & 0x3FF))
|
||||||
|
|
||||||
/* Check if substring matches at given offset. The offset must be
|
/* Check if substring matches at given offset. The offset must be
|
||||||
valid, and the substring must not be empty. */
|
valid, and the substring must not be empty. */
|
||||||
|
|
|
@ -486,19 +486,19 @@ def _strptime(data_string, format="%a %b %d %H:%M:%S %Y"):
|
||||||
|
|
||||||
return (year, month, day,
|
return (year, month, day,
|
||||||
hour, minute, second,
|
hour, minute, second,
|
||||||
weekday, julian, tz, gmtoff, tzname), fraction
|
weekday, julian, tz, tzname, gmtoff), fraction
|
||||||
|
|
||||||
def _strptime_time(data_string, format="%a %b %d %H:%M:%S %Y"):
|
def _strptime_time(data_string, format="%a %b %d %H:%M:%S %Y"):
|
||||||
"""Return a time struct based on the input string and the
|
"""Return a time struct based on the input string and the
|
||||||
format string."""
|
format string."""
|
||||||
tt = _strptime(data_string, format)[0]
|
tt = _strptime(data_string, format)[0]
|
||||||
return time.struct_time(tt[:9])
|
return time.struct_time(tt[:time._STRUCT_TM_ITEMS])
|
||||||
|
|
||||||
def _strptime_datetime(cls, data_string, format="%a %b %d %H:%M:%S %Y"):
|
def _strptime_datetime(cls, data_string, format="%a %b %d %H:%M:%S %Y"):
|
||||||
"""Return a class cls instance based on the input string and the
|
"""Return a class cls instance based on the input string and the
|
||||||
format string."""
|
format string."""
|
||||||
tt, fraction = _strptime(data_string, format)
|
tt, fraction = _strptime(data_string, format)
|
||||||
gmtoff, tzname = tt[-2:]
|
tzname, gmtoff = tt[-2:]
|
||||||
args = tt[:6] + (fraction,)
|
args = tt[:6] + (fraction,)
|
||||||
if gmtoff is not None:
|
if gmtoff is not None:
|
||||||
tzdelta = datetime_timedelta(seconds=gmtoff)
|
tzdelta = datetime_timedelta(seconds=gmtoff)
|
||||||
|
|
|
@ -1670,10 +1670,8 @@ def _cmp(self, other):
|
||||||
if mytz is ottz:
|
if mytz is ottz:
|
||||||
base_compare = True
|
base_compare = True
|
||||||
else:
|
else:
|
||||||
if mytz is not None:
|
myoff = self.utcoffset()
|
||||||
myoff = self.utcoffset()
|
otoff = other.utcoffset()
|
||||||
if ottz is not None:
|
|
||||||
otoff = other.utcoffset()
|
|
||||||
base_compare = myoff == otoff
|
base_compare = myoff == otoff
|
||||||
|
|
||||||
if base_compare:
|
if base_compare:
|
||||||
|
|
26
Lib/hmac.py
26
Lib/hmac.py
|
@ -13,24 +13,24 @@
|
||||||
digest_size = None
|
digest_size = None
|
||||||
|
|
||||||
|
|
||||||
def secure_compare(a, b):
|
def compare_digest(a, b):
|
||||||
"""Returns the equivalent of 'a == b', but using a time-independent
|
"""Returns the equivalent of 'a == b', but avoids content based short
|
||||||
comparison method to prevent timing attacks."""
|
circuiting to reduce the vulnerability to timing attacks."""
|
||||||
if not ((isinstance(a, str) and isinstance(b, str)) or
|
# Consistent timing matters more here than data type flexibility
|
||||||
(isinstance(a, bytes) and isinstance(b, bytes))):
|
if not (isinstance(a, bytes) and isinstance(b, bytes)):
|
||||||
raise TypeError("inputs must be strings or bytes")
|
raise TypeError("inputs must be bytes instances")
|
||||||
|
|
||||||
|
# We assume the length of the expected digest is public knowledge,
|
||||||
|
# thus this early return isn't leaking anything an attacker wouldn't
|
||||||
|
# already know
|
||||||
if len(a) != len(b):
|
if len(a) != len(b):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
# We assume that integers in the bytes range are all cached,
|
||||||
|
# thus timing shouldn't vary much due to integer object creation
|
||||||
result = 0
|
result = 0
|
||||||
if isinstance(a, bytes):
|
for x, y in zip(a, b):
|
||||||
for x, y in zip(a, b):
|
result |= x ^ y
|
||||||
result |= x ^ y
|
|
||||||
else:
|
|
||||||
for x, y in zip(a, b):
|
|
||||||
result |= ord(x) ^ ord(y)
|
|
||||||
|
|
||||||
return result == 0
|
return result == 0
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -140,7 +140,7 @@ def open_completions(self, evalfuncs, complete, userWantsWin, mode=None):
|
||||||
elif hp.is_in_code() and (not mode or mode==COMPLETE_ATTRIBUTES):
|
elif hp.is_in_code() and (not mode or mode==COMPLETE_ATTRIBUTES):
|
||||||
self._remove_autocomplete_window()
|
self._remove_autocomplete_window()
|
||||||
mode = COMPLETE_ATTRIBUTES
|
mode = COMPLETE_ATTRIBUTES
|
||||||
while i and curline[i-1] in ID_CHARS or ord(curline[i-1]) > 127:
|
while i and (curline[i-1] in ID_CHARS or ord(curline[i-1]) > 127):
|
||||||
i -= 1
|
i -= 1
|
||||||
comp_start = curline[i:j]
|
comp_start = curline[i:j]
|
||||||
if i and curline[i-1] == '.':
|
if i and curline[i-1] == '.':
|
||||||
|
|
|
@ -675,6 +675,7 @@ def flush(self):
|
||||||
new_file.write(buffer)
|
new_file.write(buffer)
|
||||||
new_toc[key] = (new_start, new_file.tell())
|
new_toc[key] = (new_start, new_file.tell())
|
||||||
self._post_message_hook(new_file)
|
self._post_message_hook(new_file)
|
||||||
|
self._file_length = new_file.tell()
|
||||||
except:
|
except:
|
||||||
new_file.close()
|
new_file.close()
|
||||||
os.remove(new_file.name)
|
os.remove(new_file.name)
|
||||||
|
|
|
@ -23,8 +23,8 @@
|
||||||
'Manager', 'Pipe', 'cpu_count', 'log_to_stderr', 'get_logger',
|
'Manager', 'Pipe', 'cpu_count', 'log_to_stderr', 'get_logger',
|
||||||
'allow_connection_pickling', 'BufferTooShort', 'TimeoutError',
|
'allow_connection_pickling', 'BufferTooShort', 'TimeoutError',
|
||||||
'Lock', 'RLock', 'Semaphore', 'BoundedSemaphore', 'Condition',
|
'Lock', 'RLock', 'Semaphore', 'BoundedSemaphore', 'Condition',
|
||||||
'Event', 'Queue', 'SimpleQueue', 'JoinableQueue', 'Pool', 'Value', 'Array',
|
'Event', 'Barrier', 'Queue', 'SimpleQueue', 'JoinableQueue', 'Pool',
|
||||||
'RawValue', 'RawArray', 'SUBDEBUG', 'SUBWARNING',
|
'Value', 'Array', 'RawValue', 'RawArray', 'SUBDEBUG', 'SUBWARNING',
|
||||||
]
|
]
|
||||||
|
|
||||||
__author__ = 'R. Oudkerk (r.m.oudkerk@gmail.com)'
|
__author__ = 'R. Oudkerk (r.m.oudkerk@gmail.com)'
|
||||||
|
@ -186,6 +186,13 @@ def Event():
|
||||||
from multiprocessing.synchronize import Event
|
from multiprocessing.synchronize import Event
|
||||||
return Event()
|
return Event()
|
||||||
|
|
||||||
|
def Barrier(parties, action=None, timeout=None):
|
||||||
|
'''
|
||||||
|
Returns a barrier object
|
||||||
|
'''
|
||||||
|
from multiprocessing.synchronize import Barrier
|
||||||
|
return Barrier(parties, action, timeout)
|
||||||
|
|
||||||
def Queue(maxsize=0):
|
def Queue(maxsize=0):
|
||||||
'''
|
'''
|
||||||
Returns a queue object
|
Returns a queue object
|
||||||
|
|
|
@ -35,7 +35,7 @@
|
||||||
__all__ = [
|
__all__ = [
|
||||||
'Process', 'current_process', 'active_children', 'freeze_support',
|
'Process', 'current_process', 'active_children', 'freeze_support',
|
||||||
'Lock', 'RLock', 'Semaphore', 'BoundedSemaphore', 'Condition',
|
'Lock', 'RLock', 'Semaphore', 'BoundedSemaphore', 'Condition',
|
||||||
'Event', 'Queue', 'Manager', 'Pipe', 'Pool', 'JoinableQueue'
|
'Event', 'Barrier', 'Queue', 'Manager', 'Pipe', 'Pool', 'JoinableQueue'
|
||||||
]
|
]
|
||||||
|
|
||||||
#
|
#
|
||||||
|
@ -49,7 +49,7 @@
|
||||||
|
|
||||||
from multiprocessing.dummy.connection import Pipe
|
from multiprocessing.dummy.connection import Pipe
|
||||||
from threading import Lock, RLock, Semaphore, BoundedSemaphore
|
from threading import Lock, RLock, Semaphore, BoundedSemaphore
|
||||||
from threading import Event, Condition
|
from threading import Event, Condition, Barrier
|
||||||
from queue import Queue
|
from queue import Queue
|
||||||
|
|
||||||
#
|
#
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
|
|
||||||
from multiprocessing import util, process
|
from multiprocessing import util, process
|
||||||
|
|
||||||
__all__ = ['Popen', 'assert_spawning', 'exit', 'duplicate', 'close', 'ForkingPickler']
|
__all__ = ['Popen', 'assert_spawning', 'duplicate', 'close', 'ForkingPickler']
|
||||||
|
|
||||||
#
|
#
|
||||||
# Check that the current thread is spawning a child process
|
# Check that the current thread is spawning a child process
|
||||||
|
@ -75,7 +75,6 @@ def _rebuild_partial(func, args, keywords):
|
||||||
#
|
#
|
||||||
|
|
||||||
if sys.platform != 'win32':
|
if sys.platform != 'win32':
|
||||||
exit = os._exit
|
|
||||||
duplicate = os.dup
|
duplicate = os.dup
|
||||||
close = os.close
|
close = os.close
|
||||||
|
|
||||||
|
@ -168,7 +167,6 @@ def dump(obj, file, protocol=None):
|
||||||
WINEXE = (sys.platform == 'win32' and getattr(sys, 'frozen', False))
|
WINEXE = (sys.platform == 'win32' and getattr(sys, 'frozen', False))
|
||||||
WINSERVICE = sys.executable.lower().endswith("pythonservice.exe")
|
WINSERVICE = sys.executable.lower().endswith("pythonservice.exe")
|
||||||
|
|
||||||
exit = _winapi.ExitProcess
|
|
||||||
close = _winapi.CloseHandle
|
close = _winapi.CloseHandle
|
||||||
|
|
||||||
#
|
#
|
||||||
|
@ -349,7 +347,7 @@ def main():
|
||||||
from_parent.close()
|
from_parent.close()
|
||||||
|
|
||||||
exitcode = self._bootstrap()
|
exitcode = self._bootstrap()
|
||||||
exit(exitcode)
|
sys.exit(exitcode)
|
||||||
|
|
||||||
|
|
||||||
def get_preparation_data(name):
|
def get_preparation_data(name):
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
from traceback import format_exc
|
from traceback import format_exc
|
||||||
from multiprocessing import Process, current_process, active_children, Pool, util, connection
|
from multiprocessing import Process, current_process, active_children, Pool, util, connection
|
||||||
from multiprocessing.process import AuthenticationString
|
from multiprocessing.process import AuthenticationString
|
||||||
from multiprocessing.forking import exit, Popen, ForkingPickler
|
from multiprocessing.forking import Popen, ForkingPickler
|
||||||
from time import time as _time
|
from time import time as _time
|
||||||
|
|
||||||
#
|
#
|
||||||
|
@ -140,28 +140,38 @@ def __init__(self, registry, address, authkey, serializer):
|
||||||
self.id_to_obj = {'0': (None, ())}
|
self.id_to_obj = {'0': (None, ())}
|
||||||
self.id_to_refcount = {}
|
self.id_to_refcount = {}
|
||||||
self.mutex = threading.RLock()
|
self.mutex = threading.RLock()
|
||||||
self.stop = 0
|
|
||||||
|
|
||||||
def serve_forever(self):
|
def serve_forever(self):
|
||||||
'''
|
'''
|
||||||
Run the server forever
|
Run the server forever
|
||||||
'''
|
'''
|
||||||
|
self.stop_event = threading.Event()
|
||||||
current_process()._manager_server = self
|
current_process()._manager_server = self
|
||||||
try:
|
try:
|
||||||
|
accepter = threading.Thread(target=self.accepter)
|
||||||
|
accepter.daemon = True
|
||||||
|
accepter.start()
|
||||||
try:
|
try:
|
||||||
while 1:
|
while not self.stop_event.is_set():
|
||||||
try:
|
self.stop_event.wait(1)
|
||||||
c = self.listener.accept()
|
|
||||||
except (OSError, IOError):
|
|
||||||
continue
|
|
||||||
t = threading.Thread(target=self.handle_request, args=(c,))
|
|
||||||
t.daemon = True
|
|
||||||
t.start()
|
|
||||||
except (KeyboardInterrupt, SystemExit):
|
except (KeyboardInterrupt, SystemExit):
|
||||||
pass
|
pass
|
||||||
finally:
|
finally:
|
||||||
self.stop = 999
|
if sys.stdout != sys.__stdout__:
|
||||||
self.listener.close()
|
util.debug('resetting stdout, stderr')
|
||||||
|
sys.stdout = sys.__stdout__
|
||||||
|
sys.stderr = sys.__stderr__
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
|
def accepter(self):
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
c = self.listener.accept()
|
||||||
|
except (OSError, IOError):
|
||||||
|
continue
|
||||||
|
t = threading.Thread(target=self.handle_request, args=(c,))
|
||||||
|
t.daemon = True
|
||||||
|
t.start()
|
||||||
|
|
||||||
def handle_request(self, c):
|
def handle_request(self, c):
|
||||||
'''
|
'''
|
||||||
|
@ -208,7 +218,7 @@ def serve_client(self, conn):
|
||||||
send = conn.send
|
send = conn.send
|
||||||
id_to_obj = self.id_to_obj
|
id_to_obj = self.id_to_obj
|
||||||
|
|
||||||
while not self.stop:
|
while not self.stop_event.is_set():
|
||||||
|
|
||||||
try:
|
try:
|
||||||
methodname = obj = None
|
methodname = obj = None
|
||||||
|
@ -318,32 +328,13 @@ def shutdown(self, c):
|
||||||
Shutdown this process
|
Shutdown this process
|
||||||
'''
|
'''
|
||||||
try:
|
try:
|
||||||
try:
|
util.debug('manager received shutdown message')
|
||||||
util.debug('manager received shutdown message')
|
c.send(('#RETURN', None))
|
||||||
c.send(('#RETURN', None))
|
except:
|
||||||
|
import traceback
|
||||||
if sys.stdout != sys.__stdout__:
|
traceback.print_exc()
|
||||||
util.debug('resetting stdout, stderr')
|
|
||||||
sys.stdout = sys.__stdout__
|
|
||||||
sys.stderr = sys.__stderr__
|
|
||||||
|
|
||||||
util._run_finalizers(0)
|
|
||||||
|
|
||||||
for p in active_children():
|
|
||||||
util.debug('terminating a child process of manager')
|
|
||||||
p.terminate()
|
|
||||||
|
|
||||||
for p in active_children():
|
|
||||||
util.debug('terminating a child process of manager')
|
|
||||||
p.join()
|
|
||||||
|
|
||||||
util._run_finalizers()
|
|
||||||
util.info('manager exiting with exitcode 0')
|
|
||||||
except:
|
|
||||||
import traceback
|
|
||||||
traceback.print_exc()
|
|
||||||
finally:
|
finally:
|
||||||
exit(0)
|
self.stop_event.set()
|
||||||
|
|
||||||
def create(self, c, typeid, *args, **kwds):
|
def create(self, c, typeid, *args, **kwds):
|
||||||
'''
|
'''
|
||||||
|
@ -455,10 +446,6 @@ def __init__(self, address=None, authkey=None, serializer='pickle'):
|
||||||
self._serializer = serializer
|
self._serializer = serializer
|
||||||
self._Listener, self._Client = listener_client[serializer]
|
self._Listener, self._Client = listener_client[serializer]
|
||||||
|
|
||||||
def __reduce__(self):
|
|
||||||
return type(self).from_address, \
|
|
||||||
(self._address, self._authkey, self._serializer)
|
|
||||||
|
|
||||||
def get_server(self):
|
def get_server(self):
|
||||||
'''
|
'''
|
||||||
Return server object with serve_forever() method and address attribute
|
Return server object with serve_forever() method and address attribute
|
||||||
|
@ -595,7 +582,7 @@ def _finalize_manager(process, address, authkey, state, _Client):
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
process.join(timeout=0.2)
|
process.join(timeout=1.0)
|
||||||
if process.is_alive():
|
if process.is_alive():
|
||||||
util.info('manager still alive')
|
util.info('manager still alive')
|
||||||
if hasattr(process, 'terminate'):
|
if hasattr(process, 'terminate'):
|
||||||
|
@ -1006,6 +993,26 @@ def clear(self):
|
||||||
def wait(self, timeout=None):
|
def wait(self, timeout=None):
|
||||||
return self._callmethod('wait', (timeout,))
|
return self._callmethod('wait', (timeout,))
|
||||||
|
|
||||||
|
|
||||||
|
class BarrierProxy(BaseProxy):
|
||||||
|
_exposed_ = ('__getattribute__', 'wait', 'abort', 'reset')
|
||||||
|
def wait(self, timeout=None):
|
||||||
|
return self._callmethod('wait', (timeout,))
|
||||||
|
def abort(self):
|
||||||
|
return self._callmethod('abort')
|
||||||
|
def reset(self):
|
||||||
|
return self._callmethod('reset')
|
||||||
|
@property
|
||||||
|
def parties(self):
|
||||||
|
return self._callmethod('__getattribute__', ('parties',))
|
||||||
|
@property
|
||||||
|
def n_waiting(self):
|
||||||
|
return self._callmethod('__getattribute__', ('n_waiting',))
|
||||||
|
@property
|
||||||
|
def broken(self):
|
||||||
|
return self._callmethod('__getattribute__', ('broken',))
|
||||||
|
|
||||||
|
|
||||||
class NamespaceProxy(BaseProxy):
|
class NamespaceProxy(BaseProxy):
|
||||||
_exposed_ = ('__getattribute__', '__setattr__', '__delattr__')
|
_exposed_ = ('__getattribute__', '__setattr__', '__delattr__')
|
||||||
def __getattr__(self, key):
|
def __getattr__(self, key):
|
||||||
|
@ -1097,6 +1104,7 @@ class SyncManager(BaseManager):
|
||||||
SyncManager.register('BoundedSemaphore', threading.BoundedSemaphore,
|
SyncManager.register('BoundedSemaphore', threading.BoundedSemaphore,
|
||||||
AcquirerProxy)
|
AcquirerProxy)
|
||||||
SyncManager.register('Condition', threading.Condition, ConditionProxy)
|
SyncManager.register('Condition', threading.Condition, ConditionProxy)
|
||||||
|
SyncManager.register('Barrier', threading.Barrier, BarrierProxy)
|
||||||
SyncManager.register('Pool', Pool, PoolProxy)
|
SyncManager.register('Pool', Pool, PoolProxy)
|
||||||
SyncManager.register('list', list, ListProxy)
|
SyncManager.register('list', list, ListProxy)
|
||||||
SyncManager.register('dict', dict, DictProxy)
|
SyncManager.register('dict', dict, DictProxy)
|
||||||
|
|
|
@ -333,3 +333,43 @@ def wait(self, timeout=None):
|
||||||
return False
|
return False
|
||||||
finally:
|
finally:
|
||||||
self._cond.release()
|
self._cond.release()
|
||||||
|
|
||||||
|
#
|
||||||
|
# Barrier
|
||||||
|
#
|
||||||
|
|
||||||
|
class Barrier(threading.Barrier):
|
||||||
|
|
||||||
|
def __init__(self, parties, action=None, timeout=None):
|
||||||
|
import struct
|
||||||
|
from multiprocessing.heap import BufferWrapper
|
||||||
|
wrapper = BufferWrapper(struct.calcsize('i') * 2)
|
||||||
|
cond = Condition()
|
||||||
|
self.__setstate__((parties, action, timeout, cond, wrapper))
|
||||||
|
self._state = 0
|
||||||
|
self._count = 0
|
||||||
|
|
||||||
|
def __setstate__(self, state):
|
||||||
|
(self._parties, self._action, self._timeout,
|
||||||
|
self._cond, self._wrapper) = state
|
||||||
|
self._array = self._wrapper.create_memoryview().cast('i')
|
||||||
|
|
||||||
|
def __getstate__(self):
|
||||||
|
return (self._parties, self._action, self._timeout,
|
||||||
|
self._cond, self._wrapper)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def _state(self):
|
||||||
|
return self._array[0]
|
||||||
|
|
||||||
|
@_state.setter
|
||||||
|
def _state(self, value):
|
||||||
|
self._array[0] = value
|
||||||
|
|
||||||
|
@property
|
||||||
|
def _count(self):
|
||||||
|
return self._array[1]
|
||||||
|
|
||||||
|
@_count.setter
|
||||||
|
def _count(self, value):
|
||||||
|
self._array[1] = value
|
||||||
|
|
|
@ -269,21 +269,24 @@ def is_exiting():
|
||||||
def _exit_function():
|
def _exit_function():
|
||||||
global _exiting
|
global _exiting
|
||||||
|
|
||||||
info('process shutting down')
|
if not _exiting:
|
||||||
debug('running all "atexit" finalizers with priority >= 0')
|
_exiting = True
|
||||||
_run_finalizers(0)
|
|
||||||
|
|
||||||
for p in active_children():
|
info('process shutting down')
|
||||||
if p._daemonic:
|
debug('running all "atexit" finalizers with priority >= 0')
|
||||||
info('calling terminate() for daemon %s', p.name)
|
_run_finalizers(0)
|
||||||
p._popen.terminate()
|
|
||||||
|
|
||||||
for p in active_children():
|
for p in active_children():
|
||||||
info('calling join() for process %s', p.name)
|
if p._daemonic:
|
||||||
p.join()
|
info('calling terminate() for daemon %s', p.name)
|
||||||
|
p._popen.terminate()
|
||||||
|
|
||||||
debug('running the remaining "atexit" finalizers')
|
for p in active_children():
|
||||||
_run_finalizers()
|
info('calling join() for process %s', p.name)
|
||||||
|
p.join()
|
||||||
|
|
||||||
|
debug('running the remaining "atexit" finalizers')
|
||||||
|
_run_finalizers()
|
||||||
|
|
||||||
atexit.register(_exit_function)
|
atexit.register(_exit_function)
|
||||||
|
|
||||||
|
|
|
@ -1593,7 +1593,7 @@ def strip_python_stderr(stderr):
|
||||||
This will typically be run on the result of the communicate() method
|
This will typically be run on the result of the communicate() method
|
||||||
of a subprocess.Popen object.
|
of a subprocess.Popen object.
|
||||||
"""
|
"""
|
||||||
stderr = re.sub(br"\[\d+ refs\]\r?\n?$", b"", stderr).strip()
|
stderr = re.sub(br"\[\d+ refs\]\r?\n?", b"", stderr).strip()
|
||||||
return stderr
|
return stderr
|
||||||
|
|
||||||
def args_from_interpreter_flags():
|
def args_from_interpreter_flags():
|
||||||
|
|
|
@ -302,40 +302,42 @@ def test_equality(self):
|
||||||
self.assertEqual(h1.hexdigest(), h2.hexdigest(),
|
self.assertEqual(h1.hexdigest(), h2.hexdigest(),
|
||||||
"Hexdigest of copy doesn't match original hexdigest.")
|
"Hexdigest of copy doesn't match original hexdigest.")
|
||||||
|
|
||||||
class SecureCompareTestCase(unittest.TestCase):
|
class CompareDigestTestCase(unittest.TestCase):
|
||||||
|
|
||||||
def test_compare(self):
|
def test_compare(self):
|
||||||
# Testing input type exception handling
|
# Testing input type exception handling
|
||||||
a, b = 100, 200
|
a, b = 100, 200
|
||||||
self.assertRaises(TypeError, hmac.secure_compare, a, b)
|
self.assertRaises(TypeError, hmac.compare_digest, a, b)
|
||||||
a, b = 100, "foobar"
|
a, b = 100, b"foobar"
|
||||||
self.assertRaises(TypeError, hmac.secure_compare, a, b)
|
self.assertRaises(TypeError, hmac.compare_digest, a, b)
|
||||||
|
a, b = b"foobar", 200
|
||||||
|
self.assertRaises(TypeError, hmac.compare_digest, a, b)
|
||||||
a, b = "foobar", b"foobar"
|
a, b = "foobar", b"foobar"
|
||||||
self.assertRaises(TypeError, hmac.secure_compare, a, b)
|
self.assertRaises(TypeError, hmac.compare_digest, a, b)
|
||||||
|
a, b = b"foobar", "foobar"
|
||||||
# Testing str/bytes of different lengths
|
self.assertRaises(TypeError, hmac.compare_digest, a, b)
|
||||||
a, b = "foobar", "foo"
|
|
||||||
self.assertFalse(hmac.secure_compare(a, b))
|
|
||||||
a, b = b"foobar", b"foo"
|
|
||||||
self.assertFalse(hmac.secure_compare(a, b))
|
|
||||||
a, b = b"\xde\xad\xbe\xef", b"\xde\xad"
|
|
||||||
self.assertFalse(hmac.secure_compare(a, b))
|
|
||||||
|
|
||||||
# Testing str/bytes of same lengths, different values
|
|
||||||
a, b = "foobar", "foobaz"
|
|
||||||
self.assertFalse(hmac.secure_compare(a, b))
|
|
||||||
a, b = b"foobar", b"foobaz"
|
|
||||||
self.assertFalse(hmac.secure_compare(a, b))
|
|
||||||
a, b = b"\xde\xad\xbe\xef", b"\xab\xad\x1d\xea"
|
|
||||||
self.assertFalse(hmac.secure_compare(a, b))
|
|
||||||
|
|
||||||
# Testing str/bytes of same lengths, same values
|
|
||||||
a, b = "foobar", "foobar"
|
a, b = "foobar", "foobar"
|
||||||
self.assertTrue(hmac.secure_compare(a, b))
|
self.assertRaises(TypeError, hmac.compare_digest, a, b)
|
||||||
|
a, b = bytearray(b"foobar"), bytearray(b"foobar")
|
||||||
|
self.assertRaises(TypeError, hmac.compare_digest, a, b)
|
||||||
|
|
||||||
|
# Testing bytes of different lengths
|
||||||
|
a, b = b"foobar", b"foo"
|
||||||
|
self.assertFalse(hmac.compare_digest(a, b))
|
||||||
|
a, b = b"\xde\xad\xbe\xef", b"\xde\xad"
|
||||||
|
self.assertFalse(hmac.compare_digest(a, b))
|
||||||
|
|
||||||
|
# Testing bytes of same lengths, different values
|
||||||
|
a, b = b"foobar", b"foobaz"
|
||||||
|
self.assertFalse(hmac.compare_digest(a, b))
|
||||||
|
a, b = b"\xde\xad\xbe\xef", b"\xab\xad\x1d\xea"
|
||||||
|
self.assertFalse(hmac.compare_digest(a, b))
|
||||||
|
|
||||||
|
# Testing bytes of same lengths, same values
|
||||||
a, b = b"foobar", b"foobar"
|
a, b = b"foobar", b"foobar"
|
||||||
self.assertTrue(hmac.secure_compare(a, b))
|
self.assertTrue(hmac.compare_digest(a, b))
|
||||||
a, b = b"\xde\xad\xbe\xef", b"\xde\xad\xbe\xef"
|
a, b = b"\xde\xad\xbe\xef", b"\xde\xad\xbe\xef"
|
||||||
self.assertTrue(hmac.secure_compare(a, b))
|
self.assertTrue(hmac.compare_digest(a, b))
|
||||||
|
|
||||||
def test_main():
|
def test_main():
|
||||||
support.run_unittest(
|
support.run_unittest(
|
||||||
|
@ -343,7 +345,7 @@ def test_main():
|
||||||
ConstructorTestCase,
|
ConstructorTestCase,
|
||||||
SanityTestCase,
|
SanityTestCase,
|
||||||
CopyTestCase,
|
CopyTestCase,
|
||||||
SecureCompareTestCase
|
CompareDigestTestCase
|
||||||
)
|
)
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|
|
@ -504,6 +504,17 @@ def test_flush(self):
|
||||||
# Write changes to disk
|
# Write changes to disk
|
||||||
self._test_flush_or_close(self._box.flush, True)
|
self._test_flush_or_close(self._box.flush, True)
|
||||||
|
|
||||||
|
def test_popitem_and_flush_twice(self):
|
||||||
|
# See #15036.
|
||||||
|
self._box.add(self._template % 0)
|
||||||
|
self._box.add(self._template % 1)
|
||||||
|
self._box.flush()
|
||||||
|
|
||||||
|
self._box.popitem()
|
||||||
|
self._box.flush()
|
||||||
|
self._box.popitem()
|
||||||
|
self._box.flush()
|
||||||
|
|
||||||
def test_lock_unlock(self):
|
def test_lock_unlock(self):
|
||||||
# Lock and unlock the mailbox
|
# Lock and unlock the mailbox
|
||||||
self.assertFalse(os.path.exists(self._get_lock_path()))
|
self.assertFalse(os.path.exists(self._get_lock_path()))
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
import socket
|
import socket
|
||||||
import random
|
import random
|
||||||
import logging
|
import logging
|
||||||
|
import struct
|
||||||
import test.support
|
import test.support
|
||||||
|
|
||||||
|
|
||||||
|
@ -1056,6 +1057,340 @@ def test_event(self):
|
||||||
p.start()
|
p.start()
|
||||||
self.assertEqual(wait(), True)
|
self.assertEqual(wait(), True)
|
||||||
|
|
||||||
|
#
|
||||||
|
# Tests for Barrier - adapted from tests in test/lock_tests.py
|
||||||
|
#
|
||||||
|
|
||||||
|
# Many of the tests for threading.Barrier use a list as an atomic
|
||||||
|
# counter: a value is appended to increment the counter, and the
|
||||||
|
# length of the list gives the value. We use the class DummyList
|
||||||
|
# for the same purpose.
|
||||||
|
|
||||||
|
class _DummyList(object):
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
wrapper = multiprocessing.heap.BufferWrapper(struct.calcsize('i'))
|
||||||
|
lock = multiprocessing.Lock()
|
||||||
|
self.__setstate__((wrapper, lock))
|
||||||
|
self._lengthbuf[0] = 0
|
||||||
|
|
||||||
|
def __setstate__(self, state):
|
||||||
|
(self._wrapper, self._lock) = state
|
||||||
|
self._lengthbuf = self._wrapper.create_memoryview().cast('i')
|
||||||
|
|
||||||
|
def __getstate__(self):
|
||||||
|
return (self._wrapper, self._lock)
|
||||||
|
|
||||||
|
def append(self, _):
|
||||||
|
with self._lock:
|
||||||
|
self._lengthbuf[0] += 1
|
||||||
|
|
||||||
|
def __len__(self):
|
||||||
|
with self._lock:
|
||||||
|
return self._lengthbuf[0]
|
||||||
|
|
||||||
|
def _wait():
|
||||||
|
# A crude wait/yield function not relying on synchronization primitives.
|
||||||
|
time.sleep(0.01)
|
||||||
|
|
||||||
|
|
||||||
|
class Bunch(object):
|
||||||
|
"""
|
||||||
|
A bunch of threads.
|
||||||
|
"""
|
||||||
|
def __init__(self, namespace, f, args, n, wait_before_exit=False):
|
||||||
|
"""
|
||||||
|
Construct a bunch of `n` threads running the same function `f`.
|
||||||
|
If `wait_before_exit` is True, the threads won't terminate until
|
||||||
|
do_finish() is called.
|
||||||
|
"""
|
||||||
|
self.f = f
|
||||||
|
self.args = args
|
||||||
|
self.n = n
|
||||||
|
self.started = namespace.DummyList()
|
||||||
|
self.finished = namespace.DummyList()
|
||||||
|
self._can_exit = namespace.Event()
|
||||||
|
if not wait_before_exit:
|
||||||
|
self._can_exit.set()
|
||||||
|
for i in range(n):
|
||||||
|
p = namespace.Process(target=self.task)
|
||||||
|
p.daemon = True
|
||||||
|
p.start()
|
||||||
|
|
||||||
|
def task(self):
|
||||||
|
pid = os.getpid()
|
||||||
|
self.started.append(pid)
|
||||||
|
try:
|
||||||
|
self.f(*self.args)
|
||||||
|
finally:
|
||||||
|
self.finished.append(pid)
|
||||||
|
self._can_exit.wait(30)
|
||||||
|
assert self._can_exit.is_set()
|
||||||
|
|
||||||
|
def wait_for_started(self):
|
||||||
|
while len(self.started) < self.n:
|
||||||
|
_wait()
|
||||||
|
|
||||||
|
def wait_for_finished(self):
|
||||||
|
while len(self.finished) < self.n:
|
||||||
|
_wait()
|
||||||
|
|
||||||
|
def do_finish(self):
|
||||||
|
self._can_exit.set()
|
||||||
|
|
||||||
|
|
||||||
|
class AppendTrue(object):
|
||||||
|
def __init__(self, obj):
|
||||||
|
self.obj = obj
|
||||||
|
def __call__(self):
|
||||||
|
self.obj.append(True)
|
||||||
|
|
||||||
|
|
||||||
|
class _TestBarrier(BaseTestCase):
|
||||||
|
"""
|
||||||
|
Tests for Barrier objects.
|
||||||
|
"""
|
||||||
|
N = 5
|
||||||
|
defaultTimeout = 10.0 # XXX Slow Windows buildbots need generous timeout
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
self.barrier = self.Barrier(self.N, timeout=self.defaultTimeout)
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
self.barrier.abort()
|
||||||
|
self.barrier = None
|
||||||
|
|
||||||
|
def DummyList(self):
|
||||||
|
if self.TYPE == 'threads':
|
||||||
|
return []
|
||||||
|
elif self.TYPE == 'manager':
|
||||||
|
return self.manager.list()
|
||||||
|
else:
|
||||||
|
return _DummyList()
|
||||||
|
|
||||||
|
def run_threads(self, f, args):
|
||||||
|
b = Bunch(self, f, args, self.N-1)
|
||||||
|
f(*args)
|
||||||
|
b.wait_for_finished()
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def multipass(cls, barrier, results, n):
|
||||||
|
m = barrier.parties
|
||||||
|
assert m == cls.N
|
||||||
|
for i in range(n):
|
||||||
|
results[0].append(True)
|
||||||
|
assert len(results[1]) == i * m
|
||||||
|
barrier.wait()
|
||||||
|
results[1].append(True)
|
||||||
|
assert len(results[0]) == (i + 1) * m
|
||||||
|
barrier.wait()
|
||||||
|
try:
|
||||||
|
assert barrier.n_waiting == 0
|
||||||
|
except NotImplementedError:
|
||||||
|
pass
|
||||||
|
assert not barrier.broken
|
||||||
|
|
||||||
|
def test_barrier(self, passes=1):
|
||||||
|
"""
|
||||||
|
Test that a barrier is passed in lockstep
|
||||||
|
"""
|
||||||
|
results = [self.DummyList(), self.DummyList()]
|
||||||
|
self.run_threads(self.multipass, (self.barrier, results, passes))
|
||||||
|
|
||||||
|
def test_barrier_10(self):
|
||||||
|
"""
|
||||||
|
Test that a barrier works for 10 consecutive runs
|
||||||
|
"""
|
||||||
|
return self.test_barrier(10)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _test_wait_return_f(cls, barrier, queue):
|
||||||
|
res = barrier.wait()
|
||||||
|
queue.put(res)
|
||||||
|
|
||||||
|
def test_wait_return(self):
|
||||||
|
"""
|
||||||
|
test the return value from barrier.wait
|
||||||
|
"""
|
||||||
|
queue = self.Queue()
|
||||||
|
self.run_threads(self._test_wait_return_f, (self.barrier, queue))
|
||||||
|
results = [queue.get() for i in range(self.N)]
|
||||||
|
self.assertEqual(results.count(0), 1)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _test_action_f(cls, barrier, results):
|
||||||
|
barrier.wait()
|
||||||
|
if len(results) != 1:
|
||||||
|
raise RuntimeError
|
||||||
|
|
||||||
|
def test_action(self):
|
||||||
|
"""
|
||||||
|
Test the 'action' callback
|
||||||
|
"""
|
||||||
|
results = self.DummyList()
|
||||||
|
barrier = self.Barrier(self.N, action=AppendTrue(results))
|
||||||
|
self.run_threads(self._test_action_f, (barrier, results))
|
||||||
|
self.assertEqual(len(results), 1)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _test_abort_f(cls, barrier, results1, results2):
|
||||||
|
try:
|
||||||
|
i = barrier.wait()
|
||||||
|
if i == cls.N//2:
|
||||||
|
raise RuntimeError
|
||||||
|
barrier.wait()
|
||||||
|
results1.append(True)
|
||||||
|
except threading.BrokenBarrierError:
|
||||||
|
results2.append(True)
|
||||||
|
except RuntimeError:
|
||||||
|
barrier.abort()
|
||||||
|
|
||||||
|
def test_abort(self):
|
||||||
|
"""
|
||||||
|
Test that an abort will put the barrier in a broken state
|
||||||
|
"""
|
||||||
|
results1 = self.DummyList()
|
||||||
|
results2 = self.DummyList()
|
||||||
|
self.run_threads(self._test_abort_f,
|
||||||
|
(self.barrier, results1, results2))
|
||||||
|
self.assertEqual(len(results1), 0)
|
||||||
|
self.assertEqual(len(results2), self.N-1)
|
||||||
|
self.assertTrue(self.barrier.broken)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _test_reset_f(cls, barrier, results1, results2, results3):
|
||||||
|
i = barrier.wait()
|
||||||
|
if i == cls.N//2:
|
||||||
|
# Wait until the other threads are all in the barrier.
|
||||||
|
while barrier.n_waiting < cls.N-1:
|
||||||
|
time.sleep(0.001)
|
||||||
|
barrier.reset()
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
barrier.wait()
|
||||||
|
results1.append(True)
|
||||||
|
except threading.BrokenBarrierError:
|
||||||
|
results2.append(True)
|
||||||
|
# Now, pass the barrier again
|
||||||
|
barrier.wait()
|
||||||
|
results3.append(True)
|
||||||
|
|
||||||
|
def test_reset(self):
|
||||||
|
"""
|
||||||
|
Test that a 'reset' on a barrier frees the waiting threads
|
||||||
|
"""
|
||||||
|
results1 = self.DummyList()
|
||||||
|
results2 = self.DummyList()
|
||||||
|
results3 = self.DummyList()
|
||||||
|
self.run_threads(self._test_reset_f,
|
||||||
|
(self.barrier, results1, results2, results3))
|
||||||
|
self.assertEqual(len(results1), 0)
|
||||||
|
self.assertEqual(len(results2), self.N-1)
|
||||||
|
self.assertEqual(len(results3), self.N)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _test_abort_and_reset_f(cls, barrier, barrier2,
|
||||||
|
results1, results2, results3):
|
||||||
|
try:
|
||||||
|
i = barrier.wait()
|
||||||
|
if i == cls.N//2:
|
||||||
|
raise RuntimeError
|
||||||
|
barrier.wait()
|
||||||
|
results1.append(True)
|
||||||
|
except threading.BrokenBarrierError:
|
||||||
|
results2.append(True)
|
||||||
|
except RuntimeError:
|
||||||
|
barrier.abort()
|
||||||
|
# Synchronize and reset the barrier. Must synchronize first so
|
||||||
|
# that everyone has left it when we reset, and after so that no
|
||||||
|
# one enters it before the reset.
|
||||||
|
if barrier2.wait() == cls.N//2:
|
||||||
|
barrier.reset()
|
||||||
|
barrier2.wait()
|
||||||
|
barrier.wait()
|
||||||
|
results3.append(True)
|
||||||
|
|
||||||
|
def test_abort_and_reset(self):
|
||||||
|
"""
|
||||||
|
Test that a barrier can be reset after being broken.
|
||||||
|
"""
|
||||||
|
results1 = self.DummyList()
|
||||||
|
results2 = self.DummyList()
|
||||||
|
results3 = self.DummyList()
|
||||||
|
barrier2 = self.Barrier(self.N)
|
||||||
|
|
||||||
|
self.run_threads(self._test_abort_and_reset_f,
|
||||||
|
(self.barrier, barrier2, results1, results2, results3))
|
||||||
|
self.assertEqual(len(results1), 0)
|
||||||
|
self.assertEqual(len(results2), self.N-1)
|
||||||
|
self.assertEqual(len(results3), self.N)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _test_timeout_f(cls, barrier, results):
|
||||||
|
i = barrier.wait(20)
|
||||||
|
if i == cls.N//2:
|
||||||
|
# One thread is late!
|
||||||
|
time.sleep(4.0)
|
||||||
|
try:
|
||||||
|
barrier.wait(0.5)
|
||||||
|
except threading.BrokenBarrierError:
|
||||||
|
results.append(True)
|
||||||
|
|
||||||
|
def test_timeout(self):
|
||||||
|
"""
|
||||||
|
Test wait(timeout)
|
||||||
|
"""
|
||||||
|
results = self.DummyList()
|
||||||
|
self.run_threads(self._test_timeout_f, (self.barrier, results))
|
||||||
|
self.assertEqual(len(results), self.barrier.parties)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _test_default_timeout_f(cls, barrier, results):
|
||||||
|
i = barrier.wait(20)
|
||||||
|
if i == cls.N//2:
|
||||||
|
# One thread is later than the default timeout
|
||||||
|
time.sleep(4.0)
|
||||||
|
try:
|
||||||
|
barrier.wait()
|
||||||
|
except threading.BrokenBarrierError:
|
||||||
|
results.append(True)
|
||||||
|
|
||||||
|
def test_default_timeout(self):
|
||||||
|
"""
|
||||||
|
Test the barrier's default timeout
|
||||||
|
"""
|
||||||
|
barrier = self.Barrier(self.N, timeout=1.0)
|
||||||
|
results = self.DummyList()
|
||||||
|
self.run_threads(self._test_default_timeout_f, (barrier, results))
|
||||||
|
self.assertEqual(len(results), barrier.parties)
|
||||||
|
|
||||||
|
def test_single_thread(self):
|
||||||
|
b = self.Barrier(1)
|
||||||
|
b.wait()
|
||||||
|
b.wait()
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _test_thousand_f(cls, barrier, passes, conn, lock):
|
||||||
|
for i in range(passes):
|
||||||
|
barrier.wait()
|
||||||
|
with lock:
|
||||||
|
conn.send(i)
|
||||||
|
|
||||||
|
def test_thousand(self):
|
||||||
|
if self.TYPE == 'manager':
|
||||||
|
return
|
||||||
|
passes = 1000
|
||||||
|
lock = self.Lock()
|
||||||
|
conn, child_conn = self.Pipe(False)
|
||||||
|
for j in range(self.N):
|
||||||
|
p = self.Process(target=self._test_thousand_f,
|
||||||
|
args=(self.barrier, passes, child_conn, lock))
|
||||||
|
p.start()
|
||||||
|
|
||||||
|
for i in range(passes):
|
||||||
|
for j in range(self.N):
|
||||||
|
self.assertEqual(conn.recv(), i)
|
||||||
|
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
|
@ -1485,6 +1820,11 @@ class _TestZZZNumberOfObjects(BaseTestCase):
|
||||||
# run after all the other tests for the manager. It tests that
|
# run after all the other tests for the manager. It tests that
|
||||||
# there have been no "reference leaks" for the manager's shared
|
# there have been no "reference leaks" for the manager's shared
|
||||||
# objects. Note the comment in _TestPool.test_terminate().
|
# objects. Note the comment in _TestPool.test_terminate().
|
||||||
|
|
||||||
|
# If some other test using ManagerMixin.manager fails, then the
|
||||||
|
# raised exception may keep alive a frame which holds a reference
|
||||||
|
# to a managed object. This will cause test_number_of_objects to
|
||||||
|
# also fail.
|
||||||
ALLOWED_TYPES = ('manager',)
|
ALLOWED_TYPES = ('manager',)
|
||||||
|
|
||||||
def test_number_of_objects(self):
|
def test_number_of_objects(self):
|
||||||
|
@ -1564,6 +1904,11 @@ def test_mymanager(self):
|
||||||
|
|
||||||
manager.shutdown()
|
manager.shutdown()
|
||||||
|
|
||||||
|
# If the manager process exited cleanly then the exitcode
|
||||||
|
# will be zero. Otherwise (after a short timeout)
|
||||||
|
# terminate() is used, resulting in an exitcode of -SIGTERM.
|
||||||
|
self.assertEqual(manager._process.exitcode, 0)
|
||||||
|
|
||||||
#
|
#
|
||||||
# Test of connecting to a remote server and using xmlrpclib for serialization
|
# Test of connecting to a remote server and using xmlrpclib for serialization
|
||||||
#
|
#
|
||||||
|
@ -1923,7 +2268,7 @@ def test_missing_fd_transfer(self):
|
||||||
|
|
||||||
class _TestListener(BaseTestCase):
|
class _TestListener(BaseTestCase):
|
||||||
|
|
||||||
ALLOWED_TYPES = ('processes')
|
ALLOWED_TYPES = ('processes',)
|
||||||
|
|
||||||
def test_multiple_bind(self):
|
def test_multiple_bind(self):
|
||||||
for family in self.connection.families:
|
for family in self.connection.families:
|
||||||
|
@ -2505,10 +2850,12 @@ def create_test_cases(Mixin, type):
|
||||||
result = {}
|
result = {}
|
||||||
glob = globals()
|
glob = globals()
|
||||||
Type = type.capitalize()
|
Type = type.capitalize()
|
||||||
|
ALL_TYPES = {'processes', 'threads', 'manager'}
|
||||||
|
|
||||||
for name in list(glob.keys()):
|
for name in list(glob.keys()):
|
||||||
if name.startswith('_Test'):
|
if name.startswith('_Test'):
|
||||||
base = glob[name]
|
base = glob[name]
|
||||||
|
assert set(base.ALLOWED_TYPES) <= ALL_TYPES, set(base.ALLOWED_TYPES)
|
||||||
if type in base.ALLOWED_TYPES:
|
if type in base.ALLOWED_TYPES:
|
||||||
newname = 'With' + Type + name[1:]
|
newname = 'With' + Type + name[1:]
|
||||||
class Temp(base, unittest.TestCase, Mixin):
|
class Temp(base, unittest.TestCase, Mixin):
|
||||||
|
@ -2527,7 +2874,7 @@ class ProcessesMixin(object):
|
||||||
Process = multiprocessing.Process
|
Process = multiprocessing.Process
|
||||||
locals().update(get_attributes(multiprocessing, (
|
locals().update(get_attributes(multiprocessing, (
|
||||||
'Queue', 'Lock', 'RLock', 'Semaphore', 'BoundedSemaphore',
|
'Queue', 'Lock', 'RLock', 'Semaphore', 'BoundedSemaphore',
|
||||||
'Condition', 'Event', 'Value', 'Array', 'RawValue',
|
'Condition', 'Event', 'Barrier', 'Value', 'Array', 'RawValue',
|
||||||
'RawArray', 'current_process', 'active_children', 'Pipe',
|
'RawArray', 'current_process', 'active_children', 'Pipe',
|
||||||
'connection', 'JoinableQueue', 'Pool'
|
'connection', 'JoinableQueue', 'Pool'
|
||||||
)))
|
)))
|
||||||
|
@ -2542,7 +2889,7 @@ class ManagerMixin(object):
|
||||||
manager = object.__new__(multiprocessing.managers.SyncManager)
|
manager = object.__new__(multiprocessing.managers.SyncManager)
|
||||||
locals().update(get_attributes(manager, (
|
locals().update(get_attributes(manager, (
|
||||||
'Queue', 'Lock', 'RLock', 'Semaphore', 'BoundedSemaphore',
|
'Queue', 'Lock', 'RLock', 'Semaphore', 'BoundedSemaphore',
|
||||||
'Condition', 'Event', 'Value', 'Array', 'list', 'dict',
|
'Condition', 'Event', 'Barrier', 'Value', 'Array', 'list', 'dict',
|
||||||
'Namespace', 'JoinableQueue', 'Pool'
|
'Namespace', 'JoinableQueue', 'Pool'
|
||||||
)))
|
)))
|
||||||
|
|
||||||
|
@ -2555,7 +2902,7 @@ class ThreadsMixin(object):
|
||||||
Process = multiprocessing.dummy.Process
|
Process = multiprocessing.dummy.Process
|
||||||
locals().update(get_attributes(multiprocessing.dummy, (
|
locals().update(get_attributes(multiprocessing.dummy, (
|
||||||
'Queue', 'Lock', 'RLock', 'Semaphore', 'BoundedSemaphore',
|
'Queue', 'Lock', 'RLock', 'Semaphore', 'BoundedSemaphore',
|
||||||
'Condition', 'Event', 'Value', 'Array', 'current_process',
|
'Condition', 'Event', 'Barrier', 'Value', 'Array', 'current_process',
|
||||||
'active_children', 'Pipe', 'connection', 'dict', 'list',
|
'active_children', 'Pipe', 'connection', 'dict', 'list',
|
||||||
'Namespace', 'JoinableQueue', 'Pool'
|
'Namespace', 'JoinableQueue', 'Pool'
|
||||||
)))
|
)))
|
||||||
|
|
|
@ -78,8 +78,9 @@ def test_cmp(self):
|
||||||
|
|
||||||
def test_fields(self):
|
def test_fields(self):
|
||||||
t = time.gmtime()
|
t = time.gmtime()
|
||||||
self.assertEqual(len(t), t.n_fields)
|
self.assertEqual(len(t), t.n_sequence_fields)
|
||||||
self.assertEqual(t.n_fields, t.n_sequence_fields+t.n_unnamed_fields)
|
self.assertEqual(t.n_unnamed_fields, 0)
|
||||||
|
self.assertEqual(t.n_fields, time._STRUCT_TM_ITEMS)
|
||||||
|
|
||||||
def test_constructor(self):
|
def test_constructor(self):
|
||||||
t = time.struct_time
|
t = time.struct_time
|
||||||
|
|
|
@ -31,15 +31,14 @@ def test_time(self):
|
||||||
time.time()
|
time.time()
|
||||||
info = time.get_clock_info('time')
|
info = time.get_clock_info('time')
|
||||||
self.assertFalse(info.monotonic)
|
self.assertFalse(info.monotonic)
|
||||||
if sys.platform != 'win32':
|
self.assertTrue(info.adjustable)
|
||||||
self.assertTrue(info.adjusted)
|
|
||||||
|
|
||||||
def test_clock(self):
|
def test_clock(self):
|
||||||
time.clock()
|
time.clock()
|
||||||
|
|
||||||
info = time.get_clock_info('clock')
|
info = time.get_clock_info('clock')
|
||||||
self.assertTrue(info.monotonic)
|
self.assertTrue(info.monotonic)
|
||||||
self.assertFalse(info.adjusted)
|
self.assertFalse(info.adjustable)
|
||||||
|
|
||||||
@unittest.skipUnless(hasattr(time, 'clock_gettime'),
|
@unittest.skipUnless(hasattr(time, 'clock_gettime'),
|
||||||
'need time.clock_gettime()')
|
'need time.clock_gettime()')
|
||||||
|
@ -371,10 +370,7 @@ def test_monotonic(self):
|
||||||
|
|
||||||
info = time.get_clock_info('monotonic')
|
info = time.get_clock_info('monotonic')
|
||||||
self.assertTrue(info.monotonic)
|
self.assertTrue(info.monotonic)
|
||||||
if sys.platform == 'linux':
|
self.assertFalse(info.adjustable)
|
||||||
self.assertTrue(info.adjusted)
|
|
||||||
else:
|
|
||||||
self.assertFalse(info.adjusted)
|
|
||||||
|
|
||||||
def test_perf_counter(self):
|
def test_perf_counter(self):
|
||||||
time.perf_counter()
|
time.perf_counter()
|
||||||
|
@ -390,7 +386,7 @@ def test_process_time(self):
|
||||||
|
|
||||||
info = time.get_clock_info('process_time')
|
info = time.get_clock_info('process_time')
|
||||||
self.assertTrue(info.monotonic)
|
self.assertTrue(info.monotonic)
|
||||||
self.assertFalse(info.adjusted)
|
self.assertFalse(info.adjustable)
|
||||||
|
|
||||||
@unittest.skipUnless(hasattr(time, 'monotonic'),
|
@unittest.skipUnless(hasattr(time, 'monotonic'),
|
||||||
'need time.monotonic')
|
'need time.monotonic')
|
||||||
|
@ -441,7 +437,7 @@ def test_get_clock_info(self):
|
||||||
# 0.0 < resolution <= 1.0
|
# 0.0 < resolution <= 1.0
|
||||||
self.assertGreater(info.resolution, 0.0)
|
self.assertGreater(info.resolution, 0.0)
|
||||||
self.assertLessEqual(info.resolution, 1.0)
|
self.assertLessEqual(info.resolution, 1.0)
|
||||||
self.assertIsInstance(info.adjusted, bool)
|
self.assertIsInstance(info.adjustable, bool)
|
||||||
|
|
||||||
self.assertRaises(ValueError, time.get_clock_info, 'xxx')
|
self.assertRaises(ValueError, time.get_clock_info, 'xxx')
|
||||||
|
|
||||||
|
@ -624,7 +620,58 @@ def test_timespec(self):
|
||||||
for invalid in self.invalid_values:
|
for invalid in self.invalid_values:
|
||||||
self.assertRaises(OverflowError, pytime_object_to_timespec, invalid)
|
self.assertRaises(OverflowError, pytime_object_to_timespec, invalid)
|
||||||
|
|
||||||
|
@unittest.skipUnless(time._STRUCT_TM_ITEMS == 11, "needs tm_zone support")
|
||||||
|
def test_localtime_timezone(self):
|
||||||
|
|
||||||
|
# Get the localtime and examine it for the offset and zone.
|
||||||
|
lt = time.localtime()
|
||||||
|
self.assertTrue(hasattr(lt, "tm_gmtoff"))
|
||||||
|
self.assertTrue(hasattr(lt, "tm_zone"))
|
||||||
|
|
||||||
|
# See if the offset and zone are similar to the module
|
||||||
|
# attributes.
|
||||||
|
if lt.tm_gmtoff is None:
|
||||||
|
self.assertTrue(not hasattr(time, "timezone"))
|
||||||
|
else:
|
||||||
|
self.assertEqual(lt.tm_gmtoff, -[time.timezone, time.altzone][lt.tm_isdst])
|
||||||
|
if lt.tm_zone is None:
|
||||||
|
self.assertTrue(not hasattr(time, "tzname"))
|
||||||
|
else:
|
||||||
|
self.assertEqual(lt.tm_zone, time.tzname[lt.tm_isdst])
|
||||||
|
|
||||||
|
# Try and make UNIX times from the localtime and a 9-tuple
|
||||||
|
# created from the localtime. Test to see that the times are
|
||||||
|
# the same.
|
||||||
|
t = time.mktime(lt); t9 = time.mktime(lt[:9])
|
||||||
|
self.assertEqual(t, t9)
|
||||||
|
|
||||||
|
# Make localtimes from the UNIX times and compare them to
|
||||||
|
# the original localtime, thus making a round trip.
|
||||||
|
new_lt = time.localtime(t); new_lt9 = time.localtime(t9)
|
||||||
|
self.assertEqual(new_lt, lt)
|
||||||
|
self.assertEqual(new_lt.tm_gmtoff, lt.tm_gmtoff)
|
||||||
|
self.assertEqual(new_lt.tm_zone, lt.tm_zone)
|
||||||
|
self.assertEqual(new_lt9, lt)
|
||||||
|
self.assertEqual(new_lt.tm_gmtoff, lt.tm_gmtoff)
|
||||||
|
self.assertEqual(new_lt9.tm_zone, lt.tm_zone)
|
||||||
|
|
||||||
|
@unittest.skipUnless(time._STRUCT_TM_ITEMS == 11, "needs tm_zone support")
|
||||||
|
def test_strptime_timezone(self):
|
||||||
|
t = time.strptime("UTC", "%Z")
|
||||||
|
self.assertEqual(t.tm_zone, 'UTC')
|
||||||
|
t = time.strptime("+0500", "%z")
|
||||||
|
self.assertEqual(t.tm_gmtoff, 5 * 3600)
|
||||||
|
|
||||||
|
@unittest.skipUnless(time._STRUCT_TM_ITEMS == 11, "needs tm_zone support")
|
||||||
|
def test_short_times(self):
|
||||||
|
|
||||||
|
import pickle
|
||||||
|
|
||||||
|
# Load a short time structure using pickle.
|
||||||
|
st = b"ctime\nstruct_time\np0\n((I2007\nI8\nI11\nI1\nI24\nI49\nI5\nI223\nI1\ntp1\n(dp2\ntp3\nRp4\n."
|
||||||
|
lt = pickle.loads(st)
|
||||||
|
self.assertIs(lt.tm_gmtoff, None)
|
||||||
|
self.assertIs(lt.tm_zone, None)
|
||||||
|
|
||||||
def test_main():
|
def test_main():
|
||||||
support.run_unittest(
|
support.run_unittest(
|
||||||
|
|
|
@ -23,7 +23,8 @@
|
||||||
from test import support
|
from test import support
|
||||||
from test.support import findfile, import_fresh_module, gc_collect
|
from test.support import findfile, import_fresh_module, gc_collect
|
||||||
|
|
||||||
pyET = import_fresh_module('xml.etree.ElementTree', blocked=['_elementtree'])
|
pyET = None
|
||||||
|
ET = None
|
||||||
|
|
||||||
SIMPLE_XMLFILE = findfile("simple.xml", subdir="xmltestdata")
|
SIMPLE_XMLFILE = findfile("simple.xml", subdir="xmltestdata")
|
||||||
try:
|
try:
|
||||||
|
@ -209,10 +210,8 @@ def interface():
|
||||||
|
|
||||||
These methods return an iterable. See bug 6472.
|
These methods return an iterable. See bug 6472.
|
||||||
|
|
||||||
>>> check_method(element.iter("tag").__next__)
|
|
||||||
>>> check_method(element.iterfind("tag").__next__)
|
>>> check_method(element.iterfind("tag").__next__)
|
||||||
>>> check_method(element.iterfind("*").__next__)
|
>>> check_method(element.iterfind("*").__next__)
|
||||||
>>> check_method(tree.iter("tag").__next__)
|
|
||||||
>>> check_method(tree.iterfind("tag").__next__)
|
>>> check_method(tree.iterfind("tag").__next__)
|
||||||
>>> check_method(tree.iterfind("*").__next__)
|
>>> check_method(tree.iterfind("*").__next__)
|
||||||
|
|
||||||
|
@ -291,42 +290,6 @@ def cdata():
|
||||||
'<tag>hello</tag>'
|
'<tag>hello</tag>'
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Only with Python implementation
|
|
||||||
def simplefind():
|
|
||||||
"""
|
|
||||||
Test find methods using the elementpath fallback.
|
|
||||||
|
|
||||||
>>> ElementTree = pyET
|
|
||||||
|
|
||||||
>>> CurrentElementPath = ElementTree.ElementPath
|
|
||||||
>>> ElementTree.ElementPath = ElementTree._SimpleElementPath()
|
|
||||||
>>> elem = ElementTree.XML(SAMPLE_XML)
|
|
||||||
>>> elem.find("tag").tag
|
|
||||||
'tag'
|
|
||||||
>>> ElementTree.ElementTree(elem).find("tag").tag
|
|
||||||
'tag'
|
|
||||||
>>> elem.findtext("tag")
|
|
||||||
'text'
|
|
||||||
>>> elem.findtext("tog")
|
|
||||||
>>> elem.findtext("tog", "default")
|
|
||||||
'default'
|
|
||||||
>>> ElementTree.ElementTree(elem).findtext("tag")
|
|
||||||
'text'
|
|
||||||
>>> summarize_list(elem.findall("tag"))
|
|
||||||
['tag', 'tag']
|
|
||||||
>>> summarize_list(elem.findall(".//tag"))
|
|
||||||
['tag', 'tag', 'tag']
|
|
||||||
|
|
||||||
Path syntax doesn't work in this case.
|
|
||||||
|
|
||||||
>>> elem.find("section/tag")
|
|
||||||
>>> elem.findtext("section/tag")
|
|
||||||
>>> summarize_list(elem.findall("section/tag"))
|
|
||||||
[]
|
|
||||||
|
|
||||||
>>> ElementTree.ElementPath = CurrentElementPath
|
|
||||||
"""
|
|
||||||
|
|
||||||
def find():
|
def find():
|
||||||
"""
|
"""
|
||||||
Test find methods (including xpath syntax).
|
Test find methods (including xpath syntax).
|
||||||
|
@ -1002,36 +965,6 @@ def methods():
|
||||||
'1 < 2\n'
|
'1 < 2\n'
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def iterators():
|
|
||||||
"""
|
|
||||||
Test iterators.
|
|
||||||
|
|
||||||
>>> e = ET.XML("<html><body>this is a <i>paragraph</i>.</body>..</html>")
|
|
||||||
>>> summarize_list(e.iter())
|
|
||||||
['html', 'body', 'i']
|
|
||||||
>>> summarize_list(e.find("body").iter())
|
|
||||||
['body', 'i']
|
|
||||||
>>> summarize(next(e.iter()))
|
|
||||||
'html'
|
|
||||||
>>> "".join(e.itertext())
|
|
||||||
'this is a paragraph...'
|
|
||||||
>>> "".join(e.find("body").itertext())
|
|
||||||
'this is a paragraph.'
|
|
||||||
>>> next(e.itertext())
|
|
||||||
'this is a '
|
|
||||||
|
|
||||||
Method iterparse should return an iterator. See bug 6472.
|
|
||||||
|
|
||||||
>>> sourcefile = serialize(e, to_string=False)
|
|
||||||
>>> next(ET.iterparse(sourcefile)) # doctest: +ELLIPSIS
|
|
||||||
('end', <Element 'i' at 0x...>)
|
|
||||||
|
|
||||||
>>> tree = ET.ElementTree(None)
|
|
||||||
>>> tree.iter()
|
|
||||||
Traceback (most recent call last):
|
|
||||||
AttributeError: 'NoneType' object has no attribute 'iter'
|
|
||||||
"""
|
|
||||||
|
|
||||||
ENTITY_XML = """\
|
ENTITY_XML = """\
|
||||||
<!DOCTYPE points [
|
<!DOCTYPE points [
|
||||||
<!ENTITY % user-entities SYSTEM 'user-entities.xml'>
|
<!ENTITY % user-entities SYSTEM 'user-entities.xml'>
|
||||||
|
@ -1339,6 +1272,7 @@ def processinginstruction():
|
||||||
</document>
|
</document>
|
||||||
""".format(html.escape(SIMPLE_XMLFILE, True))
|
""".format(html.escape(SIMPLE_XMLFILE, True))
|
||||||
|
|
||||||
|
|
||||||
def xinclude_loader(href, parse="xml", encoding=None):
|
def xinclude_loader(href, parse="xml", encoding=None):
|
||||||
try:
|
try:
|
||||||
data = XINCLUDE[href]
|
data = XINCLUDE[href]
|
||||||
|
@ -1411,22 +1345,6 @@ def xinclude():
|
||||||
>>> # print(serialize(document)) # C5
|
>>> # print(serialize(document)) # C5
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def xinclude_default():
|
|
||||||
"""
|
|
||||||
>>> from xml.etree import ElementInclude
|
|
||||||
|
|
||||||
>>> document = xinclude_loader("default.xml")
|
|
||||||
>>> ElementInclude.include(document)
|
|
||||||
>>> print(serialize(document)) # default
|
|
||||||
<document>
|
|
||||||
<p>Example.</p>
|
|
||||||
<root>
|
|
||||||
<element key="value">text</element>
|
|
||||||
<element>text</element>tail
|
|
||||||
<empty-element />
|
|
||||||
</root>
|
|
||||||
</document>
|
|
||||||
"""
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# badly formatted xi:include tags
|
# badly formatted xi:include tags
|
||||||
|
@ -1917,9 +1835,8 @@ def test_istype(self):
|
||||||
self.assertIsInstance(ET.QName, type)
|
self.assertIsInstance(ET.QName, type)
|
||||||
self.assertIsInstance(ET.ElementTree, type)
|
self.assertIsInstance(ET.ElementTree, type)
|
||||||
self.assertIsInstance(ET.Element, type)
|
self.assertIsInstance(ET.Element, type)
|
||||||
# XXX issue 14128 with C ElementTree
|
self.assertIsInstance(ET.TreeBuilder, type)
|
||||||
# self.assertIsInstance(ET.TreeBuilder, type)
|
self.assertIsInstance(ET.XMLParser, type)
|
||||||
# self.assertIsInstance(ET.XMLParser, type)
|
|
||||||
|
|
||||||
def test_Element_subclass_trivial(self):
|
def test_Element_subclass_trivial(self):
|
||||||
class MyElement(ET.Element):
|
class MyElement(ET.Element):
|
||||||
|
@ -1953,6 +1870,73 @@ def newmethod(self):
|
||||||
self.assertEqual(mye.newmethod(), 'joe')
|
self.assertEqual(mye.newmethod(), 'joe')
|
||||||
|
|
||||||
|
|
||||||
|
class ElementIterTest(unittest.TestCase):
|
||||||
|
def _ilist(self, elem, tag=None):
|
||||||
|
return summarize_list(elem.iter(tag))
|
||||||
|
|
||||||
|
def test_basic(self):
|
||||||
|
doc = ET.XML("<html><body>this is a <i>paragraph</i>.</body>..</html>")
|
||||||
|
self.assertEqual(self._ilist(doc), ['html', 'body', 'i'])
|
||||||
|
self.assertEqual(self._ilist(doc.find('body')), ['body', 'i'])
|
||||||
|
self.assertEqual(next(doc.iter()).tag, 'html')
|
||||||
|
self.assertEqual(''.join(doc.itertext()), 'this is a paragraph...')
|
||||||
|
self.assertEqual(''.join(doc.find('body').itertext()),
|
||||||
|
'this is a paragraph.')
|
||||||
|
self.assertEqual(next(doc.itertext()), 'this is a ')
|
||||||
|
|
||||||
|
# iterparse should return an iterator
|
||||||
|
sourcefile = serialize(doc, to_string=False)
|
||||||
|
self.assertEqual(next(ET.iterparse(sourcefile))[0], 'end')
|
||||||
|
|
||||||
|
tree = ET.ElementTree(None)
|
||||||
|
self.assertRaises(AttributeError, tree.iter)
|
||||||
|
|
||||||
|
def test_corners(self):
|
||||||
|
# single root, no subelements
|
||||||
|
a = ET.Element('a')
|
||||||
|
self.assertEqual(self._ilist(a), ['a'])
|
||||||
|
|
||||||
|
# one child
|
||||||
|
b = ET.SubElement(a, 'b')
|
||||||
|
self.assertEqual(self._ilist(a), ['a', 'b'])
|
||||||
|
|
||||||
|
# one child and one grandchild
|
||||||
|
c = ET.SubElement(b, 'c')
|
||||||
|
self.assertEqual(self._ilist(a), ['a', 'b', 'c'])
|
||||||
|
|
||||||
|
# two children, only first with grandchild
|
||||||
|
d = ET.SubElement(a, 'd')
|
||||||
|
self.assertEqual(self._ilist(a), ['a', 'b', 'c', 'd'])
|
||||||
|
|
||||||
|
# replace first child by second
|
||||||
|
a[0] = a[1]
|
||||||
|
del a[1]
|
||||||
|
self.assertEqual(self._ilist(a), ['a', 'd'])
|
||||||
|
|
||||||
|
def test_iter_by_tag(self):
|
||||||
|
doc = ET.XML('''
|
||||||
|
<document>
|
||||||
|
<house>
|
||||||
|
<room>bedroom1</room>
|
||||||
|
<room>bedroom2</room>
|
||||||
|
</house>
|
||||||
|
<shed>nothing here
|
||||||
|
</shed>
|
||||||
|
<house>
|
||||||
|
<room>bedroom8</room>
|
||||||
|
</house>
|
||||||
|
</document>''')
|
||||||
|
|
||||||
|
self.assertEqual(self._ilist(doc, 'room'), ['room'] * 3)
|
||||||
|
self.assertEqual(self._ilist(doc, 'house'), ['house'] * 2)
|
||||||
|
|
||||||
|
# make sure both tag=None and tag='*' return all tags
|
||||||
|
all_tags = ['document', 'house', 'room', 'room',
|
||||||
|
'shed', 'house', 'room']
|
||||||
|
self.assertEqual(self._ilist(doc), all_tags)
|
||||||
|
self.assertEqual(self._ilist(doc, '*'), all_tags)
|
||||||
|
|
||||||
|
|
||||||
class TreeBuilderTest(unittest.TestCase):
|
class TreeBuilderTest(unittest.TestCase):
|
||||||
sample1 = ('<!DOCTYPE html PUBLIC'
|
sample1 = ('<!DOCTYPE html PUBLIC'
|
||||||
' "-//W3C//DTD XHTML 1.0 Transitional//EN"'
|
' "-//W3C//DTD XHTML 1.0 Transitional//EN"'
|
||||||
|
@ -2027,6 +2011,23 @@ def close(self):
|
||||||
'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd'))
|
'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd'))
|
||||||
|
|
||||||
|
|
||||||
|
@unittest.skip('Unstable due to module monkeypatching')
|
||||||
|
class XincludeTest(unittest.TestCase):
|
||||||
|
def test_xinclude_default(self):
|
||||||
|
from xml.etree import ElementInclude
|
||||||
|
doc = xinclude_loader('default.xml')
|
||||||
|
ElementInclude.include(doc)
|
||||||
|
s = serialize(doc)
|
||||||
|
self.assertEqual(s.strip(), '''<document>
|
||||||
|
<p>Example.</p>
|
||||||
|
<root>
|
||||||
|
<element key="value">text</element>
|
||||||
|
<element>text</element>tail
|
||||||
|
<empty-element />
|
||||||
|
</root>
|
||||||
|
</document>''')
|
||||||
|
|
||||||
|
|
||||||
class XMLParserTest(unittest.TestCase):
|
class XMLParserTest(unittest.TestCase):
|
||||||
sample1 = '<file><line>22</line></file>'
|
sample1 = '<file><line>22</line></file>'
|
||||||
sample2 = ('<!DOCTYPE html PUBLIC'
|
sample2 = ('<!DOCTYPE html PUBLIC'
|
||||||
|
@ -2073,13 +2074,6 @@ def doctype(self, name, pubid, system):
|
||||||
'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd'))
|
'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd'))
|
||||||
|
|
||||||
|
|
||||||
class NoAcceleratorTest(unittest.TestCase):
|
|
||||||
# Test that the C accelerator was not imported for pyET
|
|
||||||
def test_correct_import_pyET(self):
|
|
||||||
self.assertEqual(pyET.Element.__module__, 'xml.etree.ElementTree')
|
|
||||||
self.assertEqual(pyET.SubElement.__module__, 'xml.etree.ElementTree')
|
|
||||||
|
|
||||||
|
|
||||||
class NamespaceParseTest(unittest.TestCase):
|
class NamespaceParseTest(unittest.TestCase):
|
||||||
def test_find_with_namespace(self):
|
def test_find_with_namespace(self):
|
||||||
nsmap = {'h': 'hello', 'f': 'foo'}
|
nsmap = {'h': 'hello', 'f': 'foo'}
|
||||||
|
@ -2090,7 +2084,6 @@ def test_find_with_namespace(self):
|
||||||
self.assertEqual(len(doc.findall('.//{foo}name', nsmap)), 1)
|
self.assertEqual(len(doc.findall('.//{foo}name', nsmap)), 1)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class ElementSlicingTest(unittest.TestCase):
|
class ElementSlicingTest(unittest.TestCase):
|
||||||
def _elem_tags(self, elemlist):
|
def _elem_tags(self, elemlist):
|
||||||
return [e.tag for e in elemlist]
|
return [e.tag for e in elemlist]
|
||||||
|
@ -2232,6 +2225,14 @@ def test_issue14818(self):
|
||||||
with self.assertRaisesRegex(TypeError, 'must be dict, not str'):
|
with self.assertRaisesRegex(TypeError, 'must be dict, not str'):
|
||||||
ET.Element('a', attrib="I'm not a dict")
|
ET.Element('a', attrib="I'm not a dict")
|
||||||
|
|
||||||
|
# --------------------------------------------------------------------
|
||||||
|
|
||||||
|
@unittest.skipUnless(pyET, 'only for the Python version')
|
||||||
|
class NoAcceleratorTest(unittest.TestCase):
|
||||||
|
# Test that the C accelerator was not imported for pyET
|
||||||
|
def test_correct_import_pyET(self):
|
||||||
|
self.assertEqual(pyET.Element.__module__, 'xml.etree.ElementTree')
|
||||||
|
self.assertEqual(pyET.SubElement.__module__, 'xml.etree.ElementTree')
|
||||||
|
|
||||||
# --------------------------------------------------------------------
|
# --------------------------------------------------------------------
|
||||||
|
|
||||||
|
@ -2276,31 +2277,42 @@ def __exit__(self, *args):
|
||||||
self.checkwarnings.__exit__(*args)
|
self.checkwarnings.__exit__(*args)
|
||||||
|
|
||||||
|
|
||||||
def test_main(module=pyET):
|
def test_main(module=None):
|
||||||
from test import test_xml_etree
|
# When invoked without a module, runs the Python ET tests by loading pyET.
|
||||||
|
# Otherwise, uses the given module as the ET.
|
||||||
|
if module is None:
|
||||||
|
global pyET
|
||||||
|
pyET = import_fresh_module('xml.etree.ElementTree',
|
||||||
|
blocked=['_elementtree'])
|
||||||
|
module = pyET
|
||||||
|
|
||||||
# The same doctests are used for both the Python and the C implementations
|
global ET
|
||||||
test_xml_etree.ET = module
|
ET = module
|
||||||
|
|
||||||
test_classes = [
|
test_classes = [
|
||||||
ElementSlicingTest,
|
ElementSlicingTest,
|
||||||
BasicElementTest,
|
BasicElementTest,
|
||||||
StringIOTest,
|
StringIOTest,
|
||||||
ParseErrorTest,
|
ParseErrorTest,
|
||||||
|
XincludeTest,
|
||||||
ElementTreeTest,
|
ElementTreeTest,
|
||||||
NamespaceParseTest,
|
ElementIterTest,
|
||||||
TreeBuilderTest,
|
TreeBuilderTest,
|
||||||
XMLParserTest,
|
]
|
||||||
KeywordArgsTest]
|
|
||||||
if module is pyET:
|
# These tests will only run for the pure-Python version that doesn't import
|
||||||
# Run the tests specific to the Python implementation
|
# _elementtree. We can't use skipUnless here, because pyET is filled in only
|
||||||
test_classes += [NoAcceleratorTest]
|
# after the module is loaded.
|
||||||
|
if pyET:
|
||||||
|
test_classes.extend([
|
||||||
|
NoAcceleratorTest,
|
||||||
|
])
|
||||||
|
|
||||||
support.run_unittest(*test_classes)
|
support.run_unittest(*test_classes)
|
||||||
|
|
||||||
# XXX the C module should give the same warnings as the Python module
|
# XXX the C module should give the same warnings as the Python module
|
||||||
with CleanContext(quiet=(module is not pyET)):
|
with CleanContext(quiet=(module is not pyET)):
|
||||||
support.run_doctest(test_xml_etree, verbosity=True)
|
support.run_doctest(sys.modules[__name__], verbosity=True)
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
test_main()
|
test_main()
|
||||||
|
|
|
@ -8,31 +8,6 @@
|
||||||
cET_alias = import_fresh_module('xml.etree.cElementTree', fresh=['_elementtree', 'xml.etree'])
|
cET_alias = import_fresh_module('xml.etree.cElementTree', fresh=['_elementtree', 'xml.etree'])
|
||||||
|
|
||||||
|
|
||||||
# cElementTree specific tests
|
|
||||||
|
|
||||||
def sanity():
|
|
||||||
r"""
|
|
||||||
Import sanity.
|
|
||||||
|
|
||||||
Issue #6697.
|
|
||||||
|
|
||||||
>>> cElementTree = cET
|
|
||||||
>>> e = cElementTree.Element('a')
|
|
||||||
>>> getattr(e, '\uD800') # doctest: +ELLIPSIS
|
|
||||||
Traceback (most recent call last):
|
|
||||||
...
|
|
||||||
UnicodeEncodeError: ...
|
|
||||||
|
|
||||||
>>> p = cElementTree.XMLParser()
|
|
||||||
>>> p.version.split()[0]
|
|
||||||
'Expat'
|
|
||||||
>>> getattr(p, '\uD800')
|
|
||||||
Traceback (most recent call last):
|
|
||||||
...
|
|
||||||
AttributeError: 'XMLParser' object has no attribute '\ud800'
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
class MiscTests(unittest.TestCase):
|
class MiscTests(unittest.TestCase):
|
||||||
# Issue #8651.
|
# Issue #8651.
|
||||||
@support.bigmemtest(size=support._2G + 100, memuse=1)
|
@support.bigmemtest(size=support._2G + 100, memuse=1)
|
||||||
|
@ -46,6 +21,7 @@ def test_length_overflow(self, size):
|
||||||
finally:
|
finally:
|
||||||
data = None
|
data = None
|
||||||
|
|
||||||
|
|
||||||
@unittest.skipUnless(cET, 'requires _elementtree')
|
@unittest.skipUnless(cET, 'requires _elementtree')
|
||||||
class TestAliasWorking(unittest.TestCase):
|
class TestAliasWorking(unittest.TestCase):
|
||||||
# Test that the cET alias module is alive
|
# Test that the cET alias module is alive
|
||||||
|
@ -53,6 +29,7 @@ def test_alias_working(self):
|
||||||
e = cET_alias.Element('foo')
|
e = cET_alias.Element('foo')
|
||||||
self.assertEqual(e.tag, 'foo')
|
self.assertEqual(e.tag, 'foo')
|
||||||
|
|
||||||
|
|
||||||
@unittest.skipUnless(cET, 'requires _elementtree')
|
@unittest.skipUnless(cET, 'requires _elementtree')
|
||||||
class TestAcceleratorImported(unittest.TestCase):
|
class TestAcceleratorImported(unittest.TestCase):
|
||||||
# Test that the C accelerator was imported, as expected
|
# Test that the C accelerator was imported, as expected
|
||||||
|
@ -67,7 +44,6 @@ def test_main():
|
||||||
from test import test_xml_etree, test_xml_etree_c
|
from test import test_xml_etree, test_xml_etree_c
|
||||||
|
|
||||||
# Run the tests specific to the C implementation
|
# Run the tests specific to the C implementation
|
||||||
support.run_doctest(test_xml_etree_c, verbosity=True)
|
|
||||||
support.run_unittest(
|
support.run_unittest(
|
||||||
MiscTests,
|
MiscTests,
|
||||||
TestAliasWorking,
|
TestAliasWorking,
|
||||||
|
|
|
@ -101,32 +101,8 @@
|
||||||
import re
|
import re
|
||||||
import warnings
|
import warnings
|
||||||
|
|
||||||
class _SimpleElementPath:
|
from . import ElementPath
|
||||||
# emulate pre-1.2 find/findtext/findall behaviour
|
|
||||||
def find(self, element, tag, namespaces=None):
|
|
||||||
for elem in element:
|
|
||||||
if elem.tag == tag:
|
|
||||||
return elem
|
|
||||||
return None
|
|
||||||
def findtext(self, element, tag, default=None, namespaces=None):
|
|
||||||
elem = self.find(element, tag)
|
|
||||||
if elem is None:
|
|
||||||
return default
|
|
||||||
return elem.text or ""
|
|
||||||
def iterfind(self, element, tag, namespaces=None):
|
|
||||||
if tag[:3] == ".//":
|
|
||||||
for elem in element.iter(tag[3:]):
|
|
||||||
yield elem
|
|
||||||
for elem in element:
|
|
||||||
if elem.tag == tag:
|
|
||||||
yield elem
|
|
||||||
def findall(self, element, tag, namespaces=None):
|
|
||||||
return list(self.iterfind(element, tag, namespaces))
|
|
||||||
|
|
||||||
try:
|
|
||||||
from . import ElementPath
|
|
||||||
except ImportError:
|
|
||||||
ElementPath = _SimpleElementPath()
|
|
||||||
|
|
||||||
##
|
##
|
||||||
# Parser error. This is a subclass of <b>SyntaxError</b>.
|
# Parser error. This is a subclass of <b>SyntaxError</b>.
|
||||||
|
@ -916,11 +892,7 @@ def add_qname(qname):
|
||||||
_raise_serialization_error(qname)
|
_raise_serialization_error(qname)
|
||||||
|
|
||||||
# populate qname and namespaces table
|
# populate qname and namespaces table
|
||||||
try:
|
for elem in elem.iter():
|
||||||
iterate = elem.iter
|
|
||||||
except AttributeError:
|
|
||||||
iterate = elem.getiterator # cET compatibility
|
|
||||||
for elem in iterate():
|
|
||||||
tag = elem.tag
|
tag = elem.tag
|
||||||
if isinstance(tag, QName):
|
if isinstance(tag, QName):
|
||||||
if tag.text not in qnames:
|
if tag.text not in qnames:
|
||||||
|
|
29
Misc/NEWS
29
Misc/NEWS
|
@ -10,6 +10,9 @@ What's New in Python 3.3.0 Beta 1?
|
||||||
Core and Builtins
|
Core and Builtins
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
|
- Issue #15026: utf-16 encoding is now significantly faster (up to 10x).
|
||||||
|
Patch by Serhiy Storchaka.
|
||||||
|
|
||||||
- Issue #11022: open() and io.TextIOWrapper are now calling
|
- Issue #11022: open() and io.TextIOWrapper are now calling
|
||||||
locale.getpreferredencoding(False) instead of locale.getpreferredencoding()
|
locale.getpreferredencoding(False) instead of locale.getpreferredencoding()
|
||||||
in text mode if the encoding is not specified. Don't change temporary the
|
in text mode if the encoding is not specified. Don't change temporary the
|
||||||
|
@ -21,6 +24,32 @@ Core and Builtins
|
||||||
Library
|
Library
|
||||||
-------
|
-------
|
||||||
|
|
||||||
|
- Issue #15036: Allow removing or changing multiple items in
|
||||||
|
single-file mailboxes (mbox, MMDF, Babyl) flushing the mailbox
|
||||||
|
between the changes.
|
||||||
|
|
||||||
|
- Issue #14059: Implement multiprocessing.Barrier.
|
||||||
|
|
||||||
|
- Issue #15061: The inappropriately named hmac.secure_compare has been
|
||||||
|
renamed to hmac.compare_digest, restricted to operating on bytes inputs
|
||||||
|
only and had its documentation updated to more accurately reflect both its
|
||||||
|
intent and its limitations
|
||||||
|
|
||||||
|
- Issue #13841: Make child processes exit using sys.exit() on Windows.
|
||||||
|
|
||||||
|
- Issue #14936: curses_panel was converted to PEP 3121 and PEP 384 API.
|
||||||
|
Patch by Robin Schreiber.
|
||||||
|
|
||||||
|
- Issue #1667546: On platforms supporting tm_zone and tm_gmtoff fields
|
||||||
|
in struct tm, time.struct_time objects returned by time.gmtime(),
|
||||||
|
time.localtime() and time.strptime() functions now have tm_zone and
|
||||||
|
tm_gmtoff attributes. Original patch by Paul Boddie.
|
||||||
|
|
||||||
|
- Rename adjusted attribute to adjustable in time.get_clock_info() result.
|
||||||
|
|
||||||
|
- Issue #3518: Remove references to non-existent BaseManager.from_address()
|
||||||
|
method.
|
||||||
|
|
||||||
- Issue #13857: Added textwrap.indent() function (initial patch by Ezra
|
- Issue #13857: Added textwrap.indent() function (initial patch by Ezra
|
||||||
Berch)
|
Berch)
|
||||||
|
|
||||||
|
|
|
@ -16,8 +16,37 @@ static char *PyCursesVersion = "2.1";
|
||||||
|
|
||||||
#include <panel.h>
|
#include <panel.h>
|
||||||
|
|
||||||
static PyObject *PyCursesError;
|
typedef struct {
|
||||||
|
PyObject *PyCursesError;
|
||||||
|
PyObject *PyCursesPanel_Type;
|
||||||
|
} _curses_panelstate;
|
||||||
|
|
||||||
|
#define _curses_panelstate(o) ((_curses_panelstate *)PyModule_GetState(o))
|
||||||
|
|
||||||
|
static int
|
||||||
|
_curses_panel_clear(PyObject *m)
|
||||||
|
{
|
||||||
|
Py_CLEAR(_curses_panelstate(m)->PyCursesError);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
_curses_panel_traverse(PyObject *m, visitproc visit, void *arg)
|
||||||
|
{
|
||||||
|
Py_VISIT(_curses_panelstate(m)->PyCursesError);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_curses_panel_free(void *m)
|
||||||
|
{
|
||||||
|
_curses_panel_clear((PyObject *) m);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct PyModuleDef _curses_panelmodule;
|
||||||
|
|
||||||
|
#define _curses_panelstate_global \
|
||||||
|
((_curses_panelstate *) PyModule_GetState(PyState_FindModule(&_curses_panelmodule)))
|
||||||
|
|
||||||
/* Utility Functions */
|
/* Utility Functions */
|
||||||
|
|
||||||
|
@ -34,9 +63,9 @@ PyCursesCheckERR(int code, char *fname)
|
||||||
return Py_None;
|
return Py_None;
|
||||||
} else {
|
} else {
|
||||||
if (fname == NULL) {
|
if (fname == NULL) {
|
||||||
PyErr_SetString(PyCursesError, catchall_ERR);
|
PyErr_SetString(_curses_panelstate_global->PyCursesError, catchall_ERR);
|
||||||
} else {
|
} else {
|
||||||
PyErr_Format(PyCursesError, "%s() returned ERR", fname);
|
PyErr_Format(_curses_panelstate_global->PyCursesError, "%s() returned ERR", fname);
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -54,9 +83,8 @@ typedef struct {
|
||||||
PyCursesWindowObject *wo; /* for reference counts */
|
PyCursesWindowObject *wo; /* for reference counts */
|
||||||
} PyCursesPanelObject;
|
} PyCursesPanelObject;
|
||||||
|
|
||||||
PyTypeObject PyCursesPanel_Type;
|
#define PyCursesPanel_Check(v) \
|
||||||
|
(Py_TYPE(v) == _curses_panelstate_global->PyCursesPanel_Type)
|
||||||
#define PyCursesPanel_Check(v) (Py_TYPE(v) == &PyCursesPanel_Type)
|
|
||||||
|
|
||||||
/* Some helper functions. The problem is that there's always a window
|
/* Some helper functions. The problem is that there's always a window
|
||||||
associated with a panel. To ensure that Python's GC doesn't pull
|
associated with a panel. To ensure that Python's GC doesn't pull
|
||||||
|
@ -175,7 +203,8 @@ PyCursesPanel_New(PANEL *pan, PyCursesWindowObject *wo)
|
||||||
{
|
{
|
||||||
PyCursesPanelObject *po;
|
PyCursesPanelObject *po;
|
||||||
|
|
||||||
po = PyObject_NEW(PyCursesPanelObject, &PyCursesPanel_Type);
|
po = PyObject_NEW(PyCursesPanelObject,
|
||||||
|
(PyTypeObject *)(_curses_panelstate_global)->PyCursesPanel_Type);
|
||||||
if (po == NULL) return NULL;
|
if (po == NULL) return NULL;
|
||||||
po->pan = pan;
|
po->pan = pan;
|
||||||
if (insert_lop(po) < 0) {
|
if (insert_lop(po) < 0) {
|
||||||
|
@ -280,7 +309,7 @@ PyCursesPanel_replace_panel(PyCursesPanelObject *self, PyObject *args)
|
||||||
|
|
||||||
rtn = replace_panel(self->pan, temp->win);
|
rtn = replace_panel(self->pan, temp->win);
|
||||||
if (rtn == ERR) {
|
if (rtn == ERR) {
|
||||||
PyErr_SetString(PyCursesError, "replace_panel() returned ERR");
|
PyErr_SetString(_curses_panelstate_global->PyCursesError, "replace_panel() returned ERR");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
Py_DECREF(po->wo);
|
Py_DECREF(po->wo);
|
||||||
|
@ -305,7 +334,7 @@ PyCursesPanel_userptr(PyCursesPanelObject *self)
|
||||||
PyCursesInitialised;
|
PyCursesInitialised;
|
||||||
obj = (PyObject *) panel_userptr(self->pan);
|
obj = (PyObject *) panel_userptr(self->pan);
|
||||||
if (obj == NULL) {
|
if (obj == NULL) {
|
||||||
PyErr_SetString(PyCursesError, "no userptr set");
|
PyErr_SetString(_curses_panelstate_global->PyCursesError, "no userptr set");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -334,36 +363,18 @@ static PyMethodDef PyCursesPanel_Methods[] = {
|
||||||
|
|
||||||
/* -------------------------------------------------------*/
|
/* -------------------------------------------------------*/
|
||||||
|
|
||||||
PyTypeObject PyCursesPanel_Type = {
|
static PyType_Slot PyCursesPanel_Type_slots[] = {
|
||||||
PyVarObject_HEAD_INIT(NULL, 0)
|
{Py_tp_dealloc, PyCursesPanel_Dealloc},
|
||||||
"_curses_panel.curses panel", /*tp_name*/
|
{Py_tp_methods, PyCursesPanel_Methods},
|
||||||
sizeof(PyCursesPanelObject), /*tp_basicsize*/
|
{0, 0},
|
||||||
0, /*tp_itemsize*/
|
};
|
||||||
/* methods */
|
|
||||||
(destructor)PyCursesPanel_Dealloc, /*tp_dealloc*/
|
static PyType_Spec PyCursesPanel_Type_spec = {
|
||||||
0, /*tp_print*/
|
"_curses_panel.curses panel",
|
||||||
0, /*tp_getattr*/
|
sizeof(PyCursesPanelObject),
|
||||||
0, /*tp_setattr*/
|
0,
|
||||||
0, /*tp_reserved*/
|
Py_TPFLAGS_DEFAULT,
|
||||||
0, /*tp_repr*/
|
PyCursesPanel_Type_slots
|
||||||
0, /*tp_as_number*/
|
|
||||||
0, /*tp_as_sequence*/
|
|
||||||
0, /*tp_as_mapping*/
|
|
||||||
0, /*tp_hash*/
|
|
||||||
0, /*tp_call*/
|
|
||||||
0, /*tp_str*/
|
|
||||||
0, /*tp_getattro*/
|
|
||||||
0, /*tp_setattro*/
|
|
||||||
0, /*tp_as_buffer*/
|
|
||||||
Py_TPFLAGS_DEFAULT, /*tp_flags*/
|
|
||||||
0, /*tp_doc*/
|
|
||||||
0, /*tp_traverse*/
|
|
||||||
0, /*tp_clear*/
|
|
||||||
0, /*tp_richcompare*/
|
|
||||||
0, /*tp_weaklistoffset*/
|
|
||||||
0, /*tp_iter*/
|
|
||||||
0, /*tp_iternext*/
|
|
||||||
PyCursesPanel_Methods, /*tp_methods*/
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Wrapper for panel_above(NULL). This function returns the bottom
|
/* Wrapper for panel_above(NULL). This function returns the bottom
|
||||||
|
@ -405,7 +416,7 @@ PyCurses_new_panel(PyObject *self, PyObject *args)
|
||||||
return NULL;
|
return NULL;
|
||||||
pan = new_panel(win->win);
|
pan = new_panel(win->win);
|
||||||
if (pan == NULL) {
|
if (pan == NULL) {
|
||||||
PyErr_SetString(PyCursesError, catchall_NULL);
|
PyErr_SetString(_curses_panelstate_global->PyCursesError, catchall_NULL);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
return (PyObject *)PyCursesPanel_New(pan, win);
|
return (PyObject *)PyCursesPanel_New(pan, win);
|
||||||
|
@ -467,12 +478,12 @@ static struct PyModuleDef _curses_panelmodule = {
|
||||||
PyModuleDef_HEAD_INIT,
|
PyModuleDef_HEAD_INIT,
|
||||||
"_curses_panel",
|
"_curses_panel",
|
||||||
NULL,
|
NULL,
|
||||||
-1,
|
sizeof(_curses_panelstate),
|
||||||
PyCurses_methods,
|
PyCurses_methods,
|
||||||
NULL,
|
NULL,
|
||||||
NULL,
|
_curses_panel_traverse,
|
||||||
NULL,
|
_curses_panel_clear,
|
||||||
NULL
|
_curses_panel_free
|
||||||
};
|
};
|
||||||
|
|
||||||
PyMODINIT_FUNC
|
PyMODINIT_FUNC
|
||||||
|
@ -480,21 +491,23 @@ PyInit__curses_panel(void)
|
||||||
{
|
{
|
||||||
PyObject *m, *d, *v;
|
PyObject *m, *d, *v;
|
||||||
|
|
||||||
/* Initialize object type */
|
|
||||||
if (PyType_Ready(&PyCursesPanel_Type) < 0)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
import_curses();
|
|
||||||
|
|
||||||
/* Create the module and add the functions */
|
/* Create the module and add the functions */
|
||||||
m = PyModule_Create(&_curses_panelmodule);
|
m = PyModule_Create(&_curses_panelmodule);
|
||||||
if (m == NULL)
|
if (m == NULL)
|
||||||
return NULL;
|
goto fail;
|
||||||
d = PyModule_GetDict(m);
|
d = PyModule_GetDict(m);
|
||||||
|
|
||||||
|
/* Initialize object type */
|
||||||
|
_curses_panelstate(m)->PyCursesPanel_Type = \
|
||||||
|
PyType_FromSpec(&PyCursesPanel_Type_spec);
|
||||||
|
if (_curses_panelstate(m)->PyCursesPanel_Type == NULL)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
import_curses();
|
||||||
|
|
||||||
/* For exception _curses_panel.error */
|
/* For exception _curses_panel.error */
|
||||||
PyCursesError = PyErr_NewException("_curses_panel.error", NULL, NULL);
|
_curses_panelstate(m)->PyCursesError = PyErr_NewException("_curses_panel.error", NULL, NULL);
|
||||||
PyDict_SetItemString(d, "error", PyCursesError);
|
PyDict_SetItemString(d, "error", _curses_panelstate(m)->PyCursesError);
|
||||||
|
|
||||||
/* Make the version available */
|
/* Make the version available */
|
||||||
v = PyUnicode_FromString(PyCursesVersion);
|
v = PyUnicode_FromString(PyCursesVersion);
|
||||||
|
@ -502,4 +515,7 @@ PyInit__curses_panel(void)
|
||||||
PyDict_SetItemString(d, "__version__", v);
|
PyDict_SetItemString(d, "__version__", v);
|
||||||
Py_DECREF(v);
|
Py_DECREF(v);
|
||||||
return m;
|
return m;
|
||||||
|
fail:
|
||||||
|
Py_XDECREF(m);
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
|
@ -107,8 +107,9 @@ static inline void _mpd_qmul(mpd_t *result, const mpd_t *a, const mpd_t *b,
|
||||||
const mpd_context_t *ctx, uint32_t *status);
|
const mpd_context_t *ctx, uint32_t *status);
|
||||||
static void _mpd_base_ndivmod(mpd_t *q, mpd_t *r, const mpd_t *a,
|
static void _mpd_base_ndivmod(mpd_t *q, mpd_t *r, const mpd_t *a,
|
||||||
const mpd_t *b, uint32_t *status);
|
const mpd_t *b, uint32_t *status);
|
||||||
static inline void _mpd_qpow_uint(mpd_t *result, mpd_t *base, mpd_uint_t exp,
|
static inline void _mpd_qpow_uint(mpd_t *result, const mpd_t *base,
|
||||||
uint8_t resultsign, const mpd_context_t *ctx, uint32_t *status);
|
mpd_uint_t exp, uint8_t resultsign,
|
||||||
|
const mpd_context_t *ctx, uint32_t *status);
|
||||||
|
|
||||||
mpd_uint_t mpd_qsshiftr(mpd_t *result, const mpd_t *a, mpd_ssize_t n);
|
mpd_uint_t mpd_qsshiftr(mpd_t *result, const mpd_t *a, mpd_ssize_t n);
|
||||||
|
|
||||||
|
@ -5841,12 +5842,12 @@ mpd_qnext_toward(mpd_t *result, const mpd_t *a, const mpd_t *b,
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Internal function: Integer power with mpd_uint_t exponent, base is modified!
|
* Internal function: Integer power with mpd_uint_t exponent. The function
|
||||||
* Function can fail with MPD_Malloc_error.
|
* can fail with MPD_Malloc_error.
|
||||||
*/
|
*/
|
||||||
static inline void
|
static inline void
|
||||||
_mpd_qpow_uint(mpd_t *result, mpd_t *base, mpd_uint_t exp, uint8_t resultsign,
|
_mpd_qpow_uint(mpd_t *result, const mpd_t *base, mpd_uint_t exp,
|
||||||
const mpd_context_t *ctx, uint32_t *status)
|
uint8_t resultsign, const mpd_context_t *ctx, uint32_t *status)
|
||||||
{
|
{
|
||||||
uint32_t workstatus = 0;
|
uint32_t workstatus = 0;
|
||||||
mpd_uint_t n;
|
mpd_uint_t n;
|
||||||
|
@ -5866,7 +5867,8 @@ _mpd_qpow_uint(mpd_t *result, mpd_t *base, mpd_uint_t exp, uint8_t resultsign,
|
||||||
if (exp & n) {
|
if (exp & n) {
|
||||||
mpd_qmul(result, result, base, ctx, &workstatus);
|
mpd_qmul(result, result, base, ctx, &workstatus);
|
||||||
}
|
}
|
||||||
if (workstatus & (MPD_Overflow|MPD_Clamped)) {
|
if (mpd_isspecial(result) ||
|
||||||
|
(mpd_iszerocoeff(result) && (workstatus & MPD_Clamped))) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -103,8 +103,6 @@ do { memory -= size; printf("%8d - %s\n", memory, comment); } while (0)
|
||||||
/* glue functions (see the init function for details) */
|
/* glue functions (see the init function for details) */
|
||||||
static PyObject* elementtree_parseerror_obj;
|
static PyObject* elementtree_parseerror_obj;
|
||||||
static PyObject* elementtree_deepcopy_obj;
|
static PyObject* elementtree_deepcopy_obj;
|
||||||
static PyObject* elementtree_iter_obj;
|
|
||||||
static PyObject* elementtree_itertext_obj;
|
|
||||||
static PyObject* elementpath_obj;
|
static PyObject* elementpath_obj;
|
||||||
|
|
||||||
/* helpers */
|
/* helpers */
|
||||||
|
@ -1109,67 +1107,32 @@ element_getchildren(ElementObject* self, PyObject* args)
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject*
|
|
||||||
element_iter(ElementObject* self, PyObject* args)
|
|
||||||
{
|
|
||||||
PyObject* result;
|
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
create_elementiter(ElementObject *self, PyObject *tag, int gettext);
|
||||||
|
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
element_iter(ElementObject *self, PyObject *args)
|
||||||
|
{
|
||||||
PyObject* tag = Py_None;
|
PyObject* tag = Py_None;
|
||||||
if (!PyArg_ParseTuple(args, "|O:iter", &tag))
|
if (!PyArg_ParseTuple(args, "|O:iter", &tag))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if (!elementtree_iter_obj) {
|
return create_elementiter(self, tag, 0);
|
||||||
PyErr_SetString(
|
|
||||||
PyExc_RuntimeError,
|
|
||||||
"iter helper not found"
|
|
||||||
);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
args = PyTuple_New(2);
|
|
||||||
if (!args)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
Py_INCREF(self); PyTuple_SET_ITEM(args, 0, (PyObject*) self);
|
|
||||||
Py_INCREF(tag); PyTuple_SET_ITEM(args, 1, (PyObject*) tag);
|
|
||||||
|
|
||||||
result = PyObject_CallObject(elementtree_iter_obj, args);
|
|
||||||
|
|
||||||
Py_DECREF(args);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static PyObject*
|
static PyObject*
|
||||||
element_itertext(ElementObject* self, PyObject* args)
|
element_itertext(ElementObject* self, PyObject* args)
|
||||||
{
|
{
|
||||||
PyObject* result;
|
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args, ":itertext"))
|
if (!PyArg_ParseTuple(args, ":itertext"))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if (!elementtree_itertext_obj) {
|
return create_elementiter(self, Py_None, 1);
|
||||||
PyErr_SetString(
|
|
||||||
PyExc_RuntimeError,
|
|
||||||
"itertext helper not found"
|
|
||||||
);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
args = PyTuple_New(1);
|
|
||||||
if (!args)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
Py_INCREF(self); PyTuple_SET_ITEM(args, 0, (PyObject*) self);
|
|
||||||
|
|
||||||
result = PyObject_CallObject(elementtree_itertext_obj, args);
|
|
||||||
|
|
||||||
Py_DECREF(args);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static PyObject*
|
static PyObject*
|
||||||
element_getitem(PyObject* self_, Py_ssize_t index)
|
element_getitem(PyObject* self_, Py_ssize_t index)
|
||||||
{
|
{
|
||||||
|
@ -1790,6 +1753,269 @@ static PyTypeObject Element_Type = {
|
||||||
0, /* tp_free */
|
0, /* tp_free */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/******************************* Element iterator ****************************/
|
||||||
|
|
||||||
|
/* ElementIterObject represents the iteration state over an XML element in
|
||||||
|
* pre-order traversal. To keep track of which sub-element should be returned
|
||||||
|
* next, a stack of parents is maintained. This is a standard stack-based
|
||||||
|
* iterative pre-order traversal of a tree.
|
||||||
|
* The stack is managed using a single-linked list starting at parent_stack.
|
||||||
|
* Each stack node contains the saved parent to which we should return after
|
||||||
|
* the current one is exhausted, and the next child to examine in that parent.
|
||||||
|
*/
|
||||||
|
typedef struct ParentLocator_t {
|
||||||
|
ElementObject *parent;
|
||||||
|
Py_ssize_t child_index;
|
||||||
|
struct ParentLocator_t *next;
|
||||||
|
} ParentLocator;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
PyObject_HEAD
|
||||||
|
ParentLocator *parent_stack;
|
||||||
|
ElementObject *root_element;
|
||||||
|
PyObject *sought_tag;
|
||||||
|
int root_done;
|
||||||
|
int gettext;
|
||||||
|
} ElementIterObject;
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
elementiter_dealloc(ElementIterObject *it)
|
||||||
|
{
|
||||||
|
ParentLocator *p = it->parent_stack;
|
||||||
|
while (p) {
|
||||||
|
ParentLocator *temp = p;
|
||||||
|
Py_XDECREF(p->parent);
|
||||||
|
p = p->next;
|
||||||
|
PyObject_Free(temp);
|
||||||
|
}
|
||||||
|
|
||||||
|
Py_XDECREF(it->sought_tag);
|
||||||
|
Py_XDECREF(it->root_element);
|
||||||
|
|
||||||
|
PyObject_GC_UnTrack(it);
|
||||||
|
PyObject_GC_Del(it);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
elementiter_traverse(ElementIterObject *it, visitproc visit, void *arg)
|
||||||
|
{
|
||||||
|
ParentLocator *p = it->parent_stack;
|
||||||
|
while (p) {
|
||||||
|
Py_VISIT(p->parent);
|
||||||
|
p = p->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
Py_VISIT(it->root_element);
|
||||||
|
Py_VISIT(it->sought_tag);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Helper function for elementiter_next. Add a new parent to the parent stack.
|
||||||
|
*/
|
||||||
|
static ParentLocator *
|
||||||
|
parent_stack_push_new(ParentLocator *stack, ElementObject *parent)
|
||||||
|
{
|
||||||
|
ParentLocator *new_node = PyObject_Malloc(sizeof(ParentLocator));
|
||||||
|
if (new_node) {
|
||||||
|
new_node->parent = parent;
|
||||||
|
Py_INCREF(parent);
|
||||||
|
new_node->child_index = 0;
|
||||||
|
new_node->next = stack;
|
||||||
|
}
|
||||||
|
return new_node;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
elementiter_next(ElementIterObject *it)
|
||||||
|
{
|
||||||
|
/* Sub-element iterator.
|
||||||
|
*
|
||||||
|
* A short note on gettext: this function serves both the iter() and
|
||||||
|
* itertext() methods to avoid code duplication. However, there are a few
|
||||||
|
* small differences in the way these iterations work. Namely:
|
||||||
|
* - itertext() only yields text from nodes that have it, and continues
|
||||||
|
* iterating when a node doesn't have text (so it doesn't return any
|
||||||
|
* node like iter())
|
||||||
|
* - itertext() also has to handle tail, after finishing with all the
|
||||||
|
* children of a node.
|
||||||
|
*/
|
||||||
|
ElementObject *cur_parent;
|
||||||
|
Py_ssize_t child_index;
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
/* Handle the case reached in the beginning and end of iteration, where
|
||||||
|
* the parent stack is empty. The root_done flag gives us indication
|
||||||
|
* whether we've just started iterating (so root_done is 0), in which
|
||||||
|
* case the root is returned. If root_done is 1 and we're here, the
|
||||||
|
* iterator is exhausted.
|
||||||
|
*/
|
||||||
|
if (!it->parent_stack->parent) {
|
||||||
|
if (it->root_done) {
|
||||||
|
PyErr_SetNone(PyExc_StopIteration);
|
||||||
|
return NULL;
|
||||||
|
} else {
|
||||||
|
it->parent_stack = parent_stack_push_new(it->parent_stack,
|
||||||
|
it->root_element);
|
||||||
|
if (!it->parent_stack) {
|
||||||
|
PyErr_NoMemory();
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
it->root_done = 1;
|
||||||
|
if (it->sought_tag == Py_None ||
|
||||||
|
PyObject_RichCompareBool(it->root_element->tag,
|
||||||
|
it->sought_tag, Py_EQ) == 1) {
|
||||||
|
if (it->gettext) {
|
||||||
|
PyObject *text = JOIN_OBJ(it->root_element->text);
|
||||||
|
if (PyObject_IsTrue(text)) {
|
||||||
|
Py_INCREF(text);
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Py_INCREF(it->root_element);
|
||||||
|
return (PyObject *)it->root_element;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* See if there are children left to traverse in the current parent. If
|
||||||
|
* yes, visit the next child. If not, pop the stack and try again.
|
||||||
|
*/
|
||||||
|
cur_parent = it->parent_stack->parent;
|
||||||
|
child_index = it->parent_stack->child_index;
|
||||||
|
if (cur_parent->extra && child_index < cur_parent->extra->length) {
|
||||||
|
ElementObject *child = (ElementObject *)
|
||||||
|
cur_parent->extra->children[child_index];
|
||||||
|
it->parent_stack->child_index++;
|
||||||
|
it->parent_stack = parent_stack_push_new(it->parent_stack,
|
||||||
|
child);
|
||||||
|
if (!it->parent_stack) {
|
||||||
|
PyErr_NoMemory();
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (it->gettext) {
|
||||||
|
PyObject *text = JOIN_OBJ(child->text);
|
||||||
|
if (PyObject_IsTrue(text)) {
|
||||||
|
Py_INCREF(text);
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
} else if (it->sought_tag == Py_None ||
|
||||||
|
PyObject_RichCompareBool(child->tag,
|
||||||
|
it->sought_tag, Py_EQ) == 1) {
|
||||||
|
Py_INCREF(child);
|
||||||
|
return (PyObject *)child;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
PyObject *tail = it->gettext ? JOIN_OBJ(cur_parent->tail) : Py_None;
|
||||||
|
ParentLocator *next = it->parent_stack->next;
|
||||||
|
Py_XDECREF(it->parent_stack->parent);
|
||||||
|
PyObject_Free(it->parent_stack);
|
||||||
|
it->parent_stack = next;
|
||||||
|
|
||||||
|
/* Note that extra condition on it->parent_stack->parent here;
|
||||||
|
* this is because itertext() is supposed to only return *inner*
|
||||||
|
* text, not text following the element it began iteration with.
|
||||||
|
*/
|
||||||
|
if (it->parent_stack->parent && PyObject_IsTrue(tail)) {
|
||||||
|
Py_INCREF(tail);
|
||||||
|
return tail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static PyTypeObject ElementIter_Type = {
|
||||||
|
PyVarObject_HEAD_INIT(NULL, 0)
|
||||||
|
"_elementtree._element_iterator", /* tp_name */
|
||||||
|
sizeof(ElementIterObject), /* tp_basicsize */
|
||||||
|
0, /* tp_itemsize */
|
||||||
|
/* methods */
|
||||||
|
(destructor)elementiter_dealloc, /* tp_dealloc */
|
||||||
|
0, /* tp_print */
|
||||||
|
0, /* tp_getattr */
|
||||||
|
0, /* tp_setattr */
|
||||||
|
0, /* tp_reserved */
|
||||||
|
0, /* tp_repr */
|
||||||
|
0, /* tp_as_number */
|
||||||
|
0, /* tp_as_sequence */
|
||||||
|
0, /* tp_as_mapping */
|
||||||
|
0, /* tp_hash */
|
||||||
|
0, /* tp_call */
|
||||||
|
0, /* tp_str */
|
||||||
|
0, /* tp_getattro */
|
||||||
|
0, /* tp_setattro */
|
||||||
|
0, /* tp_as_buffer */
|
||||||
|
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
|
||||||
|
0, /* tp_doc */
|
||||||
|
(traverseproc)elementiter_traverse, /* tp_traverse */
|
||||||
|
0, /* tp_clear */
|
||||||
|
0, /* tp_richcompare */
|
||||||
|
0, /* tp_weaklistoffset */
|
||||||
|
PyObject_SelfIter, /* tp_iter */
|
||||||
|
(iternextfunc)elementiter_next, /* tp_iternext */
|
||||||
|
0, /* tp_methods */
|
||||||
|
0, /* tp_members */
|
||||||
|
0, /* tp_getset */
|
||||||
|
0, /* tp_base */
|
||||||
|
0, /* tp_dict */
|
||||||
|
0, /* tp_descr_get */
|
||||||
|
0, /* tp_descr_set */
|
||||||
|
0, /* tp_dictoffset */
|
||||||
|
0, /* tp_init */
|
||||||
|
0, /* tp_alloc */
|
||||||
|
0, /* tp_new */
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
create_elementiter(ElementObject *self, PyObject *tag, int gettext)
|
||||||
|
{
|
||||||
|
ElementIterObject *it;
|
||||||
|
PyObject *star = NULL;
|
||||||
|
|
||||||
|
it = PyObject_GC_New(ElementIterObject, &ElementIter_Type);
|
||||||
|
if (!it)
|
||||||
|
return NULL;
|
||||||
|
if (!(it->parent_stack = PyObject_Malloc(sizeof(ParentLocator)))) {
|
||||||
|
PyObject_GC_Del(it);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
it->parent_stack->parent = NULL;
|
||||||
|
it->parent_stack->child_index = 0;
|
||||||
|
it->parent_stack->next = NULL;
|
||||||
|
|
||||||
|
if (PyUnicode_Check(tag))
|
||||||
|
star = PyUnicode_FromString("*");
|
||||||
|
else if (PyBytes_Check(tag))
|
||||||
|
star = PyBytes_FromString("*");
|
||||||
|
|
||||||
|
if (star && PyObject_RichCompareBool(tag, star, Py_EQ) == 1)
|
||||||
|
tag = Py_None;
|
||||||
|
|
||||||
|
Py_XDECREF(star);
|
||||||
|
it->sought_tag = tag;
|
||||||
|
it->root_done = 0;
|
||||||
|
it->gettext = gettext;
|
||||||
|
it->root_element = self;
|
||||||
|
|
||||||
|
Py_INCREF(self);
|
||||||
|
Py_INCREF(tag);
|
||||||
|
|
||||||
|
PyObject_GC_Track(it);
|
||||||
|
return (PyObject *)it;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* ==================================================================== */
|
/* ==================================================================== */
|
||||||
/* the tree builder type */
|
/* the tree builder type */
|
||||||
|
|
||||||
|
@ -3238,8 +3464,7 @@ static struct PyModuleDef _elementtreemodule = {
|
||||||
PyMODINIT_FUNC
|
PyMODINIT_FUNC
|
||||||
PyInit__elementtree(void)
|
PyInit__elementtree(void)
|
||||||
{
|
{
|
||||||
PyObject *m, *g, *temp;
|
PyObject *m, *temp;
|
||||||
char* bootstrap;
|
|
||||||
|
|
||||||
/* Initialize object types */
|
/* Initialize object types */
|
||||||
if (PyType_Ready(&TreeBuilder_Type) < 0)
|
if (PyType_Ready(&TreeBuilder_Type) < 0)
|
||||||
|
@ -3255,44 +3480,6 @@ PyInit__elementtree(void)
|
||||||
if (!m)
|
if (!m)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
/* The code below requires that the module gets already added
|
|
||||||
to sys.modules. */
|
|
||||||
PyDict_SetItemString(PyImport_GetModuleDict(),
|
|
||||||
_elementtreemodule.m_name,
|
|
||||||
m);
|
|
||||||
|
|
||||||
/* python glue code */
|
|
||||||
|
|
||||||
g = PyDict_New();
|
|
||||||
if (!g)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
PyDict_SetItemString(g, "__builtins__", PyEval_GetBuiltins());
|
|
||||||
|
|
||||||
bootstrap = (
|
|
||||||
"def iter(node, tag=None):\n" /* helper */
|
|
||||||
" if tag == '*':\n"
|
|
||||||
" tag = None\n"
|
|
||||||
" if tag is None or node.tag == tag:\n"
|
|
||||||
" yield node\n"
|
|
||||||
" for node in node:\n"
|
|
||||||
" for node in iter(node, tag):\n"
|
|
||||||
" yield node\n"
|
|
||||||
|
|
||||||
"def itertext(node):\n" /* helper */
|
|
||||||
" if node.text:\n"
|
|
||||||
" yield node.text\n"
|
|
||||||
" for e in node:\n"
|
|
||||||
" for s in e.itertext():\n"
|
|
||||||
" yield s\n"
|
|
||||||
" if e.tail:\n"
|
|
||||||
" yield e.tail\n"
|
|
||||||
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!PyRun_String(bootstrap, Py_file_input, g, NULL))
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
if (!(temp = PyImport_ImportModule("copy")))
|
if (!(temp = PyImport_ImportModule("copy")))
|
||||||
return NULL;
|
return NULL;
|
||||||
elementtree_deepcopy_obj = PyObject_GetAttrString(temp, "deepcopy");
|
elementtree_deepcopy_obj = PyObject_GetAttrString(temp, "deepcopy");
|
||||||
|
@ -3301,9 +3488,6 @@ PyInit__elementtree(void)
|
||||||
if (!(elementpath_obj = PyImport_ImportModule("xml.etree.ElementPath")))
|
if (!(elementpath_obj = PyImport_ImportModule("xml.etree.ElementPath")))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
elementtree_iter_obj = PyDict_GetItemString(g, "iter");
|
|
||||||
elementtree_itertext_obj = PyDict_GetItemString(g, "itertext");
|
|
||||||
|
|
||||||
/* link against pyexpat */
|
/* link against pyexpat */
|
||||||
expat_capi = PyCapsule_Import(PyExpat_CAPSULE_NAME, 0);
|
expat_capi = PyCapsule_Import(PyExpat_CAPSULE_NAME, 0);
|
||||||
if (expat_capi) {
|
if (expat_capi) {
|
||||||
|
|
|
@ -96,7 +96,7 @@ floatclock(_Py_clock_info_t *info)
|
||||||
info->implementation = "clock()";
|
info->implementation = "clock()";
|
||||||
info->resolution = 1.0 / (double)CLOCKS_PER_SEC;
|
info->resolution = 1.0 / (double)CLOCKS_PER_SEC;
|
||||||
info->monotonic = 1;
|
info->monotonic = 1;
|
||||||
info->adjusted = 0;
|
info->adjustable = 0;
|
||||||
}
|
}
|
||||||
return PyFloat_FromDouble((double)value / CLOCKS_PER_SEC);
|
return PyFloat_FromDouble((double)value / CLOCKS_PER_SEC);
|
||||||
}
|
}
|
||||||
|
@ -132,7 +132,7 @@ win_perf_counter(_Py_clock_info_t *info, PyObject **result)
|
||||||
info->implementation = "QueryPerformanceCounter()";
|
info->implementation = "QueryPerformanceCounter()";
|
||||||
info->resolution = 1.0 / (double)cpu_frequency;
|
info->resolution = 1.0 / (double)cpu_frequency;
|
||||||
info->monotonic = 1;
|
info->monotonic = 1;
|
||||||
info->adjusted = 0;
|
info->adjustable = 0;
|
||||||
}
|
}
|
||||||
*result = PyFloat_FromDouble(diff / (double)cpu_frequency);
|
*result = PyFloat_FromDouble(diff / (double)cpu_frequency);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -275,6 +275,10 @@ static PyStructSequence_Field struct_time_type_fields[] = {
|
||||||
{"tm_wday", "day of week, range [0, 6], Monday is 0"},
|
{"tm_wday", "day of week, range [0, 6], Monday is 0"},
|
||||||
{"tm_yday", "day of year, range [1, 366]"},
|
{"tm_yday", "day of year, range [1, 366]"},
|
||||||
{"tm_isdst", "1 if summer time is in effect, 0 if not, and -1 if unknown"},
|
{"tm_isdst", "1 if summer time is in effect, 0 if not, and -1 if unknown"},
|
||||||
|
#ifdef HAVE_STRUCT_TM_TM_ZONE
|
||||||
|
{"tm_zone", "abbreviation of timezone name"},
|
||||||
|
{"tm_gmtoff", "offset from UTC in seconds"},
|
||||||
|
#endif /* HAVE_STRUCT_TM_TM_ZONE */
|
||||||
{0}
|
{0}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -294,6 +298,7 @@ static PyStructSequence_Desc struct_time_type_desc = {
|
||||||
static int initialized;
|
static int initialized;
|
||||||
static PyTypeObject StructTimeType;
|
static PyTypeObject StructTimeType;
|
||||||
|
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
tmtotuple(struct tm *p)
|
tmtotuple(struct tm *p)
|
||||||
{
|
{
|
||||||
|
@ -312,6 +317,11 @@ tmtotuple(struct tm *p)
|
||||||
SET(6, (p->tm_wday + 6) % 7); /* Want Monday == 0 */
|
SET(6, (p->tm_wday + 6) % 7); /* Want Monday == 0 */
|
||||||
SET(7, p->tm_yday + 1); /* Want January, 1 == 1 */
|
SET(7, p->tm_yday + 1); /* Want January, 1 == 1 */
|
||||||
SET(8, p->tm_isdst);
|
SET(8, p->tm_isdst);
|
||||||
|
#ifdef HAVE_STRUCT_TM_TM_ZONE
|
||||||
|
PyStructSequence_SET_ITEM(v, 9,
|
||||||
|
PyUnicode_DecodeLocale(p->tm_zone, "surrogateescape"));
|
||||||
|
SET(10, p->tm_gmtoff);
|
||||||
|
#endif /* HAVE_STRUCT_TM_TM_ZONE */
|
||||||
#undef SET
|
#undef SET
|
||||||
if (PyErr_Occurred()) {
|
if (PyErr_Occurred()) {
|
||||||
Py_XDECREF(v);
|
Py_XDECREF(v);
|
||||||
|
@ -371,7 +381,10 @@ PyDoc_STRVAR(gmtime_doc,
|
||||||
tm_sec, tm_wday, tm_yday, tm_isdst)\n\
|
tm_sec, tm_wday, tm_yday, tm_isdst)\n\
|
||||||
\n\
|
\n\
|
||||||
Convert seconds since the Epoch to a time tuple expressing UTC (a.k.a.\n\
|
Convert seconds since the Epoch to a time tuple expressing UTC (a.k.a.\n\
|
||||||
GMT). When 'seconds' is not passed in, convert the current time instead.");
|
GMT). When 'seconds' is not passed in, convert the current time instead.\n\
|
||||||
|
\n\
|
||||||
|
If the platform supports the tm_gmtoff and tm_zone, they are available as\n\
|
||||||
|
attributes only.");
|
||||||
|
|
||||||
static int
|
static int
|
||||||
pylocaltime(time_t *timep, struct tm *result)
|
pylocaltime(time_t *timep, struct tm *result)
|
||||||
|
@ -401,7 +414,7 @@ time_localtime(PyObject *self, PyObject *args)
|
||||||
|
|
||||||
if (!parse_time_t_args(args, "|O:localtime", &when))
|
if (!parse_time_t_args(args, "|O:localtime", &when))
|
||||||
return NULL;
|
return NULL;
|
||||||
if (pylocaltime(&when, &buf) == 1)
|
if (pylocaltime(&when, &buf) == -1)
|
||||||
return NULL;
|
return NULL;
|
||||||
return tmtotuple(&buf);
|
return tmtotuple(&buf);
|
||||||
}
|
}
|
||||||
|
@ -438,6 +451,17 @@ gettmarg(PyObject *args, struct tm *p)
|
||||||
p->tm_mon--;
|
p->tm_mon--;
|
||||||
p->tm_wday = (p->tm_wday + 1) % 7;
|
p->tm_wday = (p->tm_wday + 1) % 7;
|
||||||
p->tm_yday--;
|
p->tm_yday--;
|
||||||
|
#ifdef HAVE_STRUCT_TM_TM_ZONE
|
||||||
|
if (Py_TYPE(args) == &StructTimeType) {
|
||||||
|
PyObject *item;
|
||||||
|
item = PyTuple_GET_ITEM(args, 9);
|
||||||
|
p->tm_zone = item == Py_None ? NULL : _PyUnicode_AsString(item);
|
||||||
|
item = PyTuple_GET_ITEM(args, 10);
|
||||||
|
p->tm_gmtoff = item == Py_None ? 0 : PyLong_AsLong(item);
|
||||||
|
if (PyErr_Occurred())
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif /* HAVE_STRUCT_TM_TM_ZONE */
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -778,7 +802,10 @@ time_mktime(PyObject *self, PyObject *tup)
|
||||||
PyDoc_STRVAR(mktime_doc,
|
PyDoc_STRVAR(mktime_doc,
|
||||||
"mktime(tuple) -> floating point number\n\
|
"mktime(tuple) -> floating point number\n\
|
||||||
\n\
|
\n\
|
||||||
Convert a time tuple in local time to seconds since the Epoch.");
|
Convert a time tuple in local time to seconds since the Epoch.\n\
|
||||||
|
Note that mktime(gmtime(0)) will not generally return zero for most\n\
|
||||||
|
time zones; instead the returned value will either be equal to that\n\
|
||||||
|
of the timezone or altzone attributes on the time module.");
|
||||||
#endif /* HAVE_MKTIME */
|
#endif /* HAVE_MKTIME */
|
||||||
|
|
||||||
#ifdef HAVE_WORKING_TZSET
|
#ifdef HAVE_WORKING_TZSET
|
||||||
|
@ -882,7 +909,7 @@ pymonotonic(_Py_clock_info_t *info)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
info->resolution = timeIncrement * 1e-7;
|
info->resolution = timeIncrement * 1e-7;
|
||||||
info->adjusted = 0;
|
info->adjustable = 0;
|
||||||
}
|
}
|
||||||
return PyFloat_FromDouble(result);
|
return PyFloat_FromDouble(result);
|
||||||
|
|
||||||
|
@ -903,7 +930,7 @@ pymonotonic(_Py_clock_info_t *info)
|
||||||
info->implementation = "mach_absolute_time()";
|
info->implementation = "mach_absolute_time()";
|
||||||
info->resolution = (double)timebase.numer / timebase.denom * 1e-9;
|
info->resolution = (double)timebase.numer / timebase.denom * 1e-9;
|
||||||
info->monotonic = 1;
|
info->monotonic = 1;
|
||||||
info->adjusted = 0;
|
info->adjustable = 0;
|
||||||
}
|
}
|
||||||
return PyFloat_FromDouble(secs);
|
return PyFloat_FromDouble(secs);
|
||||||
|
|
||||||
|
@ -926,13 +953,7 @@ pymonotonic(_Py_clock_info_t *info)
|
||||||
struct timespec res;
|
struct timespec res;
|
||||||
info->monotonic = 1;
|
info->monotonic = 1;
|
||||||
info->implementation = function;
|
info->implementation = function;
|
||||||
#if (defined(linux) || defined(__linux) || defined(__linux__)) \
|
info->adjustable = 0;
|
||||||
&& !defined(CLOCK_HIGHRES)
|
|
||||||
/* CLOCK_MONOTONIC is adjusted on Linux */
|
|
||||||
info->adjusted = 1;
|
|
||||||
#else
|
|
||||||
info->adjusted = 0;
|
|
||||||
#endif
|
|
||||||
if (clock_getres(clk_id, &res) == 0)
|
if (clock_getres(clk_id, &res) == 0)
|
||||||
info->resolution = res.tv_sec + res.tv_nsec * 1e-9;
|
info->resolution = res.tv_sec + res.tv_nsec * 1e-9;
|
||||||
else
|
else
|
||||||
|
@ -1024,7 +1045,7 @@ py_process_time(_Py_clock_info_t *info)
|
||||||
info->implementation = "GetProcessTimes()";
|
info->implementation = "GetProcessTimes()";
|
||||||
info->resolution = 1e-7;
|
info->resolution = 1e-7;
|
||||||
info->monotonic = 1;
|
info->monotonic = 1;
|
||||||
info->adjusted = 0;
|
info->adjustable = 0;
|
||||||
}
|
}
|
||||||
return PyFloat_FromDouble(total * 1e-7);
|
return PyFloat_FromDouble(total * 1e-7);
|
||||||
#else
|
#else
|
||||||
|
@ -1053,7 +1074,7 @@ py_process_time(_Py_clock_info_t *info)
|
||||||
struct timespec res;
|
struct timespec res;
|
||||||
info->implementation = function;
|
info->implementation = function;
|
||||||
info->monotonic = 1;
|
info->monotonic = 1;
|
||||||
info->adjusted = 0;
|
info->adjustable = 0;
|
||||||
if (clock_getres(clk_id, &res) == 0)
|
if (clock_getres(clk_id, &res) == 0)
|
||||||
info->resolution = res.tv_sec + res.tv_nsec * 1e-9;
|
info->resolution = res.tv_sec + res.tv_nsec * 1e-9;
|
||||||
else
|
else
|
||||||
|
@ -1071,7 +1092,7 @@ py_process_time(_Py_clock_info_t *info)
|
||||||
if (info) {
|
if (info) {
|
||||||
info->implementation = "getrusage(RUSAGE_SELF)";
|
info->implementation = "getrusage(RUSAGE_SELF)";
|
||||||
info->monotonic = 1;
|
info->monotonic = 1;
|
||||||
info->adjusted = 0;
|
info->adjustable = 0;
|
||||||
info->resolution = 1e-6;
|
info->resolution = 1e-6;
|
||||||
}
|
}
|
||||||
return PyFloat_FromDouble(total);
|
return PyFloat_FromDouble(total);
|
||||||
|
@ -1100,7 +1121,7 @@ py_process_time(_Py_clock_info_t *info)
|
||||||
if (info) {
|
if (info) {
|
||||||
info->implementation = "times()";
|
info->implementation = "times()";
|
||||||
info->monotonic = 1;
|
info->monotonic = 1;
|
||||||
info->adjusted = 0;
|
info->adjustable = 0;
|
||||||
info->resolution = 1.0 / ticks_per_second;
|
info->resolution = 1.0 / ticks_per_second;
|
||||||
}
|
}
|
||||||
return PyFloat_FromDouble(total);
|
return PyFloat_FromDouble(total);
|
||||||
|
@ -1124,35 +1145,12 @@ PyDoc_STRVAR(process_time_doc,
|
||||||
Process time for profiling: sum of the kernel and user-space CPU time.");
|
Process time for profiling: sum of the kernel and user-space CPU time.");
|
||||||
|
|
||||||
|
|
||||||
static PyTypeObject ClockInfoType;
|
|
||||||
|
|
||||||
PyDoc_STRVAR(ClockInfo_docstring,
|
|
||||||
"Clock information");
|
|
||||||
|
|
||||||
static PyStructSequence_Field ClockInfo_fields[] = {
|
|
||||||
{"implementation", "name of the underlying C function "
|
|
||||||
"used to get the clock value"},
|
|
||||||
{"monotonic", "True if the clock cannot go backward, False otherwise"},
|
|
||||||
{"adjusted", "True if the clock can be adjusted "
|
|
||||||
"(e.g. by a NTP daemon), False otherwise"},
|
|
||||||
{"resolution", "resolution of the clock in seconds"},
|
|
||||||
{NULL, NULL}
|
|
||||||
};
|
|
||||||
|
|
||||||
static PyStructSequence_Desc ClockInfo_desc = {
|
|
||||||
"time.clock_info",
|
|
||||||
ClockInfo_docstring,
|
|
||||||
ClockInfo_fields,
|
|
||||||
4,
|
|
||||||
};
|
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
time_get_clock_info(PyObject *self, PyObject *args)
|
time_get_clock_info(PyObject *self, PyObject *args)
|
||||||
{
|
{
|
||||||
char *name;
|
char *name;
|
||||||
PyObject *obj;
|
|
||||||
_Py_clock_info_t info;
|
_Py_clock_info_t info;
|
||||||
PyObject *result;
|
PyObject *obj = NULL, *dict, *ns;
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args, "s:get_clock_info", &name))
|
if (!PyArg_ParseTuple(args, "s:get_clock_info", &name))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -1160,12 +1158,12 @@ time_get_clock_info(PyObject *self, PyObject *args)
|
||||||
#ifdef Py_DEBUG
|
#ifdef Py_DEBUG
|
||||||
info.implementation = NULL;
|
info.implementation = NULL;
|
||||||
info.monotonic = -1;
|
info.monotonic = -1;
|
||||||
info.adjusted = -1;
|
info.adjustable = -1;
|
||||||
info.resolution = -1.0;
|
info.resolution = -1.0;
|
||||||
#else
|
#else
|
||||||
info.implementation = "";
|
info.implementation = "";
|
||||||
info.monotonic = 0;
|
info.monotonic = 0;
|
||||||
info.adjusted = 0;
|
info.adjustable = 0;
|
||||||
info.resolution = 1.0;
|
info.resolution = 1.0;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -1191,39 +1189,50 @@ time_get_clock_info(PyObject *self, PyObject *args)
|
||||||
return NULL;
|
return NULL;
|
||||||
Py_DECREF(obj);
|
Py_DECREF(obj);
|
||||||
|
|
||||||
result = PyStructSequence_New(&ClockInfoType);
|
dict = PyDict_New();
|
||||||
if (result == NULL)
|
if (dict == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
assert(info.implementation != NULL);
|
assert(info.implementation != NULL);
|
||||||
obj = PyUnicode_FromString(info.implementation);
|
obj = PyUnicode_FromString(info.implementation);
|
||||||
if (obj == NULL)
|
if (obj == NULL)
|
||||||
goto error;
|
goto error;
|
||||||
PyStructSequence_SET_ITEM(result, 0, obj);
|
if (PyDict_SetItemString(dict, "implementation", obj) == -1)
|
||||||
|
goto error;
|
||||||
|
Py_CLEAR(obj);
|
||||||
|
|
||||||
assert(info.monotonic != -1);
|
assert(info.monotonic != -1);
|
||||||
obj = PyBool_FromLong(info.monotonic);
|
obj = PyBool_FromLong(info.monotonic);
|
||||||
if (obj == NULL)
|
if (obj == NULL)
|
||||||
goto error;
|
goto error;
|
||||||
PyStructSequence_SET_ITEM(result, 1, obj);
|
if (PyDict_SetItemString(dict, "monotonic", obj) == -1)
|
||||||
|
goto error;
|
||||||
|
Py_CLEAR(obj);
|
||||||
|
|
||||||
assert(info.adjusted != -1);
|
assert(info.adjustable != -1);
|
||||||
obj = PyBool_FromLong(info.adjusted);
|
obj = PyBool_FromLong(info.adjustable);
|
||||||
if (obj == NULL)
|
if (obj == NULL)
|
||||||
goto error;
|
goto error;
|
||||||
PyStructSequence_SET_ITEM(result, 2, obj);
|
if (PyDict_SetItemString(dict, "adjustable", obj) == -1)
|
||||||
|
goto error;
|
||||||
|
Py_CLEAR(obj);
|
||||||
|
|
||||||
assert(info.resolution > 0.0);
|
assert(info.resolution > 0.0);
|
||||||
assert(info.resolution <= 1.0);
|
assert(info.resolution <= 1.0);
|
||||||
obj = PyFloat_FromDouble(info.resolution);
|
obj = PyFloat_FromDouble(info.resolution);
|
||||||
if (obj == NULL)
|
if (obj == NULL)
|
||||||
goto error;
|
goto error;
|
||||||
PyStructSequence_SET_ITEM(result, 3, obj);
|
if (PyDict_SetItemString(dict, "resolution", obj) == -1)
|
||||||
|
goto error;
|
||||||
|
Py_CLEAR(obj);
|
||||||
|
|
||||||
return result;
|
ns = _PyNamespace_New(dict);
|
||||||
|
Py_DECREF(dict);
|
||||||
|
return ns;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
Py_DECREF(result);
|
Py_DECREF(dict);
|
||||||
|
Py_XDECREF(obj);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1451,11 +1460,6 @@ PyInit_time(void)
|
||||||
PyStructSequence_InitType(&StructTimeType,
|
PyStructSequence_InitType(&StructTimeType,
|
||||||
&struct_time_type_desc);
|
&struct_time_type_desc);
|
||||||
|
|
||||||
/* initialize ClockInfoType */
|
|
||||||
PyStructSequence_InitType(&ClockInfoType, &ClockInfo_desc);
|
|
||||||
Py_INCREF(&ClockInfoType);
|
|
||||||
PyModule_AddObject(m, "clock_info", (PyObject*)&ClockInfoType);
|
|
||||||
|
|
||||||
#ifdef MS_WINDOWS
|
#ifdef MS_WINDOWS
|
||||||
winver.dwOSVersionInfoSize = sizeof(winver);
|
winver.dwOSVersionInfoSize = sizeof(winver);
|
||||||
if (!GetVersionEx((OSVERSIONINFO*)&winver)) {
|
if (!GetVersionEx((OSVERSIONINFO*)&winver)) {
|
||||||
|
@ -1466,6 +1470,11 @@ PyInit_time(void)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
Py_INCREF(&StructTimeType);
|
Py_INCREF(&StructTimeType);
|
||||||
|
#ifdef HAVE_STRUCT_TM_TM_ZONE
|
||||||
|
PyModule_AddIntConstant(m, "_STRUCT_TM_ITEMS", 11);
|
||||||
|
#else
|
||||||
|
PyModule_AddIntConstant(m, "_STRUCT_TM_ITEMS", 9);
|
||||||
|
#endif
|
||||||
PyModule_AddObject(m, "struct_time", (PyObject*) &StructTimeType);
|
PyModule_AddObject(m, "struct_time", (PyObject*) &StructTimeType);
|
||||||
initialized = 1;
|
initialized = 1;
|
||||||
return m;
|
return m;
|
||||||
|
@ -1488,7 +1497,7 @@ floattime(_Py_clock_info_t *info)
|
||||||
struct timespec res;
|
struct timespec res;
|
||||||
info->implementation = "clock_gettime(CLOCK_REALTIME)";
|
info->implementation = "clock_gettime(CLOCK_REALTIME)";
|
||||||
info->monotonic = 0;
|
info->monotonic = 0;
|
||||||
info->adjusted = 1;
|
info->adjustable = 1;
|
||||||
if (clock_getres(CLOCK_REALTIME, &res) == 0)
|
if (clock_getres(CLOCK_REALTIME, &res) == 0)
|
||||||
info->resolution = res.tv_sec + res.tv_nsec * 1e-9;
|
info->resolution = res.tv_sec + res.tv_nsec * 1e-9;
|
||||||
else
|
else
|
||||||
|
|
|
@ -562,4 +562,68 @@ STRINGLIB(utf16_decode)(const unsigned char **inptr, const unsigned char *e,
|
||||||
#undef STRIPPED_MASK
|
#undef STRIPPED_MASK
|
||||||
#undef SWAB
|
#undef SWAB
|
||||||
#undef LONG_PTR_MASK
|
#undef LONG_PTR_MASK
|
||||||
|
|
||||||
|
|
||||||
|
Py_LOCAL_INLINE(void)
|
||||||
|
STRINGLIB(utf16_encode)(unsigned short *out,
|
||||||
|
const STRINGLIB_CHAR *in,
|
||||||
|
Py_ssize_t len,
|
||||||
|
int native_ordering)
|
||||||
|
{
|
||||||
|
const STRINGLIB_CHAR *end = in + len;
|
||||||
|
#if STRINGLIB_SIZEOF_CHAR == 1
|
||||||
|
# define SWAB2(CH) ((CH) << 8)
|
||||||
|
#else
|
||||||
|
# define SWAB2(CH) (((CH) << 8) | ((CH) >> 8))
|
||||||
|
#endif
|
||||||
|
#if STRINGLIB_MAX_CHAR < 0x10000
|
||||||
|
if (native_ordering) {
|
||||||
|
# if STRINGLIB_SIZEOF_CHAR == 2
|
||||||
|
Py_MEMCPY(out, in, 2 * len);
|
||||||
|
# else
|
||||||
|
_PyUnicode_CONVERT_BYTES(STRINGLIB_CHAR, unsigned short, in, end, out);
|
||||||
|
# endif
|
||||||
|
} else {
|
||||||
|
const STRINGLIB_CHAR *unrolled_end = in + (len & ~ (Py_ssize_t) 3);
|
||||||
|
while (in < unrolled_end) {
|
||||||
|
out[0] = SWAB2(in[0]);
|
||||||
|
out[1] = SWAB2(in[1]);
|
||||||
|
out[2] = SWAB2(in[2]);
|
||||||
|
out[3] = SWAB2(in[3]);
|
||||||
|
in += 4; out += 4;
|
||||||
|
}
|
||||||
|
while (in < end) {
|
||||||
|
*out++ = SWAB2(*in);
|
||||||
|
++in;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
if (native_ordering) {
|
||||||
|
while (in < end) {
|
||||||
|
Py_UCS4 ch = *in++;
|
||||||
|
if (ch < 0x10000)
|
||||||
|
*out++ = ch;
|
||||||
|
else {
|
||||||
|
out[0] = Py_UNICODE_HIGH_SURROGATE(ch);
|
||||||
|
out[1] = Py_UNICODE_LOW_SURROGATE(ch);
|
||||||
|
out += 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
while (in < end) {
|
||||||
|
Py_UCS4 ch = *in++;
|
||||||
|
if (ch < 0x10000)
|
||||||
|
*out++ = SWAB2((Py_UCS2)ch);
|
||||||
|
else {
|
||||||
|
Py_UCS2 ch1 = Py_UNICODE_HIGH_SURROGATE(ch);
|
||||||
|
Py_UCS2 ch2 = Py_UNICODE_LOW_SURROGATE(ch);
|
||||||
|
out[0] = SWAB2(ch1);
|
||||||
|
out[1] = SWAB2(ch2);
|
||||||
|
out += 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#undef SWAB2
|
||||||
|
}
|
||||||
#endif /* STRINGLIB_IS_UNICODE */
|
#endif /* STRINGLIB_IS_UNICODE */
|
||||||
|
|
|
@ -5359,27 +5359,19 @@ _PyUnicode_EncodeUTF16(PyObject *str,
|
||||||
const char *errors,
|
const char *errors,
|
||||||
int byteorder)
|
int byteorder)
|
||||||
{
|
{
|
||||||
int kind;
|
enum PyUnicode_Kind kind;
|
||||||
void *data;
|
const void *data;
|
||||||
Py_ssize_t len;
|
Py_ssize_t len;
|
||||||
PyObject *v;
|
PyObject *v;
|
||||||
unsigned char *p;
|
unsigned short *out;
|
||||||
Py_ssize_t nsize, bytesize;
|
Py_ssize_t bytesize;
|
||||||
Py_ssize_t i, pairs;
|
Py_ssize_t pairs;
|
||||||
/* Offsets from p for storing byte pairs in the right order. */
|
#ifdef WORDS_BIGENDIAN
|
||||||
#ifdef BYTEORDER_IS_LITTLE_ENDIAN
|
int native_ordering = byteorder >= 0;
|
||||||
int ihi = 1, ilo = 0;
|
|
||||||
#else
|
#else
|
||||||
int ihi = 0, ilo = 1;
|
int native_ordering = byteorder <= 0;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define STORECHAR(CH) \
|
|
||||||
do { \
|
|
||||||
p[ihi] = ((CH) >> 8) & 0xff; \
|
|
||||||
p[ilo] = (CH) & 0xff; \
|
|
||||||
p += 2; \
|
|
||||||
} while(0)
|
|
||||||
|
|
||||||
if (!PyUnicode_Check(str)) {
|
if (!PyUnicode_Check(str)) {
|
||||||
PyErr_BadArgument();
|
PyErr_BadArgument();
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -5391,53 +5383,47 @@ _PyUnicode_EncodeUTF16(PyObject *str,
|
||||||
len = PyUnicode_GET_LENGTH(str);
|
len = PyUnicode_GET_LENGTH(str);
|
||||||
|
|
||||||
pairs = 0;
|
pairs = 0;
|
||||||
if (kind == PyUnicode_4BYTE_KIND)
|
if (kind == PyUnicode_4BYTE_KIND) {
|
||||||
for (i = 0; i < len; i++)
|
const Py_UCS4 *in = (const Py_UCS4 *)data;
|
||||||
if (PyUnicode_READ(kind, data, i) >= 0x10000)
|
const Py_UCS4 *end = in + len;
|
||||||
|
while (in < end)
|
||||||
|
if (*in++ >= 0x10000)
|
||||||
pairs++;
|
pairs++;
|
||||||
/* 2 * (len + pairs + (byteorder == 0)) */
|
}
|
||||||
if (len > PY_SSIZE_T_MAX - pairs - (byteorder == 0))
|
if (len > PY_SSIZE_T_MAX / 2 - pairs - (byteorder == 0))
|
||||||
return PyErr_NoMemory();
|
|
||||||
nsize = len + pairs + (byteorder == 0);
|
|
||||||
bytesize = nsize * 2;
|
|
||||||
if (bytesize / 2 != nsize)
|
|
||||||
return PyErr_NoMemory();
|
return PyErr_NoMemory();
|
||||||
|
bytesize = (len + pairs + (byteorder == 0)) * 2;
|
||||||
v = PyBytes_FromStringAndSize(NULL, bytesize);
|
v = PyBytes_FromStringAndSize(NULL, bytesize);
|
||||||
if (v == NULL)
|
if (v == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
p = (unsigned char *)PyBytes_AS_STRING(v);
|
/* output buffer is 2-bytes aligned */
|
||||||
|
assert(((Py_uintptr_t)PyBytes_AS_STRING(v) & 1) == 0);
|
||||||
|
out = (unsigned short *)PyBytes_AS_STRING(v);
|
||||||
if (byteorder == 0)
|
if (byteorder == 0)
|
||||||
STORECHAR(0xFEFF);
|
*out++ = 0xFEFF;
|
||||||
if (len == 0)
|
if (len == 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
if (byteorder == -1) {
|
switch (kind) {
|
||||||
/* force LE */
|
case PyUnicode_1BYTE_KIND: {
|
||||||
ihi = 1;
|
ucs1lib_utf16_encode(out, (const Py_UCS1 *)data, len, native_ordering);
|
||||||
ilo = 0;
|
break;
|
||||||
}
|
}
|
||||||
else if (byteorder == 1) {
|
case PyUnicode_2BYTE_KIND: {
|
||||||
/* force BE */
|
ucs2lib_utf16_encode(out, (const Py_UCS2 *)data, len, native_ordering);
|
||||||
ihi = 0;
|
break;
|
||||||
ilo = 1;
|
|
||||||
}
|
}
|
||||||
|
case PyUnicode_4BYTE_KIND: {
|
||||||
for (i = 0; i < len; i++) {
|
ucs4lib_utf16_encode(out, (const Py_UCS4 *)data, len, native_ordering);
|
||||||
Py_UCS4 ch = PyUnicode_READ(kind, data, i);
|
break;
|
||||||
Py_UCS4 ch2 = 0;
|
}
|
||||||
if (ch >= 0x10000) {
|
default:
|
||||||
ch2 = Py_UNICODE_LOW_SURROGATE(ch);
|
assert(0);
|
||||||
ch = Py_UNICODE_HIGH_SURROGATE(ch);
|
|
||||||
}
|
|
||||||
STORECHAR(ch);
|
|
||||||
if (ch2)
|
|
||||||
STORECHAR(ch2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
done:
|
done:
|
||||||
return v;
|
return v;
|
||||||
#undef STORECHAR
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PyObject *
|
PyObject *
|
||||||
|
|
|
@ -802,6 +802,10 @@
|
||||||
RelativePath="..\..\Include\moduleobject.h"
|
RelativePath="..\..\Include\moduleobject.h"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\Include\namespaceobject.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\..\Include\node.h"
|
RelativePath="..\..\Include\node.h"
|
||||||
>
|
>
|
||||||
|
@ -1562,6 +1566,10 @@
|
||||||
RelativePath="..\..\Objects\moduleobject.c"
|
RelativePath="..\..\Objects\moduleobject.c"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\Objects\namespaceobject.c"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\..\Objects\object.c"
|
RelativePath="..\..\Objects\object.c"
|
||||||
>
|
>
|
||||||
|
|
|
@ -44,10 +44,7 @@ pygettimeofday(_PyTime_timeval *tp, _Py_clock_info_t *info)
|
||||||
(void) GetSystemTimeAdjustment(&timeAdjustment, &timeIncrement,
|
(void) GetSystemTimeAdjustment(&timeAdjustment, &timeIncrement,
|
||||||
&isTimeAdjustmentDisabled);
|
&isTimeAdjustmentDisabled);
|
||||||
info->resolution = timeIncrement * 1e-7;
|
info->resolution = timeIncrement * 1e-7;
|
||||||
if (isTimeAdjustmentDisabled)
|
info->adjustable = 1;
|
||||||
info->adjusted = 0;
|
|
||||||
else
|
|
||||||
info->adjusted = 1;
|
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
/* There are three ways to get the time:
|
/* There are three ways to get the time:
|
||||||
|
@ -71,7 +68,7 @@ pygettimeofday(_PyTime_timeval *tp, _Py_clock_info_t *info)
|
||||||
info->implementation = "gettimeofday()";
|
info->implementation = "gettimeofday()";
|
||||||
info->resolution = 1e-6;
|
info->resolution = 1e-6;
|
||||||
info->monotonic = 0;
|
info->monotonic = 0;
|
||||||
info->adjusted = 1;
|
info->adjustable = 1;
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -87,7 +84,7 @@ pygettimeofday(_PyTime_timeval *tp, _Py_clock_info_t *info)
|
||||||
info->implementation = "ftime()";
|
info->implementation = "ftime()";
|
||||||
info->resolution = 1e-3;
|
info->resolution = 1e-3;
|
||||||
info->monotonic = 0;
|
info->monotonic = 0;
|
||||||
info->adjusted = 1;
|
info->adjustable = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#else /* !HAVE_FTIME */
|
#else /* !HAVE_FTIME */
|
||||||
|
@ -97,7 +94,7 @@ pygettimeofday(_PyTime_timeval *tp, _Py_clock_info_t *info)
|
||||||
info->implementation = "time()";
|
info->implementation = "time()";
|
||||||
info->resolution = 1.0;
|
info->resolution = 1.0;
|
||||||
info->monotonic = 0;
|
info->monotonic = 0;
|
||||||
info->adjusted = 1;
|
info->adjustable = 1;
|
||||||
}
|
}
|
||||||
#endif /* !HAVE_FTIME */
|
#endif /* !HAVE_FTIME */
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue