Skip to content

Commit fcf6dec

Browse files
committed
Merge remote-tracking branch 'upstream/main' into bytecode-print-expr
2 parents ad2715d + 59f422d commit fcf6dec

File tree

11 files changed

+235
-143
lines changed

11 files changed

+235
-143
lines changed

Lib/test/test_io.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4217,7 +4217,6 @@ def test_basic_io(self):
42174217
def test_constructor(self):
42184218
return super().test_constructor()
42194219

4220-
@unittest.expectedFailure # TODO: RUSTPYTHON
42214220
def test_detach(self):
42224221
return super().test_detach()
42234222

Lib/test/test_print.py

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -129,14 +129,24 @@ def flush(self):
129129
raise RuntimeError
130130
self.assertRaises(RuntimeError, print, 1, file=noflush(), flush=True)
131131

132+
def test_gh130163(self):
133+
class X:
134+
def __str__(self):
135+
sys.stdout = StringIO()
136+
support.gc_collect()
137+
return 'foo'
138+
139+
with support.swap_attr(sys, 'stdout', None):
140+
sys.stdout = StringIO() # the only reference
141+
print(X()) # should not crash
142+
132143

133144
class TestPy2MigrationHint(unittest.TestCase):
134145
"""Test that correct hint is produced analogous to Python3 syntax,
135146
if print statement is executed as in Python 2.
136147
"""
137148

138-
# TODO: RUSTPYTHON
139-
@unittest.expectedFailure
149+
@unittest.expectedFailure # TODO: RUSTPYTHON
140150
def test_normal_string(self):
141151
python2_print_str = 'print "Hello World"'
142152
with self.assertRaises(SyntaxError) as context:
@@ -145,8 +155,7 @@ def test_normal_string(self):
145155
self.assertIn("Missing parentheses in call to 'print'. Did you mean print(...)",
146156
str(context.exception))
147157

148-
# TODO: RUSTPYTHON
149-
@unittest.expectedFailure
158+
@unittest.expectedFailure # TODO: RUSTPYTHON
150159
def test_string_with_soft_space(self):
151160
python2_print_str = 'print "Hello World",'
152161
with self.assertRaises(SyntaxError) as context:
@@ -155,8 +164,7 @@ def test_string_with_soft_space(self):
155164
self.assertIn("Missing parentheses in call to 'print'. Did you mean print(...)",
156165
str(context.exception))
157166

158-
# TODO: RUSTPYTHON
159-
@unittest.expectedFailure
167+
@unittest.expectedFailure # TODO: RUSTPYTHON
160168
def test_string_with_excessive_whitespace(self):
161169
python2_print_str = 'print "Hello World", '
162170
with self.assertRaises(SyntaxError) as context:
@@ -165,8 +173,7 @@ def test_string_with_excessive_whitespace(self):
165173
self.assertIn("Missing parentheses in call to 'print'. Did you mean print(...)",
166174
str(context.exception))
167175

168-
# TODO: RUSTPYTHON
169-
@unittest.expectedFailure
176+
@unittest.expectedFailure # TODO: RUSTPYTHON
170177
def test_string_with_leading_whitespace(self):
171178
python2_print_str = '''if 1:
172179
print "Hello World"
@@ -180,9 +187,7 @@ def test_string_with_leading_whitespace(self):
180187
# bpo-32685: Suggestions for print statement should be proper when
181188
# it is in the same line as the header of a compound statement
182189
# and/or followed by a semicolon
183-
184-
# TODO: RUSTPYTHON
185-
@unittest.expectedFailure
190+
@unittest.expectedFailure # TODO: RUSTPYTHON
186191
def test_string_with_semicolon(self):
187192
python2_print_str = 'print p;'
188193
with self.assertRaises(SyntaxError) as context:
@@ -191,8 +196,7 @@ def test_string_with_semicolon(self):
191196
self.assertIn("Missing parentheses in call to 'print'. Did you mean print(...)",
192197
str(context.exception))
193198

194-
# TODO: RUSTPYTHON
195-
@unittest.expectedFailure
199+
@unittest.expectedFailure # TODO: RUSTPYTHON
196200
def test_string_in_loop_on_same_line(self):
197201
python2_print_str = 'for i in s: print i'
198202
with self.assertRaises(SyntaxError) as context:
@@ -201,8 +205,7 @@ def test_string_in_loop_on_same_line(self):
201205
self.assertIn("Missing parentheses in call to 'print'. Did you mean print(...)",
202206
str(context.exception))
203207

204-
# TODO: RUSTPYTHON
205-
@unittest.expectedFailure
208+
@unittest.expectedFailure # TODO: RUSTPYTHON
206209
def test_stream_redirection_hint_for_py2_migration(self):
207210
# Test correct hint produced for Py2 redirection syntax
208211
with self.assertRaises(TypeError) as context:

Lib/test/test_tarfile.py

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -258,8 +258,6 @@ class ListTest(ReadTest, unittest.TestCase):
258258
def setUp(self):
259259
self.tar = tarfile.open(self.tarname, mode=self.mode)
260260

261-
# TODO: RUSTPYTHON
262-
@unittest.expectedFailure
263261
def test_list(self):
264262
tio = io.TextIOWrapper(io.BytesIO(), 'ascii', newline='\n')
265263
with support.swap_attr(sys, 'stdout', tio):
@@ -297,8 +295,6 @@ def conv(b):
297295
self.assertNotIn(b'link to', out)
298296
self.assertNotIn(b'->', out)
299297

300-
# TODO: RUSTPYTHON
301-
@unittest.expectedFailure
302298
def test_list_verbose(self):
303299
tio = io.TextIOWrapper(io.BytesIO(), 'ascii', newline='\n')
304300
with support.swap_attr(sys, 'stdout', tio):
@@ -323,8 +319,6 @@ def test_list_verbose(self):
323319
self.assertIn(b'pax' + (b'/123' * 125) + b'/longlink link to pax' +
324320
(b'/123' * 125) + b'/longname', out)
325321

326-
# TODO: RUSTPYTHON
327-
@unittest.expectedFailure
328322
def test_list_members(self):
329323
tio = io.TextIOWrapper(io.BytesIO(), 'ascii', newline='\n')
330324
def members(tar):

Lib/test/test_tempfile.py

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1187,8 +1187,6 @@ def test_properties(self):
11871187
with self.assertRaises(AttributeError):
11881188
f.errors
11891189

1190-
# TODO: RUSTPYTHON
1191-
@unittest.expectedFailure
11921190
def test_text_mode(self):
11931191
# Creating a SpooledTemporaryFile with a text mode should produce
11941192
# a file object reading and writing (Unicode) text strings.
@@ -1221,8 +1219,6 @@ def test_text_mode(self):
12211219
self.assertEqual(f.encoding, "utf-8")
12221220
self.assertEqual(f.errors, "strict")
12231221

1224-
# TODO: RUSTPYTHON
1225-
@unittest.expectedFailure
12261222
def test_text_newline_and_encoding(self):
12271223
f = tempfile.SpooledTemporaryFile(mode='w+', max_size=10,
12281224
newline='', encoding='utf-8',

Lib/test/test_xml_etree.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -437,7 +437,6 @@ def test_copy(self):
437437
self.serialize_check(e2, '<tag>hello<bar /></tag>')
438438
self.serialize_check(e3, '<tag>hello<foo /></tag>')
439439

440-
@unittest.expectedFailure # TODO: RUSTPYTHON
441440
def test_attrib(self):
442441
# Test attribute handling.
443442

@@ -1481,7 +1480,6 @@ def check(p, expected, namespaces=None):
14811480
{'': 'http://www.w3.org/2001/XMLSchema',
14821481
'ns': 'http://www.w3.org/2001/XMLSchema'})
14831482

1484-
@unittest.expectedFailure # TODO: RUSTPYTHON
14851483
def test_processinginstruction(self):
14861484
# Test ProcessingInstruction directly
14871485

@@ -2369,7 +2367,6 @@ def test_bug_200709_default_namespace(self):
23692367
self.assertEqual(str(cm.exception),
23702368
'cannot use non-qualified names with default_namespace option')
23712369

2372-
@unittest.expectedFailure # TODO: RUSTPYTHON
23732370
def test_bug_200709_register_namespace(self):
23742371
e = ET.Element("{http://namespace.invalid/does/not/exist/}title")
23752372
self.assertEqual(ET.tostring(e),

crates/codegen/src/compile.rs

Lines changed: 38 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,8 @@ use rustpython_compiler_core::{
3636
Mode, OneIndexed, PositionEncoding, SourceFile, SourceLocation,
3737
bytecode::{
3838
self, Arg as OpArgMarker, BinaryOperator, BuildSliceArgCount, CodeObject,
39-
ComparisonOperator, ConstantData, Instruction, Invert, OpArg, OpArgType, UnpackExArgs,
39+
ComparisonOperator, ConstantData, ConvertValueOparg, Instruction, Invert, OpArg, OpArgType,
40+
UnpackExArgs,
4041
},
4142
};
4243
use rustpython_wtf8::Wtf8Buf;
@@ -1365,20 +1366,17 @@ impl Compiler {
13651366
.collect()
13661367
};
13671368

1368-
let module_idx = module.as_ref().map(|s| self.name(s.as_str()));
1369-
13701369
// from .... import (*fromlist)
13711370
self.emit_load_const(ConstantData::Integer {
13721371
value: (*level).into(),
13731372
});
13741373
self.emit_load_const(ConstantData::Tuple {
13751374
elements: from_list,
13761375
});
1377-
if let Some(idx) = module_idx {
1378-
emit!(self, Instruction::ImportName { idx });
1379-
} else {
1380-
emit!(self, Instruction::ImportNameless);
1381-
}
1376+
1377+
let module_name = module.as_ref().map_or("", |s| s.as_str());
1378+
let module_idx = self.name(module_name);
1379+
emit!(self, Instruction::ImportName { idx: module_idx });
13821380

13831381
if import_star {
13841382
// from .... import *
@@ -5650,7 +5648,12 @@ impl Compiler {
56505648
}
56515649
}
56525650
InterpolatedStringElement::Interpolation(fstring_expr) => {
5653-
let mut conversion = fstring_expr.conversion;
5651+
let mut conversion = match fstring_expr.conversion {
5652+
ConversionFlag::None => ConvertValueOparg::None,
5653+
ConversionFlag::Str => ConvertValueOparg::Str,
5654+
ConversionFlag::Repr => ConvertValueOparg::Repr,
5655+
ConversionFlag::Ascii => ConvertValueOparg::Ascii,
5656+
};
56545657

56555658
if let Some(DebugText { leading, trailing }) = &fstring_expr.debug_text {
56565659
let range = fstring_expr.expression.range();
@@ -5659,35 +5662,39 @@ impl Compiler {
56595662

56605663
self.emit_load_const(ConstantData::Str { value: text.into() });
56615664
element_count += 1;
5665+
5666+
// Match CPython behavior: If debug text is present, apply repr conversion.
5667+
// if no `format_spec` specified.
5668+
// See: https://github.com/python/cpython/blob/f61afca262d3a0aa6a8a501db0b1936c60858e35/Parser/action_helpers.c#L1456
5669+
if matches!(
5670+
(conversion, &fstring_expr.format_spec),
5671+
(ConvertValueOparg::None, None)
5672+
) {
5673+
conversion = ConvertValueOparg::Repr;
5674+
}
56625675
}
56635676

5664-
match &fstring_expr.format_spec {
5665-
None => {
5666-
self.emit_load_const(ConstantData::Str {
5667-
value: Wtf8Buf::new(),
5668-
});
5669-
// Match CPython behavior: If debug text is present, apply repr conversion.
5670-
// See: https://github.com/python/cpython/blob/f61afca262d3a0aa6a8a501db0b1936c60858e35/Parser/action_helpers.c#L1456
5671-
if conversion == ConversionFlag::None
5672-
&& fstring_expr.debug_text.is_some()
5673-
{
5674-
conversion = ConversionFlag::Repr;
5675-
}
5677+
self.compile_expression(&fstring_expr.expression)?;
5678+
5679+
match conversion {
5680+
ConvertValueOparg::None => {}
5681+
ConvertValueOparg::Str
5682+
| ConvertValueOparg::Repr
5683+
| ConvertValueOparg::Ascii => {
5684+
emit!(self, Instruction::ConvertValue { oparg: conversion })
56765685
}
5686+
}
5687+
5688+
match &fstring_expr.format_spec {
56775689
Some(format_spec) => {
56785690
self.compile_fstring_elements(flags, &format_spec.elements)?;
5691+
5692+
emit!(self, Instruction::FormatWithSpec);
5693+
}
5694+
None => {
5695+
emit!(self, Instruction::FormatSimple);
56795696
}
56805697
}
5681-
5682-
self.compile_expression(&fstring_expr.expression)?;
5683-
5684-
let conversion = match conversion {
5685-
ConversionFlag::None => bytecode::ConversionFlag::None,
5686-
ConversionFlag::Str => bytecode::ConversionFlag::Str,
5687-
ConversionFlag::Ascii => bytecode::ConversionFlag::Ascii,
5688-
ConversionFlag::Repr => bytecode::ConversionFlag::Repr,
5689-
};
5690-
emit!(self, Instruction::FormatValue { conversion });
56915698
}
56925699
}
56935700
}

crates/codegen/src/snapshots/rustpython_codegen__compile__tests__nested_double_async_with.snap

Lines changed: 16 additions & 17 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)