Skip to content

Commit

Permalink
Merge branch 'main' into modulelocals
Browse files Browse the repository at this point in the history
* main:
  pythongh-104799: PEP 695 backward compatibility for ast.unparse (python#105846)
  pythongh-105834: Add tests for calling `issubclass()` between two protocols (python#105835)
  CI: Remove docs build from Azure Pipelines (python#105823)
  pythongh-105844: Consistently use 'minor version' for X.Y versions (python#105851)
  Fix inaccuracies in "Assorted Topics" section of "Defining Extension Types" tutorial (python#104969)
  pythongh-105433: Add `pickle` tests for PEP695 (python#105443)
  bpo-44530: Document the change in MAKE_FUNCTION behavior (python#93189)
  pythonGH-103124: Multiline statement support for pdb (pythonGH-103125)
  pythonGH-105588: Add missing error checks to some obj2ast_* converters (pythonGH-105589)
  • Loading branch information
carljm committed Jun 16, 2023
2 parents 166aca9 + 957a974 commit b096651
Show file tree
Hide file tree
Showing 21 changed files with 391 additions and 106 deletions.
14 changes: 0 additions & 14 deletions .azure-pipelines/ci.yml
Expand Up @@ -14,20 +14,6 @@ jobs:
- template: ./prebuild-checks.yml


- job: Docs_PR
displayName: Docs PR
dependsOn: Prebuild
condition: and(succeeded(), eq(dependencies.Prebuild.outputs['docs.run'], 'true'))

pool:
vmImage: ubuntu-22.04

steps:
- template: ./docs-steps.yml
parameters:
upload: true


- job: macOS_CI_Tests
displayName: macOS CI Tests
dependsOn: Prebuild
Expand Down
47 changes: 0 additions & 47 deletions .azure-pipelines/docs-steps.yml

This file was deleted.

12 changes: 0 additions & 12 deletions .azure-pipelines/pr.yml
Expand Up @@ -14,18 +14,6 @@ jobs:
- template: ./prebuild-checks.yml


- job: Docs_PR
displayName: Docs PR
dependsOn: Prebuild
condition: and(succeeded(), eq(dependencies.Prebuild.outputs['docs.run'], 'true'))

pool:
vmImage: ubuntu-22.04

steps:
- template: ./docs-steps.yml


- job: macOS_PR_Tests
displayName: macOS PR Tests
dependsOn: Prebuild
Expand Down
12 changes: 0 additions & 12 deletions .azure-pipelines/prebuild-checks.yml
Expand Up @@ -11,18 +11,6 @@ steps:
displayName: Fetch comparison tree
condition: and(succeeded(), variables['System.PullRequest.TargetBranch'])

- script: |
if ! git diff --name-only $(diffTarget) | grep -qE '(\.rst$|^Doc|^Misc)'
then
echo "No docs were updated: docs.run=false"
echo "##vso[task.setvariable variable=run;isOutput=true]false"
else
echo "Docs were updated: docs.run=true"
echo "##vso[task.setvariable variable=run;isOutput=true]true"
fi
displayName: Detect documentation changes
name: docs

- script: |
if ! git diff --name-only $(diffTarget) | grep -qvE '(\.rst$|^Doc|^Misc)'
then
Expand Down
10 changes: 5 additions & 5 deletions Doc/extending/newtypes.rst
Expand Up @@ -168,7 +168,7 @@ representation of the instance for which it is called. Here is a simple
example::

static PyObject *
newdatatype_repr(newdatatypeobject * obj)
newdatatype_repr(newdatatypeobject *obj)
{
return PyUnicode_FromFormat("Repr-ified_newdatatype{{size:%d}}",
obj->obj_UnderlyingDatatypePtr->size);
Expand All @@ -188,7 +188,7 @@ used instead.
Here is a simple example::

static PyObject *
newdatatype_str(newdatatypeobject * obj)
newdatatype_str(newdatatypeobject *obj)
{
return PyUnicode_FromFormat("Stringified_newdatatype{{size:%d}}",
obj->obj_UnderlyingDatatypePtr->size);
Expand Down Expand Up @@ -338,7 +338,7 @@ Here is an example::

PyErr_Format(PyExc_AttributeError,
"'%.100s' object has no attribute '%.400s'",
tp->tp_name, name);
Py_TYPE(obj)->tp_name, name);
return NULL;
}

Expand Down Expand Up @@ -379,7 +379,7 @@ Here is a sample implementation, for a datatype that is considered equal if the
size of an internal pointer is equal::

static PyObject *
newdatatype_richcmp(PyObject *obj1, PyObject *obj2, int op)
newdatatype_richcmp(newdatatypeobject *obj1, newdatatypeobject *obj2, int op)
{
PyObject *result;
int c, size1, size2;
Expand Down Expand Up @@ -478,7 +478,7 @@ This function takes three arguments:
Here is a toy ``tp_call`` implementation::

static PyObject *
newdatatype_call(newdatatypeobject *self, PyObject *args, PyObject *kwds)
newdatatype_call(newdatatypeobject *obj, PyObject *args, PyObject *kwds)
{
PyObject *result;
const char *arg1;
Expand Down
4 changes: 2 additions & 2 deletions Doc/faq/general.rst
Expand Up @@ -135,7 +135,7 @@ Python versions are numbered "A.B.C" or "A.B":

See :pep:`6` for more information about bugfix releases.

Not all releases are bugfix releases. In the run-up to a new major release, a
Not all releases are bugfix releases. In the run-up to a new minor release, a
series of development releases are made, denoted as alpha, beta, or release
candidate. Alphas are early releases in which interfaces aren't yet finalized;
it's not unexpected to see an interface change between two alpha releases.
Expand Down Expand Up @@ -297,7 +297,7 @@ How stable is Python?

Very stable. New, stable releases have been coming out roughly every 6 to 18
months since 1991, and this seems likely to continue. As of version 3.9,
Python will have a major new release every 12 months (:pep:`602`).
Python will have a minor new release every 12 months (:pep:`602`).

The developers issue "bugfix" releases of older versions, so the stability of
existing releases gradually improves. Bugfix releases, indicated by a third
Expand Down
2 changes: 1 addition & 1 deletion Doc/install/index.rst
Expand Up @@ -696,7 +696,7 @@ is supplied to suppress this behaviour. So you could simply edit
import sys
sys.path.append('/www/python/')
However, if you reinstall the same major version of Python (perhaps when
However, if you reinstall the same minor version of Python (perhaps when
upgrading from 2.2 to 2.2.2, for example) :file:`site.py` will be overwritten by
the stock version. You'd have to remember that it was modified and save a copy
before doing the installation.
Expand Down
7 changes: 5 additions & 2 deletions Doc/library/dis.rst
Expand Up @@ -1431,12 +1431,15 @@ iterations of the loop.
* ``0x02`` a dictionary of keyword-only parameters' default values
* ``0x04`` a tuple of strings containing parameters' annotations
* ``0x08`` a tuple containing cells for free variables, making a closure
* the code associated with the function (at ``STACK[-2]``)
* the :term:`qualified name` of the function (at ``STACK[-1]``)
* the code associated with the function (at ``STACK[-1]``)

.. versionchanged:: 3.10
Flag value ``0x04`` is a tuple of strings instead of dictionary

.. versionchanged:: 3.11
Qualified name at ``STACK[-1]`` was removed.


.. opcode:: BUILD_SLICE (argc)

.. index:: pair: built-in function; slice
Expand Down
6 changes: 4 additions & 2 deletions Lib/ast.py
Expand Up @@ -1051,7 +1051,8 @@ def visit_ClassDef(self, node):
self.fill("@")
self.traverse(deco)
self.fill("class " + node.name)
self._type_params_helper(node.type_params)
if hasattr(node, "type_params"):
self._type_params_helper(node.type_params)
with self.delimit_if("(", ")", condition = node.bases or node.keywords):
comma = False
for e in node.bases:
Expand Down Expand Up @@ -1083,7 +1084,8 @@ def _function_helper(self, node, fill_suffix):
self.traverse(deco)
def_str = fill_suffix + " " + node.name
self.fill(def_str)
self._type_params_helper(node.type_params)
if hasattr(node, "type_params"):
self._type_params_helper(node.type_params)
with self.delimit("(", ")"):
self.traverse(node.args)
if node.returns:
Expand Down
26 changes: 25 additions & 1 deletion Lib/pdb.py
Expand Up @@ -76,6 +76,7 @@
import dis
import code
import glob
import codeop
import pprint
import signal
import inspect
Expand Down Expand Up @@ -444,7 +445,30 @@ def default(self, line):
locals = self.curframe_locals
globals = self.curframe.f_globals
try:
code = compile(line + '\n', '<stdin>', 'single')
if (code := codeop.compile_command(line + '\n', '<stdin>', 'single')) is None:
# Multi-line mode
buffer = line
continue_prompt = "... "
while (code := codeop.compile_command(buffer, '<stdin>', 'single')) is None:
if self.use_rawinput:
try:
line = input(continue_prompt)
except (EOFError, KeyboardInterrupt):
self.lastcmd = ""
print('\n')
return
else:
self.stdout.write(continue_prompt)
self.stdout.flush()
line = self.stdin.readline()
if not len(line):
self.lastcmd = ""
self.stdout.write('\n')
self.stdout.flush()
return
else:
line = line.rstrip('\r\n')
buffer += '\n' + line
save_stdout = sys.stdout
save_stdin = sys.stdin
save_displayhook = sys.displayhook
Expand Down
27 changes: 27 additions & 0 deletions Lib/test/test_ast.py
Expand Up @@ -3,6 +3,7 @@
import dis
import enum
import os
import re
import sys
import textwrap
import types
Expand Down Expand Up @@ -1110,6 +1111,32 @@ def test_null_bytes(self):
msg="source code string cannot contain null bytes"):
ast.parse("a\0b")

def assert_none_check(self, node: type[ast.AST], attr: str, source: str) -> None:
with self.subTest(f"{node.__name__}.{attr}"):
tree = ast.parse(source)
found = 0
for child in ast.walk(tree):
if isinstance(child, node):
setattr(child, attr, None)
found += 1
self.assertEqual(found, 1)
e = re.escape(f"field '{attr}' is required for {node.__name__}")
with self.assertRaisesRegex(ValueError, f"^{e}$"):
compile(tree, "<test>", "exec")

def test_none_checks(self) -> None:
tests = [
(ast.alias, "name", "import spam as SPAM"),
(ast.arg, "arg", "def spam(SPAM): spam"),
(ast.comprehension, "target", "[spam for SPAM in spam]"),
(ast.comprehension, "iter", "[spam for spam in SPAM]"),
(ast.keyword, "value", "spam(**SPAM)"),
(ast.match_case, "pattern", "match spam:\n case SPAM: spam"),
(ast.withitem, "context_expr", "with SPAM: spam"),
]
for node, attr, source in tests:
self.assert_none_check(node, attr, source)

class ASTHelpers_Test(unittest.TestCase):
maxDiff = None

Expand Down
33 changes: 30 additions & 3 deletions Lib/test/test_pdb.py
Expand Up @@ -389,7 +389,7 @@ def test_pdb_breakpoints_preserved_across_interactive_sessions():
1 breakpoint keep yes at ...test_pdb.py:...
2 breakpoint keep yes at ...test_pdb.py:...
(Pdb) break pdb.find_function
Breakpoint 3 at ...pdb.py:97
Breakpoint 3 at ...pdb.py:...
(Pdb) break
Num Type Disp Enb Where
1 breakpoint keep yes at ...test_pdb.py:...
Expand Down Expand Up @@ -1589,6 +1589,32 @@ def test_pdb_next_command_subiterator():
(Pdb) continue
"""

def test_pdb_multiline_statement():
"""Test for multiline statement
>>> def test_function():
... import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace()
... pass
>>> with PdbTestInput([ # doctest: +NORMALIZE_WHITESPACE
... 'def f(x):',
... ' return x * 2',
... '',
... 'f(2)',
... 'c'
... ]):
... test_function()
> <doctest test.test_pdb.test_pdb_multiline_statement[0]>(3)test_function()
-> pass
(Pdb) def f(x):
... return x * 2
...
(Pdb) f(2)
4
(Pdb) c
"""


def test_pdb_issue_20766():
"""Test for reference leaks when the SIGINT handler is set.
Expand Down Expand Up @@ -2362,7 +2388,7 @@ def test_relative_imports_on_plain_module(self):

def test_errors_in_command(self):
commands = "\n".join([
'print(',
'print(]',
'debug print(',
'debug doesnotexist',
'c',
Expand All @@ -2371,7 +2397,8 @@ def test_errors_in_command(self):

self.assertEqual(stdout.splitlines()[1:], [
'-> pass',
'(Pdb) *** SyntaxError: \'(\' was never closed',
"(Pdb) *** SyntaxError: closing parenthesis ']' does not match opening "
"parenthesis '('",

'(Pdb) ENTERING RECURSIVE DEBUGGER',
'*** SyntaxError: \'(\' was never closed',
Expand Down

0 comments on commit b096651

Please sign in to comment.