Skip to content

Commit 8af3be7

Browse files
authored
Merge branch 'main' into sem-macosx-multiprocessing-module-C
2 parents 45017a9 + 310fe88 commit 8af3be7

11 files changed

Lines changed: 93 additions & 80 deletions

File tree

Doc/whatsnew/3.16.rst

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -106,10 +106,13 @@ module_name
106106
Removed
107107
=======
108108

109-
module_name
110-
-----------
109+
sysconfig
110+
---------
111+
112+
* The :func:`!sysconfig.expand_makefile_vars` function
113+
which has been deprecated since Python 3.14.
114+
Use the ``vars`` argument of :func:`sysconfig.get_paths` instead.
111115

112-
* TODO
113116
.. Add removals above alphabetically, not here at the end.
114117
115118
@@ -156,4 +159,3 @@ Deprecated C APIs
156159
157160
Removed C APIs
158161
--------------
159-

Include/cpython/bytesobject.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
typedef struct {
66
PyObject_VAR_HEAD
77
Py_DEPRECATED(3.11) Py_hash_t ob_shash;
8-
char ob_sval[1];
8+
unsigned char ob_sval[1];
99

1010
/* Invariants:
1111
* ob_sval contains space for 'ob_size+1' elements.
@@ -20,7 +20,7 @@ PyAPI_FUNC(int) _PyBytes_Resize(PyObject **, Py_ssize_t);
2020
#define _PyBytes_CAST(op) \
2121
(assert(PyBytes_Check(op)), _Py_CAST(PyBytesObject*, op))
2222

23-
static inline char* PyBytes_AS_STRING(PyObject *op)
23+
static inline unsigned char* PyBytes_AS_STRING(PyObject *op)
2424
{
2525
return _PyBytes_CAST(op)->ob_sval;
2626
}

Include/internal/pycore_magic_number.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -297,9 +297,10 @@ Known values:
297297
Python 3.15a8 3664 (Fix __qualname__ for __annotate__ functions)
298298
Python 3.15a8 3665 (Add FOR_ITER_VIRTUAL and GET_ITER specializations)
299299
Python 3.15b1 3666 (Add SEND_VIRTUAL and SEND_ASYNC_GEN specializations)
300+
Python 3.16a0 3700 (Initial version)
300301
301302
302-
Python 3.16 will start with 3700
303+
Python 3.17 will start with 3750
303304
304305
Please don't copy-paste the same pre-release tag for new entries above!!!
305306
You should always use the *upcoming* tag. For example, if 3.12a6 came out
@@ -310,7 +311,7 @@ PC/launcher.c must also be updated.
310311
311312
*/
312313

313-
#define PYC_MAGIC_NUMBER 3666
314+
#define PYC_MAGIC_NUMBER 3700
314315
/* This is equivalent to converting PYC_MAGIC_NUMBER to 2 bytes
315316
(little-endian) and then appending b'\r\n'. */
316317
#define PYC_MAGIC_NUMBER_TOKEN \

Lib/sysconfig/__init__.py

Lines changed: 0 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -753,41 +753,3 @@ def get_python_version():
753753

754754
def _get_python_version_abi():
755755
return _PY_VERSION_SHORT + get_config_var("abi_thread")
756-
757-
758-
def expand_makefile_vars(s, vars):
759-
"""Expand Makefile-style variables -- "${foo}" or "$(foo)" -- in
760-
'string' according to 'vars' (a dictionary mapping variable names to
761-
values). Variables not present in 'vars' are silently expanded to the
762-
empty string. The variable values in 'vars' should not contain further
763-
variable expansions; if 'vars' is the output of 'parse_makefile()',
764-
you're fine. Returns a variable-expanded version of 's'.
765-
"""
766-
767-
import warnings
768-
warnings.warn(
769-
'sysconfig.expand_makefile_vars is deprecated and will be removed in '
770-
'Python 3.16. Use sysconfig.get_paths(vars=...) instead.',
771-
DeprecationWarning,
772-
stacklevel=2,
773-
)
774-
775-
import re
776-
777-
_findvar1_rx = r"\$\(([A-Za-z][A-Za-z0-9_]*)\)"
778-
_findvar2_rx = r"\${([A-Za-z][A-Za-z0-9_]*)}"
779-
780-
# This algorithm does multiple expansion, so if vars['foo'] contains
781-
# "${bar}", it will expand ${foo} to ${bar}, and then expand
782-
# ${bar}... and so forth. This is fine as long as 'vars' comes from
783-
# 'parse_makefile()', which takes care of such expansions eagerly,
784-
# according to make's variable expansion semantics.
785-
786-
while True:
787-
m = re.search(_findvar1_rx, s) or re.search(_findvar2_rx, s)
788-
if m:
789-
(beg, end) = m.span()
790-
s = s[0:beg] + vars.get(m.group(1)) + s[end:]
791-
else:
792-
break
793-
return s

Lib/test/test_robotparser.py

Lines changed: 50 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -646,26 +646,23 @@ def test_group_without_user_agent(self):
646646
)
647647
class BaseLocalNetworkTestCase:
648648

649-
def setUp(self):
649+
@classmethod
650+
def setUpClass(cls):
650651
# clear _opener global variable
651-
self.addCleanup(urllib.request.urlcleanup)
652+
cls.addClassCleanup(urllib.request.urlcleanup)
652653

653-
self.server = HTTPServer((socket_helper.HOST, 0), self.RobotHandler)
654+
cls.server = HTTPServer((socket_helper.HOST, 0), cls.RobotHandler)
655+
cls.addClassCleanup(cls.server.server_close)
654656

655-
self.t = threading.Thread(
657+
t = threading.Thread(
656658
name='HTTPServer serving',
657-
target=self.server.serve_forever,
659+
target=cls.server.serve_forever,
658660
# Short poll interval to make the test finish quickly.
659661
# Time between requests is short enough that we won't wake
660662
# up spuriously too many times.
661663
kwargs={'poll_interval':0.01})
662-
self.t.daemon = True # In case this function raises.
663-
self.t.start()
664-
665-
def tearDown(self):
666-
self.server.shutdown()
667-
self.t.join()
668-
self.server.server_close()
664+
cls.enterClassContext(threading_helper.start_threads([t]))
665+
cls.addClassCleanup(cls.server.shutdown)
669666

670667

671668
SAMPLE_ROBOTS_TXT = b'''\
@@ -687,7 +684,6 @@ def do_GET(self):
687684
def log_message(self, format, *args):
688685
pass
689686

690-
@threading_helper.reap_threads
691687
def testRead(self):
692688
# Test that reading a weird robots.txt doesn't fail.
693689
addr = self.server.server_address
@@ -709,24 +705,62 @@ def testRead(self):
709705
self.assertFalse(parser.can_fetch(agent, url + '/%2F[spam]/path'))
710706

711707

712-
class PasswordProtectedSiteTestCase(BaseLocalNetworkTestCase, unittest.TestCase):
708+
class HttpErrorsTestCase(BaseLocalNetworkTestCase, unittest.TestCase):
713709
class RobotHandler(BaseHTTPRequestHandler):
714710

715711
def do_GET(self):
716-
self.send_error(403, "Forbidden access")
712+
self.send_error(self.server.return_code)
717713

718714
def log_message(self, format, *args):
719715
pass
720716

721-
@threading_helper.reap_threads
717+
def setUp(self):
718+
# Make sure that a valid code is set in the test.
719+
self.server.return_code = None
720+
722721
def testPasswordProtectedSite(self):
722+
self.server.return_code = 403
723723
addr = self.server.server_address
724724
url = 'http://' + socket_helper.HOST + ':' + str(addr[1])
725725
robots_url = url + "/robots.txt"
726726
parser = urllib.robotparser.RobotFileParser()
727727
parser.set_url(url)
728728
parser.read()
729729
self.assertFalse(parser.can_fetch("*", robots_url))
730+
self.assertFalse(parser.can_fetch("*", url + '/some/file.html'))
731+
732+
def testNotFound(self):
733+
self.server.return_code = 404
734+
addr = self.server.server_address
735+
url = f'http://{socket_helper.HOST}:{addr[1]}'
736+
robots_url = url + "/robots.txt"
737+
parser = urllib.robotparser.RobotFileParser()
738+
parser.set_url(url)
739+
parser.read()
740+
self.assertTrue(parser.can_fetch("*", robots_url))
741+
self.assertTrue(parser.can_fetch("*", url + '/path/file.html'))
742+
743+
def testTeapot(self):
744+
self.server.return_code = 418
745+
addr = self.server.server_address
746+
url = f'http://{socket_helper.HOST}:{addr[1]}'
747+
robots_url = url + "/robots.txt"
748+
parser = urllib.robotparser.RobotFileParser()
749+
parser.set_url(url)
750+
parser.read()
751+
self.assertTrue(parser.can_fetch("*", robots_url))
752+
self.assertTrue(parser.can_fetch("*", url + '/pot-1?milk-type=Cream'))
753+
754+
def testServiceUnavailable(self):
755+
self.server.return_code = 503
756+
addr = self.server.server_address
757+
url = f'http://{socket_helper.HOST}:{addr[1]}'
758+
robots_url = url + "/robots.txt"
759+
parser = urllib.robotparser.RobotFileParser()
760+
parser.set_url(url)
761+
parser.read()
762+
self.assertFalse(parser.can_fetch("*", robots_url))
763+
self.assertFalse(parser.can_fetch("*", url + '/path/file.html'))
730764

731765

732766
@support.requires_working_socket()

Lib/urllib/robotparser.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,9 +65,17 @@ def read(self):
6565
f = urllib.request.urlopen(self.url)
6666
except urllib.error.HTTPError as err:
6767
if err.code in (401, 403):
68+
# If access to robot.txt has the status Unauthorized/Forbidden,
69+
# then most likely this applies to the entire site.
6870
self.disallow_all = True
69-
elif err.code >= 400 and err.code < 500:
71+
elif 400 <= err.code < 500:
72+
# RFC 9309, Section 2.3.1.3: the crawler MAY access any
73+
# resources on the server.
7074
self.allow_all = True
75+
elif 500 <= err.code < 600:
76+
# RFC 9309, Section 2.3.1.4: the crawler MUST assume
77+
# complete disallow.
78+
self.disallow_all = True
7179
err.close()
7280
else:
7381
raw = f.read()
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Disallow all access in :mod:`urllib.robotparser` if the ``robots.txt`` file
2+
is unreachable due to server or network errors.
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Removed the :func:`!sysconfig.expand_makefile_vars` function which has been
2+
deprecated since Python 3.14. Use the ``vars`` argument of
3+
:func:`sysconfig.get_paths` instead.

PC/launcher.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1273,6 +1273,7 @@ static PYC_MAGIC magic_values[] = {
12731273
{ 3550, 3599, L"3.13" },
12741274
{ 3600, 3649, L"3.14" },
12751275
{ 3650, 3699, L"3.15" },
1276+
{ 3700, 3749, L"3.16" },
12761277
{ 0 }
12771278
};
12781279

PC/pyconfig.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -330,21 +330,21 @@ Py_NO_ENABLE_SHARED to find out. Also support MS_NO_COREDLL for b/w compat */
330330
the linking is explicitly handled */
331331
# if defined(Py_GIL_DISABLED)
332332
# if defined(Py_DEBUG)
333-
# pragma comment(lib,"python315t_d.lib")
333+
# pragma comment(lib,"python316t_d.lib")
334334
# elif defined(Py_LIMITED_API) || defined(Py_TARGET_ABI3T)
335335
# pragma comment(lib,"python3t.lib")
336336
# else
337-
# pragma comment(lib,"python315t.lib")
337+
# pragma comment(lib,"python316t.lib")
338338
# endif /* Py_DEBUG */
339339
# else /* Py_GIL_DISABLED */
340340
# if defined(Py_DEBUG)
341-
# pragma comment(lib,"python315_d.lib")
341+
# pragma comment(lib,"python316_d.lib")
342342
# elif defined(Py_TARGET_ABI3T)
343343
# pragma comment(lib,"python3t.lib")
344344
# elif defined(Py_LIMITED_API)
345345
# pragma comment(lib,"python3.lib")
346346
# else
347-
# pragma comment(lib,"python315.lib")
347+
# pragma comment(lib,"python316.lib")
348348
# endif /* Py_DEBUG */
349349
# endif /* Py_GIL_DISABLED */
350350
# endif /* _MSC_VER && !Py_NO_LINK_LIB */

0 commit comments

Comments
 (0)