Skip to content

Commit

Permalink
Merge branch 'main' into pythongh-100479-add-makepath
Browse files Browse the repository at this point in the history
  • Loading branch information
barneygale authored Apr 13, 2023
2 parents e75dedc + 4307fea commit 5a6bd3f
Show file tree
Hide file tree
Showing 29 changed files with 272 additions and 1,812 deletions.
3 changes: 3 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ Lib/test/test_importlib/resources/data01/* noeol
Lib/test/test_importlib/resources/namespacedata01/* noeol
Lib/test/xmltestdata/* noeol

# Shell scripts should have LF even on Windows because of Cygwin
Lib/venv/scripts/common/activate text eol=lf

# CRLF files
[attr]dos text eol=crlf

Expand Down
6 changes: 1 addition & 5 deletions .github/CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
Expand Up @@ -61,11 +61,7 @@ Python/traceback.c @iritkatriel
/Tools/build/parse_html5_entities.py @ezio-melotti

# Import (including importlib).
# Ignoring importlib.h so as to not get flagged on
# all pull requests that change the emitted
# bytecode.
**/*import*.c @brettcannon @encukou @ericsnowcurrently @ncoghlan @warsaw
**/*import*.py @brettcannon @encukou @ericsnowcurrently @ncoghlan @warsaw
**/*import* @brettcannon @encukou @ericsnowcurrently @ncoghlan @warsaw
**/*importlib/resources/* @jaraco @warsaw @FFY00
**/importlib/metadata/* @jaraco @warsaw

Expand Down
22 changes: 20 additions & 2 deletions Doc/library/csv.rst
Original file line number Diff line number Diff line change
Expand Up @@ -327,7 +327,7 @@ The :mod:`csv` module defines the following constants:

Instructs :class:`writer` objects to quote all non-numeric fields.

Instructs the reader to convert all non-quoted fields to type *float*.
Instructs :class:`reader` objects to convert all non-quoted fields to type *float*.


.. data:: QUOTE_NONE
Expand All @@ -337,7 +337,25 @@ The :mod:`csv` module defines the following constants:
character. If *escapechar* is not set, the writer will raise :exc:`Error` if
any characters that require escaping are encountered.

Instructs :class:`reader` to perform no special processing of quote characters.
Instructs :class:`reader` objects to perform no special processing of quote characters.

.. data:: QUOTE_NOTNULL

Instructs :class:`writer` objects to quote all fields which are not
``None``. This is similar to :data:`QUOTE_ALL`, except that if a
field value is ``None`` an empty (unquoted) string is written.

Instructs :class:`reader` objects to interpret an empty (unquoted) field as None and
to otherwise behave as :data:`QUOTE_ALL`.

.. data:: QUOTE_STRINGS

Instructs :class:`writer` objects to always place quotes around fields
which are strings. This is similar to :data:`QUOTE_NONNUMERIC`, except that if a
field value is ``None`` an empty (unquoted) string is written.

Instructs :class:`reader` objects to interpret an empty (unquoted) string as ``None`` and
to otherwise behave as :data:`QUOTE_NONNUMERIC`.

The :mod:`csv` module defines the following exception:

Expand Down
7 changes: 7 additions & 0 deletions Doc/whatsnew/3.12.rst
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,13 @@ asyncio
* :func:`asyncio.wait` now accepts generators yielding tasks.
(Contributed by Kumar Aditya in :gh:`78530`.)

csv
---

* Add :data:`~csv.QUOTE_NOTNULL` and :data:`~csv.QUOTE_STRINGS` flags to
provide finer grained control of ``None`` and empty strings by
:class:`~csv.reader` and :class:`~csv.writer` objects.

inspect
-------

Expand Down
3 changes: 3 additions & 0 deletions Lib/asyncio/selector_events.py
Original file line number Diff line number Diff line change
Expand Up @@ -1176,6 +1176,9 @@ def writelines(self, list_of_data):
return
self._buffer.extend([memoryview(data) for data in list_of_data])
self._write_ready()
# If the entire buffer couldn't be written, register a write handler
if self._buffer:
self._loop._add_writer(self._sock_fd, self._write_ready)

def can_write_eof(self):
return True
Expand Down
2 changes: 2 additions & 0 deletions Lib/csv.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,14 @@
unregister_dialect, get_dialect, list_dialects, \
field_size_limit, \
QUOTE_MINIMAL, QUOTE_ALL, QUOTE_NONNUMERIC, QUOTE_NONE, \
QUOTE_STRINGS, QUOTE_NOTNULL, \
__doc__
from _csv import Dialect as _Dialect

from io import StringIO

__all__ = ["QUOTE_MINIMAL", "QUOTE_ALL", "QUOTE_NONNUMERIC", "QUOTE_NONE",
"QUOTE_STRINGS", "QUOTE_NOTNULL",
"Error", "Dialect", "__doc__", "excel", "excel_tab",
"field_size_limit", "reader", "writer",
"register_dialect", "get_dialect", "list_dialects", "Sniffer",
Expand Down
11 changes: 3 additions & 8 deletions Lib/test/setup_testcppext.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# gh-91321: Build a basic C++ test extension to check that the Python C API is
# compatible with C++ and does not emit C++ compiler warnings.
import os
import sys
from test import support

Expand All @@ -25,14 +26,8 @@

def main():
cppflags = list(CPPFLAGS)
if '-std=c++03' in sys.argv:
sys.argv.remove('-std=c++03')
std = 'c++03'
name = '_testcpp03ext'
else:
# Python currently targets C++11
std = 'c++11'
name = '_testcpp11ext'
std = os.environ["CPYTHON_TEST_CPP_STD"]
name = os.environ["CPYTHON_TEST_EXT_NAME"]

cppflags = [*CPPFLAGS, f'-std={std}']

Expand Down
Binary file added Lib/test/setuptools-67.6.1-py3-none-any.whl
Binary file not shown.
42 changes: 42 additions & 0 deletions Lib/test/test_asyncio/test_selector_events.py
Original file line number Diff line number Diff line change
Expand Up @@ -747,6 +747,48 @@ def test_write_sendmsg_no_data(self):
self.assertFalse(self.sock.sendmsg.called)
self.assertEqual(list_to_buffer([b'data']), transport._buffer)

@unittest.skipUnless(selector_events._HAS_SENDMSG, 'no sendmsg')
def test_writelines_sendmsg_full(self):
data = memoryview(b'data')
self.sock.sendmsg = mock.Mock()
self.sock.sendmsg.return_value = len(data)

transport = self.socket_transport(sendmsg=True)
transport.writelines([data])
self.assertTrue(self.sock.sendmsg.called)
self.assertFalse(self.loop.writers)

@unittest.skipUnless(selector_events._HAS_SENDMSG, 'no sendmsg')
def test_writelines_sendmsg_partial(self):
data = memoryview(b'data')
self.sock.sendmsg = mock.Mock()
self.sock.sendmsg.return_value = 2

transport = self.socket_transport(sendmsg=True)
transport.writelines([data])
self.assertTrue(self.sock.sendmsg.called)
self.assertTrue(self.loop.writers)

def test_writelines_send_full(self):
data = memoryview(b'data')
self.sock.send.return_value = len(data)
self.sock.send.fileno.return_value = 7

transport = self.socket_transport()
transport.writelines([data])
self.assertTrue(self.sock.send.called)
self.assertFalse(self.loop.writers)

def test_writelines_send_partial(self):
data = memoryview(b'data')
self.sock.send.return_value = 2
self.sock.send.fileno.return_value = 7

transport = self.socket_transport()
transport.writelines([data])
self.assertTrue(self.sock.send.called)
self.assertTrue(self.loop.writers)

@unittest.skipUnless(selector_events._HAS_SENDMSG, 'no sendmsg')
def test_write_sendmsg_full(self):
data = memoryview(b'data')
Expand Down
25 changes: 17 additions & 8 deletions Lib/test/test_cppext.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# gh-91321: Build a basic C++ test extension to check that the Python C API is
# compatible with C++ and does not emit C++ compiler warnings.
import os.path
import shutil
import sys
import unittest
import subprocess
Expand Down Expand Up @@ -39,6 +40,10 @@ def check_build(self, std_cpp03, extension_name):
self._check_build(std_cpp03, extension_name)

def _check_build(self, std_cpp03, extension_name):
pkg_dir = 'pkg'
os.mkdir(pkg_dir)
shutil.copy(SETUP_TESTCPPEXT, os.path.join(pkg_dir, "setup.py"))

venv_dir = 'env'
verbose = support.verbose

Expand All @@ -59,11 +64,15 @@ def _check_build(self, std_cpp03, extension_name):
python = os.path.join(venv_dir, 'bin', python_exe)

def run_cmd(operation, cmd):
env = os.environ.copy()
env['CPYTHON_TEST_CPP_STD'] = 'c++03' if std_cpp03 else 'c++11'
env['CPYTHON_TEST_EXT_NAME'] = extension_name
if verbose:
print('Run:', ' '.join(cmd))
subprocess.run(cmd, check=True)
subprocess.run(cmd, check=True, env=env)
else:
proc = subprocess.run(cmd,
env=env,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
text=True)
Expand All @@ -72,16 +81,16 @@ def run_cmd(operation, cmd):
self.fail(
f"{operation} failed with exit code {proc.returncode}")

# Build the C++ extension
cmd = [python, '-X', 'dev',
SETUP_TESTCPPEXT, 'build_ext', '--verbose']
if std_cpp03:
cmd.append('-std=c++03')
run_cmd('Build', cmd)
'-m', 'pip', 'install',
support.findfile('setuptools-67.6.1-py3-none-any.whl'),
support.findfile('wheel-0.40.0-py3-none-any.whl')]
run_cmd('Install build dependencies', cmd)

# Install the C++ extension
# Build and install the C++ extension
cmd = [python, '-X', 'dev',
SETUP_TESTCPPEXT, 'install']
'-m', 'pip', 'install', '--no-build-isolation',
os.path.abspath(pkg_dir)]
run_cmd('Install', cmd)

# Do a reference run. Until we test that running python
Expand Down
4 changes: 4 additions & 0 deletions Lib/test/test_csv.py
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,10 @@ def test_write_quoting(self):
quoting = csv.QUOTE_ALL)
self._write_test(['a\nb',1], '"a\nb","1"',
quoting = csv.QUOTE_ALL)
self._write_test(['a','',None,1], '"a","",,1',
quoting = csv.QUOTE_STRINGS)
self._write_test(['a','',None,1], '"a","",,"1"',
quoting = csv.QUOTE_NOTNULL)

def test_write_escape(self):
self._write_test(['a',1,'p,q'], 'a,1,"p,q"',
Expand Down
71 changes: 71 additions & 0 deletions Lib/test/test_monitoring.py
Original file line number Diff line number Diff line change
Expand Up @@ -1011,6 +1011,77 @@ def func3():
('line', 'func3', 6)])


def line_from_offset(code, offset):
for start, end, line in code.co_lines():
if start <= offset < end:
return line - code.co_firstlineno
return -1

class JumpRecorder:

event_type = E.JUMP
name = "jump"

def __init__(self, events):
self.events = events

def __call__(self, code, from_, to):
from_line = line_from_offset(code, from_)
to_line = line_from_offset(code, to)
self.events.append((self.name, code.co_name, from_line, to_line))


class BranchRecorder(JumpRecorder):

event_type = E.BRANCH
name = "branch"


JUMP_AND_BRANCH_RECORDERS = JumpRecorder, BranchRecorder
JUMP_BRANCH_AND_LINE_RECORDERS = JumpRecorder, BranchRecorder, LineRecorder

class TestBranchAndJumpEvents(CheckEvents):
maxDiff = None

def test_loop(self):

def func():
x = 1
for a in range(2):
if a:
x = 4
else:
x = 6

self.check_events(func, recorders = JUMP_AND_BRANCH_RECORDERS, expected = [
('branch', 'func', 2, 2),
('branch', 'func', 3, 6),
('jump', 'func', 6, 2),
('branch', 'func', 2, 2),
('branch', 'func', 3, 4),
('jump', 'func', 4, 2),
('branch', 'func', 2, 2)])


self.check_events(func, recorders = JUMP_BRANCH_AND_LINE_RECORDERS, expected = [
('line', 'check_events', 10),
('line', 'func', 1),
('line', 'func', 2),
('branch', 'func', 2, 2),
('line', 'func', 3),
('branch', 'func', 3, 6),
('line', 'func', 6),
('jump', 'func', 6, 2),
('branch', 'func', 2, 2),
('line', 'func', 3),
('branch', 'func', 3, 4),
('line', 'func', 4),
('jump', 'func', 4, 2),
('branch', 'func', 2, 2),
('line', 'func', 2),
('line', 'check_events', 11)])


class TestSetGetEvents(MonitoringTestBase, unittest.TestCase):

def test_global(self):
Expand Down
18 changes: 18 additions & 0 deletions Lib/test/test_unittest/testmock/testhelpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -952,6 +952,24 @@ def __getattr__(self, attribute):
self.assertFalse(hasattr(autospec, '__name__'))


def test_autospec_signature_staticmethod(self):
class Foo:
@staticmethod
def static_method(a, b=10, *, c): pass

mock = create_autospec(Foo.__dict__['static_method'])
self.assertEqual(inspect.signature(Foo.static_method), inspect.signature(mock))


def test_autospec_signature_classmethod(self):
class Foo:
@classmethod
def class_method(cls, a, b=10, *, c): pass

mock = create_autospec(Foo.__dict__['class_method'])
self.assertEqual(inspect.signature(Foo.class_method), inspect.signature(mock))


def test_spec_inspect_signature(self):

def myfunc(x, y): pass
Expand Down
30 changes: 30 additions & 0 deletions Lib/test/test_unittest/testmock/testpatch.py
Original file line number Diff line number Diff line change
Expand Up @@ -996,6 +996,36 @@ def test_autospec_classmethod(self):
method.assert_called_once_with()


def test_autospec_staticmethod_signature(self):
# Patched methods which are decorated with @staticmethod should have the same signature
class Foo:
@staticmethod
def static_method(a, b=10, *, c): pass

Foo.static_method(1, 2, c=3)

with patch.object(Foo, 'static_method', autospec=True) as method:
method(1, 2, c=3)
self.assertRaises(TypeError, method)
self.assertRaises(TypeError, method, 1)
self.assertRaises(TypeError, method, 1, 2, 3, c=4)


def test_autospec_classmethod_signature(self):
# Patched methods which are decorated with @classmethod should have the same signature
class Foo:
@classmethod
def class_method(cls, a, b=10, *, c): pass

Foo.class_method(1, 2, c=3)

with patch.object(Foo, 'class_method', autospec=True) as method:
method(1, 2, c=3)
self.assertRaises(TypeError, method)
self.assertRaises(TypeError, method, 1)
self.assertRaises(TypeError, method, 1, 2, 3, c=4)


def test_autospec_with_new(self):
patcher = patch('%s.function' % __name__, new=3, autospec=True)
self.assertRaises(TypeError, patcher.start)
Expand Down
Loading

0 comments on commit 5a6bd3f

Please sign in to comment.