Skip to content

Commit 77e94cb

Browse files
committed
Merge remote-tracking branch 'upstream/main' into pythongh-116168-remove-extra-_check_stack_space-ops
2 parents 64fac38 + 7ecd55d commit 77e94cb

File tree

171 files changed

+6385
-4019
lines changed

Some content is hidden

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

171 files changed

+6385
-4019
lines changed

Doc/library/datetime.rst

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1079,6 +1079,24 @@ Other constructors, all class methods:
10791079
time tuple. See also :ref:`strftime-strptime-behavior` and
10801080
:meth:`datetime.fromisoformat`.
10811081

1082+
.. versionchanged:: 3.13
1083+
1084+
If *format* specifies a day of month without a year a
1085+
:exc:`DeprecationWarning` is now emitted. This is to avoid a quadrennial
1086+
leap year bug in code seeking to parse only a month and day as the
1087+
default year used in absence of one in the format is not a leap year.
1088+
Such *format* values may raise an error as of Python 3.15. The
1089+
workaround is to always include a year in your *format*. If parsing
1090+
*date_string* values that do not have a year, explicitly add a year that
1091+
is a leap year before parsing:
1092+
1093+
.. doctest::
1094+
1095+
>>> from datetime import datetime
1096+
>>> date_string = "02/29"
1097+
>>> when = datetime.strptime(f"{date_string};1984", "%m/%d;%Y") # Avoids leap year bug.
1098+
>>> when.strftime("%B %d") # doctest: +SKIP
1099+
'February 29'
10821100

10831101

10841102
Class attributes:
@@ -2657,6 +2675,25 @@ Notes:
26572675
for formats ``%d``, ``%m``, ``%H``, ``%I``, ``%M``, ``%S``, ``%j``, ``%U``,
26582676
``%W``, and ``%V``. Format ``%y`` does require a leading zero.
26592677

2678+
(10)
2679+
When parsing a month and day using :meth:`~.datetime.strptime`, always
2680+
include a year in the format. If the value you need to parse lacks a year,
2681+
append an explicit dummy leap year. Otherwise your code will raise an
2682+
exception when it encounters leap day because the default year used by the
2683+
parser is not a leap year. Users run into this bug every four years...
2684+
2685+
.. doctest::
2686+
2687+
>>> month_day = "02/29"
2688+
>>> datetime.strptime(f"{month_day};1984", "%m/%d;%Y") # No leap year bug.
2689+
datetime.datetime(1984, 2, 29, 0, 0)
2690+
2691+
.. deprecated-removed:: 3.13 3.15
2692+
:meth:`~.datetime.strptime` calls using a format string containing
2693+
a day of month without a year now emit a
2694+
:exc:`DeprecationWarning`. In 3.15 or later we may change this into
2695+
an error or change the default year to a leap year. See :gh:`70647`.
2696+
26602697
.. rubric:: Footnotes
26612698

26622699
.. [#] If, that is, we ignore the effects of Relativity

Doc/library/importlib.resources.abc.rst

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -109,13 +109,35 @@
109109

110110
Return True if self is a file.
111111

112-
.. abstractmethod:: joinpath(child)
112+
.. abstractmethod:: joinpath(*pathsegments)
113113

114-
Return Traversable child in self.
114+
Traverse directories according to *pathsegments* and return
115+
the result as :class:`!Traversable`.
116+
117+
Each *pathsegments* argument may contain multiple names separated by
118+
forward slashes (``/``, ``posixpath.sep`` ).
119+
For example, the following are equivalent::
120+
121+
files.joinpath('subdir', 'subsuddir', 'file.txt')
122+
files.joinpath('subdir/subsuddir/file.txt')
123+
124+
Note that some :class:`!Traversable` implementations
125+
might not be updated to the latest version of the protocol.
126+
For compatibility with such implementations, provide a single argument
127+
without path separators to each call to ``joinpath``. For example::
128+
129+
files.joinpath('subdir').joinpath('subsubdir').joinpath('file.txt')
130+
131+
.. versionchanged:: 3.11
132+
133+
``joinpath`` accepts multiple *pathsegments*, and these segments
134+
may contain forward slashes as path separators.
135+
Previously, only a single *child* argument was accepted.
115136

116137
.. abstractmethod:: __truediv__(child)
117138

118139
Return Traversable child in self.
140+
Equivalent to ``joinpath(child)``.
119141

120142
.. abstractmethod:: open(mode='r', *args, **kwargs)
121143

Doc/library/unittest.rst

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1880,8 +1880,8 @@ Loading and running tests
18801880
Python identifiers) will be loaded.
18811881

18821882
All test modules must be importable from the top level of the project. If
1883-
the start directory is not the top level directory then the top level
1884-
directory must be specified separately.
1883+
the start directory is not the top level directory then *top_level_dir*
1884+
must be specified separately.
18851885

18861886
If importing a module fails, for example due to a syntax error, then
18871887
this will be recorded as a single error and discovery will continue. If
@@ -1901,9 +1901,11 @@ Loading and running tests
19011901
package.
19021902

19031903
The pattern is deliberately not stored as a loader attribute so that
1904-
packages can continue discovery themselves. *top_level_dir* is stored so
1905-
``load_tests`` does not need to pass this argument in to
1906-
``loader.discover()``.
1904+
packages can continue discovery themselves.
1905+
1906+
*top_level_dir* is stored internally, and used as a default to any
1907+
nested calls to ``discover()``. That is, if a package's ``load_tests``
1908+
calls ``loader.discover()``, it does not need to pass this argument.
19071909

19081910
*start_dir* can be a dotted module name as well as a directory.
19091911

@@ -1930,6 +1932,9 @@ Loading and running tests
19301932
*start_dir* can not be a :term:`namespace packages <namespace package>`.
19311933
It has been broken since Python 3.7 and Python 3.11 officially remove it.
19321934

1935+
.. versionchanged:: 3.13
1936+
*top_level_dir* is only stored for the duration of *discover* call.
1937+
19331938

19341939
The following attributes of a :class:`TestLoader` can be configured either by
19351940
subclassing or assignment on an instance:

Grammar/python.gram

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1013,6 +1013,7 @@ kwargs[asdl_seq*]:
10131013
starred_expression[expr_ty]:
10141014
| invalid_starred_expression
10151015
| '*' a=expression { _PyAST_Starred(a, Load, EXTRA) }
1016+
| '*' { RAISE_SYNTAX_ERROR("Invalid star expression") }
10161017

10171018
kwarg_or_starred[KeywordOrStarred*]:
10181019
| invalid_kwarg
@@ -1133,8 +1134,8 @@ func_type_comment[Token*]:
11331134

11341135
# From here on, there are rules for invalid syntax with specialised error messages
11351136
invalid_arguments:
1136-
| ((','.(starred_expression | ( assignment_expression | expression !':=') !'=')+ ',' kwargs) | kwargs) ',' b='*' {
1137-
RAISE_SYNTAX_ERROR_KNOWN_LOCATION(b, "iterable argument unpacking follows keyword argument unpacking") }
1137+
| ((','.(starred_expression | ( assignment_expression | expression !':=') !'=')+ ',' kwargs) | kwargs) a=',' ','.(starred_expression !'=')+ {
1138+
RAISE_SYNTAX_ERROR_STARTING_FROM(a, "iterable argument unpacking follows keyword argument unpacking") }
11381139
| a=expression b=for_if_clauses ',' [args | expression for_if_clauses] {
11391140
RAISE_SYNTAX_ERROR_KNOWN_RANGE(a, _PyPegen_get_last_comprehension_item(PyPegen_last_item(b, comprehension_ty)), "Generator expression must be parenthesized") }
11401141
| a=NAME b='=' expression for_if_clauses {
@@ -1396,6 +1397,7 @@ invalid_kvpair:
13961397
| expression a=':' &('}'|',') {RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "expression expected after dictionary key and ':'") }
13971398
invalid_starred_expression:
13981399
| a='*' expression '=' b=expression { RAISE_SYNTAX_ERROR_KNOWN_RANGE(a, b, "cannot assign to iterable argument unpacking") }
1400+
13991401
invalid_replacement_field:
14001402
| '{' a='=' { RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "f-string: valid expression required before '='") }
14011403
| '{' a='!' { RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "f-string: valid expression required before '!'") }

Include/cpython/compile.h

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -32,28 +32,8 @@ typedef struct {
3232
#define _PyCompilerFlags_INIT \
3333
(PyCompilerFlags){.cf_flags = 0, .cf_feature_version = PY_MINOR_VERSION}
3434

35-
/* source location information */
36-
typedef struct {
37-
int lineno;
38-
int end_lineno;
39-
int col_offset;
40-
int end_col_offset;
41-
} _PyCompilerSrcLocation;
42-
43-
#define SRC_LOCATION_FROM_AST(n) \
44-
(_PyCompilerSrcLocation){ \
45-
.lineno = (n)->lineno, \
46-
.end_lineno = (n)->end_lineno, \
47-
.col_offset = (n)->col_offset, \
48-
.end_col_offset = (n)->end_col_offset }
49-
5035
/* Future feature support */
5136

52-
typedef struct {
53-
int ff_features; /* flags set by future statements */
54-
_PyCompilerSrcLocation ff_location; /* location of last future statement */
55-
} PyFutureFeatures;
56-
5737
#define FUTURE_NESTED_SCOPES "nested_scopes"
5838
#define FUTURE_GENERATORS "generators"
5939
#define FUTURE_DIVISION "division"

Include/cpython/pystats.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,12 +77,11 @@ typedef struct _object_stats {
7777
uint64_t frees;
7878
uint64_t to_freelist;
7979
uint64_t from_freelist;
80-
uint64_t new_values;
80+
uint64_t inline_values;
8181
uint64_t dict_materialized_on_request;
8282
uint64_t dict_materialized_new_key;
8383
uint64_t dict_materialized_too_big;
8484
uint64_t dict_materialized_str_subclass;
85-
uint64_t dict_dematerialized;
8685
uint64_t type_cache_hits;
8786
uint64_t type_cache_misses;
8887
uint64_t type_cache_dunder_hits;

Include/internal/pycore_bytes_methods.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,12 @@ extern PyObject *_Py_bytes_rfind(const char *str, Py_ssize_t len, PyObject *args
3232
extern PyObject *_Py_bytes_rindex(const char *str, Py_ssize_t len, PyObject *args);
3333
extern PyObject *_Py_bytes_count(const char *str, Py_ssize_t len, PyObject *args);
3434
extern int _Py_bytes_contains(const char *str, Py_ssize_t len, PyObject *arg);
35-
extern PyObject *_Py_bytes_startswith(const char *str, Py_ssize_t len, PyObject *args);
36-
extern PyObject *_Py_bytes_endswith(const char *str, Py_ssize_t len, PyObject *args);
35+
extern PyObject *_Py_bytes_startswith(const char *str, Py_ssize_t len,
36+
PyObject *subobj, Py_ssize_t start,
37+
Py_ssize_t end);
38+
extern PyObject *_Py_bytes_endswith(const char *str, Py_ssize_t len,
39+
PyObject *subobj, Py_ssize_t start,
40+
Py_ssize_t end);
3741

3842
/* The maketrans() static method. */
3943
extern PyObject* _Py_bytes_maketrans(Py_buffer *frm, Py_buffer *to);

Include/internal/pycore_code.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,10 @@ typedef struct {
7979
typedef struct {
8080
uint16_t counter;
8181
uint16_t type_version[2];
82-
uint16_t keys_version[2];
82+
union {
83+
uint16_t keys_version[2];
84+
uint16_t dict_offset;
85+
};
8386
uint16_t descr[4];
8487
} _PyLoadMethodCache;
8588

Include/internal/pycore_compile.h

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ extern "C" {
88
# error "this header requires Py_BUILD_CORE define"
99
#endif
1010

11+
#include "pycore_symtable.h" // _Py_SourceLocation
12+
1113
struct _arena; // Type defined in pycore_pyarena.h
1214
struct _mod; // Type defined in pycore_ast.h
1315

@@ -27,7 +29,7 @@ extern int _PyCompile_AstOptimize(
2729
int optimize,
2830
struct _arena *arena);
2931

30-
static const _PyCompilerSrcLocation NO_LOCATION = {-1, -1, -1, -1};
32+
struct _Py_SourceLocation;
3133

3234
extern int _PyAST_Optimize(
3335
struct _mod *,
@@ -44,7 +46,7 @@ typedef struct {
4446
typedef struct {
4547
int i_opcode;
4648
int i_oparg;
47-
_PyCompilerSrcLocation i_loc;
49+
_Py_SourceLocation i_loc;
4850
_PyCompile_ExceptHandlerInfo i_except_handler_info;
4951

5052
/* Used by the assembler */
@@ -65,7 +67,7 @@ typedef struct {
6567
int _PyCompile_InstructionSequence_UseLabel(_PyCompile_InstructionSequence *seq, int lbl);
6668
int _PyCompile_InstructionSequence_Addop(_PyCompile_InstructionSequence *seq,
6769
int opcode, int oparg,
68-
_PyCompilerSrcLocation loc);
70+
_Py_SourceLocation loc);
6971
int _PyCompile_InstructionSequence_ApplyLabelMap(_PyCompile_InstructionSequence *seq);
7072

7173
typedef struct {

Include/internal/pycore_dict.h

Lines changed: 52 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ extern "C" {
1111

1212
#include "pycore_freelist.h" // _PyFreeListState
1313
#include "pycore_identifier.h" // _Py_Identifier
14-
#include "pycore_object.h" // PyDictOrValues
14+
#include "pycore_object.h" // PyManagedDictPointer
1515

1616
// Unsafe flavor of PyDict_GetItemWithError(): no error checking
1717
extern PyObject* _PyDict_GetItemWithError(PyObject *dp, PyObject *key);
@@ -181,6 +181,10 @@ struct _dictkeysobject {
181181
* [-1] = prefix size. [-2] = used size. size[-2-n...] = insertion order.
182182
*/
183183
struct _dictvalues {
184+
uint8_t capacity;
185+
uint8_t size;
186+
uint8_t embedded;
187+
uint8_t valid;
184188
PyObject *values[1];
185189
};
186190

@@ -196,6 +200,7 @@ static inline void* _DK_ENTRIES(PyDictKeysObject *dk) {
196200
size_t index = (size_t)1 << dk->dk_log2_index_bytes;
197201
return (&indices[index]);
198202
}
203+
199204
static inline PyDictKeyEntry* DK_ENTRIES(PyDictKeysObject *dk) {
200205
assert(dk->dk_kind == DICT_KEYS_GENERAL);
201206
return (PyDictKeyEntry*)_DK_ENTRIES(dk);
@@ -211,9 +216,6 @@ static inline PyDictUnicodeEntry* DK_UNICODE_ENTRIES(PyDictKeysObject *dk) {
211216
#define DICT_WATCHER_MASK ((1 << DICT_MAX_WATCHERS) - 1)
212217
#define DICT_WATCHER_AND_MODIFICATION_MASK ((1 << (DICT_MAX_WATCHERS + DICT_WATCHED_MUTATION_BITS)) - 1)
213218

214-
#define DICT_VALUES_SIZE(values) ((uint8_t *)values)[-1]
215-
#define DICT_VALUES_USED_SIZE(values) ((uint8_t *)values)[-2]
216-
217219
#ifdef Py_GIL_DISABLED
218220
#define DICT_NEXT_VERSION(INTERP) \
219221
(_Py_atomic_add_uint64(&(INTERP)->dict_state.global_version, DICT_VERSION_INCREMENT) + DICT_VERSION_INCREMENT)
@@ -246,25 +248,63 @@ _PyDict_NotifyEvent(PyInterpreterState *interp,
246248
return DICT_NEXT_VERSION(interp) | (mp->ma_version_tag & DICT_WATCHER_AND_MODIFICATION_MASK);
247249
}
248250

249-
extern PyObject *_PyObject_MakeDictFromInstanceAttributes(PyObject *obj, PyDictValues *values);
250-
PyAPI_FUNC(bool) _PyObject_MakeInstanceAttributesFromDict(PyObject *obj, PyDictOrValues *dorv);
251+
extern PyDictObject *_PyObject_MakeDictFromInstanceAttributes(PyObject *obj);
252+
251253
PyAPI_FUNC(PyObject *)_PyDict_FromItems(
252254
PyObject *const *keys, Py_ssize_t keys_offset,
253255
PyObject *const *values, Py_ssize_t values_offset,
254256
Py_ssize_t length);
255257

258+
static inline uint8_t *
259+
get_insertion_order_array(PyDictValues *values)
260+
{
261+
return (uint8_t *)&values->values[values->capacity];
262+
}
263+
256264
static inline void
257265
_PyDictValues_AddToInsertionOrder(PyDictValues *values, Py_ssize_t ix)
258266
{
259267
assert(ix < SHARED_KEYS_MAX_SIZE);
260-
uint8_t *size_ptr = ((uint8_t *)values)-2;
261-
int size = *size_ptr;
262-
assert(size+2 < DICT_VALUES_SIZE(values));
263-
size++;
264-
size_ptr[-size] = (uint8_t)ix;
265-
*size_ptr = size;
268+
int size = values->size;
269+
uint8_t *array = get_insertion_order_array(values);
270+
assert(size < values->capacity);
271+
assert(((uint8_t)ix) == ix);
272+
array[size] = (uint8_t)ix;
273+
values->size = size+1;
274+
}
275+
276+
static inline size_t
277+
shared_keys_usable_size(PyDictKeysObject *keys)
278+
{
279+
#ifdef Py_GIL_DISABLED
280+
// dk_usable will decrease for each instance that is created and each
281+
// value that is added. dk_nentries will increase for each value that
282+
// is added. We want to always return the right value or larger.
283+
// We therefore increase dk_nentries first and we decrease dk_usable
284+
// second, and conversely here we read dk_usable first and dk_entries
285+
// second (to avoid the case where we read entries before the increment
286+
// and read usable after the decrement)
287+
return (size_t)(_Py_atomic_load_ssize_acquire(&keys->dk_usable) +
288+
_Py_atomic_load_ssize_acquire(&keys->dk_nentries));
289+
#else
290+
return (size_t)keys->dk_nentries + (size_t)keys->dk_usable;
291+
#endif
266292
}
267293

294+
static inline size_t
295+
_PyInlineValuesSize(PyTypeObject *tp)
296+
{
297+
PyDictKeysObject *keys = ((PyHeapTypeObject*)tp)->ht_cached_keys;
298+
assert(keys != NULL);
299+
size_t size = shared_keys_usable_size(keys);
300+
size_t prefix_size = _Py_SIZE_ROUND_UP(size, sizeof(PyObject *));
301+
assert(prefix_size < 256);
302+
return prefix_size + (size + 1) * sizeof(PyObject *);
303+
}
304+
305+
int
306+
_PyDict_DetachFromObject(PyDictObject *dict, PyObject *obj);
307+
268308
#ifdef __cplusplus
269309
}
270310
#endif

Include/internal/pycore_flowgraph.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ typedef struct {
1818
struct _PyCfgBuilder;
1919

2020
int _PyCfgBuilder_UseLabel(struct _PyCfgBuilder *g, _PyCfgJumpTargetLabel lbl);
21-
int _PyCfgBuilder_Addop(struct _PyCfgBuilder *g, int opcode, int oparg, _PyCompilerSrcLocation loc);
21+
int _PyCfgBuilder_Addop(struct _PyCfgBuilder *g, int opcode, int oparg, _Py_SourceLocation loc);
2222

2323
struct _PyCfgBuilder* _PyCfgBuilder_New(void);
2424
void _PyCfgBuilder_Free(struct _PyCfgBuilder *g);

0 commit comments

Comments
 (0)