Skip to content

Commit c85f899

Browse files
authored
Fix separated format (RustPython#4397)
1 parent 80a8d37 commit c85f899

File tree

3 files changed

+87
-42
lines changed

3 files changed

+87
-42
lines changed

Lib/test/test_ipaddress.py

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -195,8 +195,6 @@ def test_invalid_scope_id_with_percent(self):
195195
class AddressTestCase_v4(BaseTestCase, CommonTestMixin_v4):
196196
factory = ipaddress.IPv4Address
197197

198-
# TODO: RUSTPYTHON
199-
@unittest.expectedFailure
200198
def test_format(self):
201199
v4 = ipaddress.IPv4Address("1.2.3.42")
202200
v4_pairs = [
@@ -309,8 +307,6 @@ def test_weakref(self):
309307
class AddressTestCase_v6(BaseTestCase, CommonTestMixin_v6):
310308
factory = ipaddress.IPv6Address
311309

312-
# TODO: RUSTPYTHON
313-
@unittest.expectedFailure
314310
def test_format(self):
315311

316312
v6 = ipaddress.IPv6Address("::1.2.3.42")

extra_tests/snippets/builtin_format.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,3 +43,24 @@ def test_zero_padding():
4343
assert f"{512:0>+#10x}" == "0000+0x200"
4444
assert f"{512:0^+#10x}" == "00+0x20000"
4545
assert f"{512:0<+#10x}" == "+0x2000000"
46+
assert f"{123:,}" == "123"
47+
assert f"{1234:,}" == "1,234"
48+
assert f"{12345:,}" == "12,345"
49+
assert f"{123456:,}" == "123,456"
50+
assert f"{123:03_}" == "123"
51+
assert f"{123:04_}" == "0_123"
52+
assert f"{123:05_}" == "0_123"
53+
assert f"{123:06_}" == "00_123"
54+
assert f"{123:07_}" == "000_123"
55+
assert f"{255:#010_x}" == "0x000_00ff"
56+
assert f"{255:+#010_x}" == "+0x00_00ff"
57+
assert f"{123.4567:,}" == "123.4567"
58+
assert f"{1234.567:,}" == "1,234.567"
59+
assert f"{12345.67:,}" == "12,345.67"
60+
assert f"{123456.7:,}" == "123,456.7"
61+
assert f"{123.456:07,}" == "123.456"
62+
assert f"{123.456:08,}" == "0,123.456"
63+
assert f"{123.456:09,}" == "0,123.456"
64+
assert f"{123.456:010,}" == "00,123.456"
65+
assert f"{123.456:011,}" == "000,123.456"
66+
assert f"{123.456:+011,}" == "+00,123.456"

vm/src/format.rs

Lines changed: 66 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -292,30 +292,54 @@ impl FormatSpec {
292292
}
293293

294294
fn add_magnitude_separators_for_char(
295-
magnitude_string: String,
296-
interval: usize,
297-
separator: char,
295+
magnitude_str: String,
296+
inter: i32,
297+
sep: char,
298+
disp_digit_cnt: i32,
298299
) -> String {
299-
let mut result = String::new();
300-
301300
// Don't add separators to the floating decimal point of numbers
302-
let mut parts = magnitude_string.splitn(2, '.');
303-
let magnitude_integer_string = parts.next().unwrap();
304-
let mut remaining: usize = magnitude_integer_string.len();
305-
for c in magnitude_integer_string.chars() {
306-
result.push(c);
307-
remaining -= 1;
308-
if remaining % interval == 0 && remaining > 0 {
309-
result.push(separator);
310-
}
311-
}
301+
let mut parts = magnitude_str.splitn(2, '.');
302+
let magnitude_int_str = parts.next().unwrap().to_string();
303+
let dec_digit_cnt = magnitude_str.len() as i32 - magnitude_int_str.len() as i32;
304+
let int_digit_cnt = disp_digit_cnt - dec_digit_cnt;
305+
let mut result = FormatSpec::separate_integer(magnitude_int_str, inter, sep, int_digit_cnt);
312306
if let Some(part) = parts.next() {
313-
result.push('.');
314-
result.push_str(part);
307+
result.push_str(&format!(".{}", part))
315308
}
316309
result
317310
}
318311

312+
fn separate_integer(
313+
magnitude_str: String,
314+
inter: i32,
315+
sep: char,
316+
disp_digit_cnt: i32,
317+
) -> String {
318+
let magnitude_len = magnitude_str.len() as i32;
319+
let offset = (disp_digit_cnt % (inter + 1) == 0) as i32;
320+
let disp_digit_cnt = disp_digit_cnt + offset;
321+
let pad_cnt = disp_digit_cnt - magnitude_len;
322+
if pad_cnt > 0 {
323+
// separate with 0 padding
324+
let sep_cnt = disp_digit_cnt / (inter + 1);
325+
let padding = "0".repeat((pad_cnt - sep_cnt) as usize);
326+
let padded_num = format!("{}{}", padding, magnitude_str);
327+
FormatSpec::insert_separator(padded_num, inter, sep, sep_cnt)
328+
} else {
329+
// separate without padding
330+
let sep_cnt = (magnitude_len - 1) / inter;
331+
FormatSpec::insert_separator(magnitude_str, inter, sep, sep_cnt)
332+
}
333+
}
334+
335+
fn insert_separator(mut magnitude_str: String, inter: i32, sep: char, sep_cnt: i32) -> String {
336+
let magnitude_len = magnitude_str.len() as i32;
337+
for i in 1..sep_cnt + 1 {
338+
magnitude_str.insert((magnitude_len - inter * i) as usize, sep);
339+
}
340+
magnitude_str
341+
}
342+
319343
fn get_separator_interval(&self) -> usize {
320344
match self.format_type {
321345
Some(FormatType::Binary) => 4,
@@ -330,26 +354,32 @@ impl FormatSpec {
330354
}
331355
}
332356

333-
fn add_magnitude_separators(&self, magnitude_string: String) -> String {
334-
match self.grouping_option {
335-
Some(FormatGrouping::Comma) => FormatSpec::add_magnitude_separators_for_char(
336-
magnitude_string,
337-
self.get_separator_interval(),
338-
',',
339-
),
340-
Some(FormatGrouping::Underscore) => FormatSpec::add_magnitude_separators_for_char(
341-
magnitude_string,
342-
self.get_separator_interval(),
343-
'_',
344-
),
345-
None => magnitude_string,
357+
fn add_magnitude_separators(&self, magnitude_str: String, prefix: &str) -> String {
358+
match &self.grouping_option {
359+
Some(fg) => {
360+
let sep = match fg {
361+
FormatGrouping::Comma => ',',
362+
FormatGrouping::Underscore => '_',
363+
};
364+
let inter = self.get_separator_interval().try_into().unwrap();
365+
let magnitude_len = magnitude_str.len();
366+
let width = self.width.unwrap_or(magnitude_len) as i32 - prefix.len() as i32;
367+
let disp_digit_cnt = cmp::max(width, magnitude_len as i32);
368+
FormatSpec::add_magnitude_separators_for_char(
369+
magnitude_str,
370+
inter,
371+
sep,
372+
disp_digit_cnt,
373+
)
374+
}
375+
None => magnitude_str,
346376
}
347377
}
348378

349379
pub(crate) fn format_float(&self, num: f64) -> Result<String, &'static str> {
350380
let precision = self.precision.unwrap_or(6);
351381
let magnitude = num.abs();
352-
let raw_magnitude_string_result: Result<String, &'static str> = match self.format_type {
382+
let raw_magnitude_str: Result<String, &'static str> = match self.format_type {
353383
Some(FormatType::FixedPointUpper) => Ok(float_ops::format_fixed(
354384
precision,
355385
magnitude,
@@ -425,8 +455,6 @@ impl FormatSpec {
425455
},
426456
},
427457
};
428-
429-
let magnitude_string = self.add_magnitude_separators(raw_magnitude_string_result?);
430458
let format_sign = self.sign.unwrap_or(FormatSign::Minus);
431459
let sign_str = if num.is_sign_negative() && !num.is_nan() {
432460
"-"
@@ -437,8 +465,8 @@ impl FormatSpec {
437465
FormatSign::MinusOrSpace => " ",
438466
}
439467
};
440-
441-
self.format_sign_and_align(&magnitude_string, sign_str, FormatAlign::Right)
468+
let magnitude_str = self.add_magnitude_separators(raw_magnitude_str?, sign_str);
469+
self.format_sign_and_align(&magnitude_str, sign_str, FormatAlign::Right)
442470
}
443471

444472
#[inline]
@@ -462,7 +490,7 @@ impl FormatSpec {
462490
} else {
463491
""
464492
};
465-
let raw_magnitude_string_result: Result<String, &'static str> = match self.format_type {
493+
let raw_magnitude_str: Result<String, &'static str> = match self.format_type {
466494
Some(FormatType::Binary) => self.format_int_radix(magnitude, 2),
467495
Some(FormatType::Decimal) => self.format_int_radix(magnitude, 10),
468496
Some(FormatType::Octal) => self.format_int_radix(magnitude, 8),
@@ -504,7 +532,6 @@ impl FormatSpec {
504532
},
505533
None => self.format_int_radix(magnitude, 10),
506534
};
507-
let magnitude_string = self.add_magnitude_separators(raw_magnitude_string_result?);
508535
let format_sign = self.sign.unwrap_or(FormatSign::Minus);
509536
let sign_str = match num.sign() {
510537
Sign::Minus => "-",
@@ -515,7 +542,8 @@ impl FormatSpec {
515542
},
516543
};
517544
let sign_prefix = format!("{}{}", sign_str, prefix);
518-
self.format_sign_and_align(&magnitude_string, &sign_prefix, FormatAlign::Right)
545+
let magnitude_str = self.add_magnitude_separators(raw_magnitude_str?, &sign_prefix);
546+
self.format_sign_and_align(&magnitude_str, &sign_prefix, FormatAlign::Right)
519547
}
520548

521549
pub(crate) fn format_string(&self, s: &str) -> Result<String, &'static str> {

0 commit comments

Comments
 (0)