Skip to content

Commit 72b93f8

Browse files
authored
Merge branch 'main' into agent/gh-155504-threadstate-interp
2 parents 211087d + b11e749 commit 72b93f8

52 files changed

Lines changed: 920 additions & 229 deletions

Some content is hidden

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

Doc/library/ast.rst

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -806,8 +806,11 @@ Comprehensions
806806
List and set comprehensions, generator expressions, and dictionary
807807
comprehensions. ``elt`` (or ``key`` and ``value``) is a single node
808808
representing the part that will be evaluated for each item.
809+
809810
For dictionary comprehensions using unpacking, for example
810-
``{**item for item in items}``, ``value`` is ``None``,
811+
``{**item for item in items}``, the expression to be expanded goes in
812+
``key`` and ``value`` is ``None``.
813+
811814
``generators`` is a list of :class:`comprehension` nodes.
812815

813816
.. doctest::

Doc/library/unittest.mock.rst

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -231,16 +231,20 @@ the *new_callable* argument to :func:`patch`.
231231
Create a new :class:`Mock` object. :class:`Mock` takes several optional arguments
232232
that specify the behaviour of the Mock object:
233233

234-
* *spec*: This can be either a list of strings or an existing object (a
235-
class or instance) that acts as the specification for the mock object. If
236-
you pass in an object then a list of strings is formed by calling dir on
234+
* *spec*: This can be either a list or tuple of strings,
235+
or an existing object (a class or instance)
236+
that acts as the specification for the mock object.
237+
If you pass in an object then a list of strings is formed by calling dir on
237238
the object (excluding unsupported magic attributes and methods).
238239
Accessing any attribute not in this list will raise an :exc:`AttributeError`.
239240

240241
If *spec* is an object (rather than a list of strings) then
241242
:attr:`~object.__class__` returns the class of the spec object. This
242243
allows mocks to pass :func:`isinstance` tests.
243244

245+
.. versionchanged:: next
246+
:func:`dir` now works for a mock created with a tuple *spec*.
247+
244248
* *spec_set*: A stricter variant of *spec*. If used, attempting to *set*
245249
or get an attribute on the mock that isn't on the object passed as
246250
*spec_set* will raise an :exc:`AttributeError`.
@@ -448,9 +452,9 @@ the *new_callable* argument to :func:`patch`.
448452

449453
.. method:: mock_add_spec(spec, spec_set=False)
450454

451-
Add a spec to a mock. *spec* can either be an object or a
452-
list of strings. Only attributes on the *spec* can be fetched as
453-
attributes from the mock.
455+
Add a spec to a mock.
456+
*spec* can either be an object or a list or tuple of strings.
457+
Only attributes on the *spec* can be fetched as attributes from the mock.
454458

455459
If *spec_set* is true then only attributes on the spec can be set.
456460

Include/object.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -490,7 +490,7 @@ given type object has a specified feature.
490490
#define Py_TPFLAGS_SEQUENCE (1 << 5)
491491
/* Set if instances of the type object are treated as mappings for pattern matching */
492492
#define Py_TPFLAGS_MAPPING (1 << 6)
493-
#endif
493+
#endif // Py_LIMITED_API
494494

495495
/* Disallow creating instances of the type: set tp_new to NULL and don't create
496496
* the "__new__" key in the type dictionary. */

Lib/http/cookiejar.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2056,7 +2056,8 @@ def _really_load(self, f, filename, ignore_discard, ignore_expires):
20562056
assert domain_specified == initial_dot
20572057

20582058
discard = False
2059-
if expires == "":
2059+
# curl and Wget set expires to 0 for session cookies.
2060+
if expires == "0" or expires == "":
20602061
expires = None
20612062
discard = True
20622063

@@ -2108,7 +2109,9 @@ def save(self, filename=None, ignore_discard=False, ignore_expires=False):
21082109
if cookie.expires is not None:
21092110
expires = str(cookie.expires)
21102111
else:
2111-
expires = ""
2112+
# curl and Wget use 0 for session cookies, and ignore
2113+
# the line if this field is empty.
2114+
expires = "0"
21122115
if cookie.value is None:
21132116
# cookies.txt regards 'Set-Cookie: foo' as a cookie
21142117
# with no name, whereas http.cookiejar regards it as a

Lib/profiling/sampling/_flamegraph_assets/flamegraph.js

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,10 @@ function getDisplayName(moduleName, filename) {
9999
return filename;
100100
}
101101

102+
function samplesToMilliseconds(samples, data) {
103+
return (samples * data.stats.sample_interval_usec / 1000).toFixed(2);
104+
}
105+
102106
function selectFlamegraphData(selectedThreadId = null) {
103107
let baseData = isShowingElided ? elidedFlamegraphData : normalData;
104108

@@ -255,12 +259,12 @@ function setupLogos() {
255259
// Status Bar
256260
// ============================================================================
257261

258-
function updateStatusBar(nodeData, rootValue) {
262+
function updateStatusBar(nodeData, rootValue, data) {
259263
const funcname = resolveString(nodeData.funcname) || resolveString(nodeData.name) || "--";
260264
const filename = resolveString(nodeData.filename) || "";
261265
const moduleName = resolveString(nodeData.module) || "";
262266
const lineno = nodeData.lineno;
263-
const timeMs = (nodeData.value / 1000).toFixed(2);
267+
const timeMs = samplesToMilliseconds(nodeData.value, data);
264268
const percent = rootValue > 0 ? ((nodeData.value / rootValue) * 100).toFixed(1) : "0.0";
265269

266270
const brandEl = document.getElementById('status-brand');
@@ -322,9 +326,9 @@ function createPythonTooltip(data) {
322326
.style("opacity", 0);
323327
}
324328

325-
const timeMs = (d.data.value / 1000).toFixed(2);
329+
const timeMs = samplesToMilliseconds(d.data.value, data);
326330
const selfSamples = d.data.self || 0;
327-
const selfMs = (selfSamples / 1000).toFixed(2);
331+
const selfMs = samplesToMilliseconds(selfSamples, data);
328332
const percentage = ((d.data.value / data.value) * 100).toFixed(2);
329333
const relativePercentage = Math.min(100, ((d.data.value / (zoomedNodeValue ?? data.value)) * 100)).toFixed(2);
330334
const calls = d.data.calls || 0;
@@ -408,9 +412,9 @@ function createPythonTooltip(data) {
408412
// Differential stats section
409413
let diffSection = "";
410414
if (d.data.diff !== undefined && d.data.baseline !== undefined) {
411-
const baselineSelf = (d.data.baseline / 1000).toFixed(2);
412-
const currentSelf = ((d.data.self_time || 0) / 1000).toFixed(2);
413-
const diffMs = (d.data.diff / 1000).toFixed(2);
415+
const baselineSelf = samplesToMilliseconds(d.data.baseline, data);
416+
const currentSelf = samplesToMilliseconds(d.data.self_time || 0, data);
417+
const diffMs = samplesToMilliseconds(d.data.diff, data);
414418
const diffPct = d.data.diff_pct;
415419
const sign = d.data.diff >= 0 ? "+" : "";
416420
const diffClass = d.data.diff > 0 ? "regression" : (d.data.diff < 0 ? "improvement" : "neutral");
@@ -508,7 +512,7 @@ function createPythonTooltip(data) {
508512
.style("opacity", 1);
509513

510514
// Update status bar
511-
updateStatusBar(d.data, data.value);
515+
updateStatusBar(d.data, data.value, data);
512516
};
513517

514518
pythonTooltip.hide = function () {

Lib/profiling/sampling/stack_collector.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ def export(self, filename):
7070
class FlamegraphCollector(StackTraceCollector):
7171
def __init__(self, *args, **kwargs):
7272
super().__init__(*args, **kwargs)
73-
self.stats = {}
73+
self.stats = {"sample_interval_usec": self.sample_interval_usec}
7474
self._root = {
7575
"samples": 0,
7676
"children": {},

Lib/socket.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -327,8 +327,18 @@ def makefile(self, mode="r", buffering=None, *,
327327
rawmode += "w"
328328
raw = SocketIO(self, rawmode)
329329
self._io_refs += 1
330+
line_buffering = False
330331
if buffering is None:
331332
buffering = -1
333+
if buffering == 1:
334+
if binary:
335+
import warnings
336+
warnings.warn("line buffering (buffering=1) isn't supported "
337+
"in binary mode, the default buffer size will "
338+
"be used", RuntimeWarning, 2)
339+
else:
340+
line_buffering = True
341+
buffering = -1
332342
if buffering < 0:
333343
buffering = io.DEFAULT_BUFFER_SIZE
334344
if buffering == 0:
@@ -345,7 +355,8 @@ def makefile(self, mode="r", buffering=None, *,
345355
if binary:
346356
return buffer
347357
encoding = io.text_encoding(encoding)
348-
text = io.TextIOWrapper(buffer, encoding, errors, newline)
358+
text = io.TextIOWrapper(
359+
buffer, encoding, errors, newline, line_buffering)
349360
text.mode = mode
350361
return text
351362

0 commit comments

Comments
 (0)