Skip to content

Commit 937aa63

Browse files
authored
Merge branch 'main' into fix/ubsan/casts-111178
2 parents 5e68e29 + d372472 commit 937aa63

File tree

8 files changed

+53
-54
lines changed

8 files changed

+53
-54
lines changed

Doc/library/datetime.rst

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -699,8 +699,8 @@ Instance methods:
699699

700700
.. method:: date.replace(year=self.year, month=self.month, day=self.day)
701701

702-
Return a date with the same value, except for those parameters given new
703-
values by whichever keyword arguments are specified.
702+
Return a new :class:`date` object with the same values, but with specified
703+
parameters updated.
704704

705705
Example::
706706

@@ -709,8 +709,8 @@ Instance methods:
709709
>>> d.replace(day=26)
710710
datetime.date(2002, 12, 26)
711711

712-
:class:`date` objects are also supported by generic function
713-
:func:`copy.replace`.
712+
The generic function :func:`copy.replace` also supports :class:`date`
713+
objects.
714714

715715

716716
.. method:: date.timetuple()
@@ -1348,10 +1348,10 @@ Instance methods:
13481348
hour=self.hour, minute=self.minute, second=self.second, microsecond=self.microsecond, \
13491349
tzinfo=self.tzinfo, *, fold=0)
13501350
1351-
Return a datetime with the same attributes, except for those attributes given
1352-
new values by whichever keyword arguments are specified. Note that
1353-
``tzinfo=None`` can be specified to create a naive datetime from an aware
1354-
datetime with no conversion of date and time data.
1351+
Return a new :class:`datetime` object with the same attributes, but with
1352+
specified parameters updated. Note that ``tzinfo=None`` can be specified to
1353+
create a naive datetime from an aware datetime with no conversion of date
1354+
and time data.
13551355

13561356
:class:`.datetime` objects are also supported by generic function
13571357
:func:`copy.replace`.
@@ -1942,10 +1942,10 @@ Instance methods:
19421942
.. method:: time.replace(hour=self.hour, minute=self.minute, second=self.second, \
19431943
microsecond=self.microsecond, tzinfo=self.tzinfo, *, fold=0)
19441944
1945-
Return a :class:`.time` with the same value, except for those attributes given
1946-
new values by whichever keyword arguments are specified. Note that
1947-
``tzinfo=None`` can be specified to create a naive :class:`.time` from an
1948-
aware :class:`.time`, without conversion of the time data.
1945+
Return a new :class:`.time` with the same values, but with specified
1946+
parameters updated. Note that ``tzinfo=None`` can be specified to create a
1947+
naive :class:`.time` from an aware :class:`.time`, without conversion of the
1948+
time data.
19491949

19501950
:class:`.time` objects are also supported by generic function
19511951
:func:`copy.replace`.

Lib/pathlib/__init__.py

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1105,11 +1105,7 @@ def copy(self, target, **kwargs):
11051105
if not hasattr(target, 'with_segments'):
11061106
target = self.with_segments(target)
11071107
ensure_distinct_paths(self, target)
1108-
try:
1109-
copy_to_target = target._copy_from
1110-
except AttributeError:
1111-
raise TypeError(f"Target path is not writable: {target!r}") from None
1112-
copy_to_target(self, **kwargs)
1108+
target._copy_from(self, **kwargs)
11131109
return target.joinpath() # Empty join to ensure fresh metadata.
11141110

11151111
def copy_into(self, target_dir, **kwargs):

Lib/pathlib/_os.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,12 @@ def magic_open(path, mode='r', buffering=-1, encoding=None, errors=None,
186186
pass
187187
else:
188188
return attr(path, buffering, encoding, errors, newline)
189+
elif encoding is not None:
190+
raise ValueError("binary mode doesn't take an encoding argument")
191+
elif errors is not None:
192+
raise ValueError("binary mode doesn't take an errors argument")
193+
elif newline is not None:
194+
raise ValueError("binary mode doesn't take a newline argument")
189195

190196
try:
191197
attr = getattr(cls, f'__open_{mode}b__')

Lib/pathlib/types.py

Lines changed: 10 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,12 @@
1717
from typing import Optional, Protocol, runtime_checkable
1818

1919

20-
def _explode_path(path):
20+
def _explode_path(path, split):
2121
"""
2222
Split the path into a 2-tuple (anchor, parts), where *anchor* is the
2323
uppermost parent of the path (equivalent to path.parents[-1]), and
2424
*parts* is a reversed list of parts following the anchor.
2525
"""
26-
split = path.parser.split
27-
path = str(path)
2826
parent, name = split(path)
2927
names = []
3028
while path != parent:
@@ -95,7 +93,7 @@ def __str__(self):
9593
@property
9694
def anchor(self):
9795
"""The concatenation of the drive and root, or ''."""
98-
return _explode_path(self)[0]
96+
return _explode_path(str(self), self.parser.split)[0]
9997

10098
@property
10199
def name(self):
@@ -169,7 +167,7 @@ def with_suffix(self, suffix):
169167
def parts(self):
170168
"""An object providing sequence-like access to the
171169
components in the filesystem path."""
172-
anchor, parts = _explode_path(self)
170+
anchor, parts = _explode_path(str(self), self.parser.split)
173171
if anchor:
174172
parts.append(anchor)
175173
return tuple(reversed(parts))
@@ -221,11 +219,9 @@ def full_match(self, pattern):
221219
Return True if this path matches the given glob-style pattern. The
222220
pattern is matched against the entire path.
223221
"""
224-
if not hasattr(pattern, 'with_segments'):
225-
pattern = self.with_segments(pattern)
226222
case_sensitive = self.parser.normcase('Aa') == 'Aa'
227-
globber = _PathGlobber(pattern.parser.sep, case_sensitive, recursive=True)
228-
match = globber.compile(str(pattern), altsep=pattern.parser.altsep)
223+
globber = _PathGlobber(self.parser.sep, case_sensitive, recursive=True)
224+
match = globber.compile(pattern, altsep=self.parser.altsep)
229225
return match(str(self)) is not None
230226

231227

@@ -282,11 +278,11 @@ def glob(self, pattern, *, recurse_symlinks=True):
282278
"""Iterate over this subtree and yield all existing files (of any
283279
kind, including directories) matching the given relative pattern.
284280
"""
285-
if not hasattr(pattern, 'with_segments'):
286-
pattern = self.with_segments(pattern)
287-
anchor, parts = _explode_path(pattern)
281+
anchor, parts = _explode_path(pattern, self.parser.split)
288282
if anchor:
289283
raise NotImplementedError("Non-relative patterns are unsupported")
284+
elif not parts:
285+
raise ValueError(f"Unacceptable pattern: {pattern!r}")
290286
elif not recurse_symlinks:
291287
raise NotImplementedError("recurse_symlinks=False is unsupported")
292288
case_sensitive = self.parser.normcase('Aa') == 'Aa'
@@ -336,14 +332,8 @@ def copy(self, target, **kwargs):
336332
"""
337333
Recursively copy this file or directory tree to the given destination.
338334
"""
339-
if not hasattr(target, 'with_segments'):
340-
target = self.with_segments(target)
341335
ensure_distinct_paths(self, target)
342-
try:
343-
copy_to_target = target._copy_from
344-
except AttributeError:
345-
raise TypeError(f"Target path is not writable: {target!r}") from None
346-
copy_to_target(self, **kwargs)
336+
target._copy_from(self, **kwargs)
347337
return target.joinpath() # Empty join to ensure fresh metadata.
348338

349339
def copy_into(self, target_dir, **kwargs):
@@ -353,11 +343,7 @@ def copy_into(self, target_dir, **kwargs):
353343
name = self.name
354344
if not name:
355345
raise ValueError(f"{self!r} has an empty name")
356-
elif hasattr(target_dir, 'with_segments'):
357-
target = target_dir / name
358-
else:
359-
target = self.with_segments(target_dir, name)
360-
return self.copy(target, **kwargs)
346+
return self.copy(target_dir / name, **kwargs)
361347

362348

363349
class _WritablePath(_JoinablePath):

Lib/test/test_pathlib/test_read.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,9 @@ def test_open_rb(self):
3939
p = self.root / 'fileA'
4040
with magic_open(p, 'rb') as f:
4141
self.assertEqual(f.read(), b'this is file A\n')
42+
self.assertRaises(ValueError, magic_open, p, 'rb', encoding='utf8')
43+
self.assertRaises(ValueError, magic_open, p, 'rb', errors='strict')
44+
self.assertRaises(ValueError, magic_open, p, 'rb', newline='')
4245

4346
def test_read_bytes(self):
4447
p = self.root / 'fileA'
@@ -127,6 +130,8 @@ def check(pattern, expected):
127130
check("**/file*",
128131
["fileA", "dirA/linkC/fileB", "dirB/fileB", "dirC/fileC", "dirC/dirD/fileD",
129132
"linkB/fileB"])
133+
with self.assertRaisesRegex(ValueError, 'Unacceptable pattern'):
134+
list(p.glob(''))
130135

131136
def test_walk_top_down(self):
132137
it = self.root.walk()

Lib/test/test_pathlib/test_write.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,9 @@ def test_open_wb(self):
4141
#self.assertIsInstance(f, io.BufferedWriter)
4242
f.write(b'this is file A\n')
4343
self.assertEqual(self.ground.readbytes(p), b'this is file A\n')
44+
self.assertRaises(ValueError, magic_open, p, 'wb', encoding='utf8')
45+
self.assertRaises(ValueError, magic_open, p, 'wb', errors='strict')
46+
self.assertRaises(ValueError, magic_open, p, 'wb', newline='')
4447

4548
def test_write_bytes(self):
4649
p = self.root / 'fileA'

Modules/socketmodule.c

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1380,6 +1380,11 @@ makebdaddr(bdaddr_t *bdaddr)
13801380
}
13811381
#endif
13821382

1383+
PyObject*
1384+
unicode_fsdecode(void *arg)
1385+
{
1386+
return PyUnicode_DecodeFSDefault((const char*)arg);
1387+
}
13831388

13841389
/* Create an object representing the given socket address,
13851390
suitable for passing it back to bind(), connect() etc.
@@ -1616,26 +1621,25 @@ makesockaddr(SOCKET_T sockfd, struct sockaddr *addr, size_t addrlen, int proto)
16161621
#ifdef CAN_ISOTP
16171622
case CAN_ISOTP:
16181623
{
1619-
return Py_BuildValue("O&kk", PyUnicode_DecodeFSDefault,
1620-
ifname,
1621-
a->can_addr.tp.rx_id,
1622-
a->can_addr.tp.tx_id);
1624+
return Py_BuildValue("O&kk", unicode_fsdecode,
1625+
ifname,
1626+
a->can_addr.tp.rx_id,
1627+
a->can_addr.tp.tx_id);
16231628
}
16241629
#endif /* CAN_ISOTP */
16251630
#ifdef CAN_J1939
16261631
case CAN_J1939:
16271632
{
1628-
return Py_BuildValue("O&KIB", PyUnicode_DecodeFSDefault,
1629-
ifname,
1630-
(unsigned long long)a->can_addr.j1939.name,
1631-
(unsigned int)a->can_addr.j1939.pgn,
1632-
a->can_addr.j1939.addr);
1633+
return Py_BuildValue("O&KIB", unicode_fsdecode,
1634+
ifname,
1635+
(unsigned long long)a->can_addr.j1939.name,
1636+
(unsigned int)a->can_addr.j1939.pgn,
1637+
a->can_addr.j1939.addr);
16331638
}
16341639
#endif /* CAN_J1939 */
16351640
default:
16361641
{
1637-
return Py_BuildValue("(O&)", PyUnicode_DecodeFSDefault,
1638-
ifname);
1642+
return Py_BuildValue("(O&)", unicode_fsdecode, ifname);
16391643
}
16401644
}
16411645
}
@@ -7161,7 +7165,7 @@ socket_if_nameindex(PyObject *self, PyObject *arg)
71617165
}
71627166
#endif
71637167
PyObject *ni_tuple = Py_BuildValue("IO&",
7164-
ni[i].if_index, PyUnicode_DecodeFSDefault, ni[i].if_name);
7168+
ni[i].if_index, unicode_fsdecode, ni[i].if_name);
71657169

71667170
if (ni_tuple == NULL || PyList_Append(list, ni_tuple) == -1) {
71677171
Py_XDECREF(ni_tuple);

PC/_wmimodule.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,6 @@ _wmi_exec_query_impl(PyObject *module, PyObject *query)
240240

241241
/*[clinic end generated code]*/
242242
{
243-
PyObject *result = NULL;
244243
HANDLE hThread = NULL;
245244
int err = 0;
246245
WCHAR buffer[8192];

0 commit comments

Comments
 (0)