Skip to content

Commit 218f43f

Browse files
committed
add python 3.14.3 lib
1 parent 4ad7a13 commit 218f43f

File tree

998 files changed

+61795
-87487
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

998 files changed

+61795
-87487
lines changed

PythonLib/full/_android_support.py

Lines changed: 192 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,192 @@
1+
import io
2+
import sys
3+
from threading import RLock
4+
from time import sleep, time
5+
6+
# The maximum length of a log message in bytes, including the level marker and
7+
# tag, is defined as LOGGER_ENTRY_MAX_PAYLOAD at
8+
# https://cs.android.com/android/platform/superproject/+/android-14.0.0_r1:system/logging/liblog/include/log/log.h;l=71.
9+
# Messages longer than this will be truncated by logcat. This limit has already
10+
# been reduced at least once in the history of Android (from 4076 to 4068 between
11+
# API level 23 and 26), so leave some headroom.
12+
MAX_BYTES_PER_WRITE = 4000
13+
14+
# UTF-8 uses a maximum of 4 bytes per character, so limiting text writes to this
15+
# size ensures that we can always avoid exceeding MAX_BYTES_PER_WRITE.
16+
# However, if the actual number of bytes per character is smaller than that,
17+
# then we may still join multiple consecutive text writes into binary
18+
# writes containing a larger number of characters.
19+
MAX_CHARS_PER_WRITE = MAX_BYTES_PER_WRITE // 4
20+
21+
22+
# When embedded in an app on current versions of Android, there's no easy way to
23+
# monitor the C-level stdout and stderr. The testbed comes with a .c file to
24+
# redirect them to the system log using a pipe, but that wouldn't be convenient
25+
# or appropriate for all apps. So we redirect at the Python level instead.
26+
def init_streams(android_log_write, stdout_prio, stderr_prio):
27+
if sys.executable:
28+
return # Not embedded in an app.
29+
30+
global logcat
31+
logcat = Logcat(android_log_write)
32+
sys.stdout = TextLogStream(stdout_prio, "python.stdout", sys.stdout)
33+
sys.stderr = TextLogStream(stderr_prio, "python.stderr", sys.stderr)
34+
35+
36+
class TextLogStream(io.TextIOWrapper):
37+
def __init__(self, prio, tag, original=None, **kwargs):
38+
# Respect the -u option.
39+
if original:
40+
kwargs.setdefault("write_through", original.write_through)
41+
fileno = original.fileno()
42+
else:
43+
fileno = None
44+
45+
# The default is surrogateescape for stdout and backslashreplace for
46+
# stderr, but in the context of an Android log, readability is more
47+
# important than reversibility.
48+
kwargs.setdefault("encoding", "UTF-8")
49+
kwargs.setdefault("errors", "backslashreplace")
50+
51+
super().__init__(BinaryLogStream(prio, tag, fileno), **kwargs)
52+
self._lock = RLock()
53+
self._pending_bytes = []
54+
self._pending_bytes_count = 0
55+
56+
def __repr__(self):
57+
return f"<TextLogStream {self.buffer.tag!r}>"
58+
59+
def write(self, s):
60+
if not isinstance(s, str):
61+
raise TypeError(
62+
f"write() argument must be str, not {type(s).__name__}")
63+
64+
# In case `s` is a str subclass that writes itself to stdout or stderr
65+
# when we call its methods, convert it to an actual str.
66+
s = str.__str__(s)
67+
68+
# We want to emit one log message per line wherever possible, so split
69+
# the string into lines first. Note that "".splitlines() == [], so
70+
# nothing will be logged for an empty string.
71+
with self._lock:
72+
for line in s.splitlines(keepends=True):
73+
while line:
74+
chunk = line[:MAX_CHARS_PER_WRITE]
75+
line = line[MAX_CHARS_PER_WRITE:]
76+
self._write_chunk(chunk)
77+
78+
return len(s)
79+
80+
# The size and behavior of TextIOWrapper's buffer is not part of its public
81+
# API, so we handle buffering ourselves to avoid truncation.
82+
def _write_chunk(self, s):
83+
b = s.encode(self.encoding, self.errors)
84+
if self._pending_bytes_count + len(b) > MAX_BYTES_PER_WRITE:
85+
self.flush()
86+
87+
self._pending_bytes.append(b)
88+
self._pending_bytes_count += len(b)
89+
if (
90+
self.write_through
91+
or b.endswith(b"\n")
92+
or self._pending_bytes_count > MAX_BYTES_PER_WRITE
93+
):
94+
self.flush()
95+
96+
def flush(self):
97+
with self._lock:
98+
self.buffer.write(b"".join(self._pending_bytes))
99+
self._pending_bytes.clear()
100+
self._pending_bytes_count = 0
101+
102+
# Since this is a line-based logging system, line buffering cannot be turned
103+
# off, i.e. a newline always causes a flush.
104+
@property
105+
def line_buffering(self):
106+
return True
107+
108+
109+
class BinaryLogStream(io.RawIOBase):
110+
def __init__(self, prio, tag, fileno=None):
111+
self.prio = prio
112+
self.tag = tag
113+
self._fileno = fileno
114+
115+
def __repr__(self):
116+
return f"<BinaryLogStream {self.tag!r}>"
117+
118+
def writable(self):
119+
return True
120+
121+
def write(self, b):
122+
if type(b) is not bytes:
123+
try:
124+
b = bytes(memoryview(b))
125+
except TypeError:
126+
raise TypeError(
127+
f"write() argument must be bytes-like, not {type(b).__name__}"
128+
) from None
129+
130+
# Writing an empty string to the stream should have no effect.
131+
if b:
132+
logcat.write(self.prio, self.tag, b)
133+
return len(b)
134+
135+
# This is needed by the test suite --timeout option, which uses faulthandler.
136+
def fileno(self):
137+
if self._fileno is None:
138+
raise io.UnsupportedOperation("fileno")
139+
return self._fileno
140+
141+
142+
# When a large volume of data is written to logcat at once, e.g. when a test
143+
# module fails in --verbose3 mode, there's a risk of overflowing logcat's own
144+
# buffer and losing messages. We avoid this by imposing a rate limit using the
145+
# token bucket algorithm, based on a conservative estimate of how fast `adb
146+
# logcat` can consume data.
147+
MAX_BYTES_PER_SECOND = 1024 * 1024
148+
149+
# The logcat buffer size of a device can be determined by running `logcat -g`.
150+
# We set the token bucket size to half of the buffer size of our current minimum
151+
# API level, because other things on the system will be producing messages as
152+
# well.
153+
BUCKET_SIZE = 128 * 1024
154+
155+
# https://cs.android.com/android/platform/superproject/+/android-14.0.0_r1:system/logging/liblog/include/log/log_read.h;l=39
156+
PER_MESSAGE_OVERHEAD = 28
157+
158+
159+
class Logcat:
160+
def __init__(self, android_log_write):
161+
self.android_log_write = android_log_write
162+
self._lock = RLock()
163+
self._bucket_level = 0
164+
self._prev_write_time = time()
165+
166+
def write(self, prio, tag, message):
167+
# Encode null bytes using "modified UTF-8" to avoid them truncating the
168+
# message.
169+
message = message.replace(b"\x00", b"\xc0\x80")
170+
171+
# On API level 30 and higher, Logcat will strip any number of leading
172+
# newlines. This is visible in all `logcat` modes, even --binary. Work
173+
# around this by adding a leading space, which shouldn't make any
174+
# difference to the log's usability.
175+
if message.startswith(b"\n"):
176+
message = b" " + message
177+
178+
with self._lock:
179+
now = time()
180+
self._bucket_level += (
181+
(now - self._prev_write_time) * MAX_BYTES_PER_SECOND)
182+
183+
# If the bucket level is still below zero, the clock must have gone
184+
# backwards, so reset it to zero and continue.
185+
self._bucket_level = max(0, min(self._bucket_level, BUCKET_SIZE))
186+
self._prev_write_time = now
187+
188+
self._bucket_level -= PER_MESSAGE_OVERHEAD + len(tag) + len(message)
189+
if self._bucket_level < 0:
190+
sleep(-self._bucket_level / MAX_BYTES_PER_SECOND)
191+
192+
self.android_log_write(prio, tag, message)

PythonLib/full/_apple_support.py

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
import io
2+
import sys
3+
4+
5+
def init_streams(log_write, stdout_level, stderr_level):
6+
# Redirect stdout and stderr to the Apple system log. This method is
7+
# invoked by init_apple_streams() (initconfig.c) if config->use_system_logger
8+
# is enabled.
9+
sys.stdout = SystemLog(log_write, stdout_level, errors=sys.stderr.errors)
10+
sys.stderr = SystemLog(log_write, stderr_level, errors=sys.stderr.errors)
11+
12+
13+
class SystemLog(io.TextIOWrapper):
14+
def __init__(self, log_write, level, **kwargs):
15+
kwargs.setdefault("encoding", "UTF-8")
16+
kwargs.setdefault("line_buffering", True)
17+
super().__init__(LogStream(log_write, level), **kwargs)
18+
19+
def __repr__(self):
20+
return f"<SystemLog (level {self.buffer.level})>"
21+
22+
def write(self, s):
23+
if not isinstance(s, str):
24+
raise TypeError(
25+
f"write() argument must be str, not {type(s).__name__}")
26+
27+
# In case `s` is a str subclass that writes itself to stdout or stderr
28+
# when we call its methods, convert it to an actual str.
29+
s = str.__str__(s)
30+
31+
# We want to emit one log message per line, so split
32+
# the string before sending it to the superclass.
33+
for line in s.splitlines(keepends=True):
34+
super().write(line)
35+
36+
return len(s)
37+
38+
39+
class LogStream(io.RawIOBase):
40+
def __init__(self, log_write, level):
41+
self.log_write = log_write
42+
self.level = level
43+
44+
def __repr__(self):
45+
return f"<LogStream (level {self.level!r})>"
46+
47+
def writable(self):
48+
return True
49+
50+
def write(self, b):
51+
if type(b) is not bytes:
52+
try:
53+
b = bytes(memoryview(b))
54+
except TypeError:
55+
raise TypeError(
56+
f"write() argument must be bytes-like, not {type(b).__name__}"
57+
) from None
58+
59+
# Writing an empty string to the stream should have no effect.
60+
if b:
61+
# Encode null bytes using "modified UTF-8" to avoid truncating the
62+
# message. This should not affect the return value, as the caller
63+
# may be expecting it to match the length of the input.
64+
self.log_write(self.level, b.replace(b"\x00", b"\xc0\x80"))
65+
66+
return len(b)

0 commit comments

Comments
 (0)