Skip to content

Commit d918f7e

Browse files
authored
'n' support for float format (#4865)
1 parent cb6cf10 commit d918f7e

File tree

4 files changed

+44
-14
lines changed

4 files changed

+44
-14
lines changed

Lib/test/test_enum.py

-2
Original file line numberDiff line numberDiff line change
@@ -529,8 +529,6 @@ def test_format_enum_date(self):
529529
self.assertFormatIsValue('{:%Y %m}', Holiday.IDES_OF_MARCH)
530530
self.assertFormatIsValue('{:%Y %m %M:00}', Holiday.IDES_OF_MARCH)
531531

532-
# TODO: RUSTPYTHON
533-
@unittest.expectedFailure
534532
def test_format_enum_float(self):
535533
Konstants = self.Konstants
536534
self.assertFormatIsValue('{}', Konstants.TAU)

Lib/test/test_format.py

-2
Original file line numberDiff line numberDiff line change
@@ -420,8 +420,6 @@ def test_non_ascii(self):
420420
self.assertEqual(format(1+2j, "\u2007^8"), "\u2007(1+2j)\u2007")
421421
self.assertEqual(format(0j, "\u2007^4"), "\u20070j\u2007")
422422

423-
# TODO: RUSTPYTHON
424-
@unittest.expectedFailure
425423
def test_locale(self):
426424
try:
427425
oldloc = locale.setlocale(locale.LC_ALL)

common/src/format.rs

+15-10
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ pub enum FormatType {
126126
Character,
127127
Decimal,
128128
Octal,
129-
Number,
129+
Number(Case),
130130
Hex(Case),
131131
Exponent(Case),
132132
GeneralFormat(Case),
@@ -142,7 +142,8 @@ impl From<&FormatType> for char {
142142
FormatType::Character => 'c',
143143
FormatType::Decimal => 'd',
144144
FormatType::Octal => 'o',
145-
FormatType::Number => 'n',
145+
FormatType::Number(Case::Lower) => 'n',
146+
FormatType::Number(Case::Upper) => 'N',
146147
FormatType::Hex(Case::Lower) => 'x',
147148
FormatType::Hex(Case::Upper) => 'X',
148149
FormatType::Exponent(Case::Lower) => 'e',
@@ -165,7 +166,8 @@ impl FormatParse for FormatType {
165166
Some('c') => (Some(Self::Character), chars.as_str()),
166167
Some('d') => (Some(Self::Decimal), chars.as_str()),
167168
Some('o') => (Some(Self::Octal), chars.as_str()),
168-
Some('n') => (Some(Self::Number), chars.as_str()),
169+
Some('n') => (Some(Self::Number(Case::Lower)), chars.as_str()),
170+
Some('N') => (Some(Self::Number(Case::Upper)), chars.as_str()),
169171
Some('x') => (Some(Self::Hex(Case::Lower)), chars.as_str()),
170172
Some('X') => (Some(Self::Hex(Case::Upper)), chars.as_str()),
171173
Some('e') => (Some(Self::Exponent(Case::Lower)), chars.as_str()),
@@ -367,14 +369,14 @@ impl FormatSpec {
367369
| FormatType::Binary
368370
| FormatType::Octal
369371
| FormatType::Hex(_)
370-
| FormatType::Number,
372+
| FormatType::Number(_),
371373
) => {
372374
let ch = char::from(format_type);
373375
Err(FormatSpecError::UnspecifiedFormat(',', ch))
374376
}
375377
(
376378
Some(FormatGrouping::Underscore),
377-
FormatType::String | FormatType::Character | FormatType::Number,
379+
FormatType::String | FormatType::Character | FormatType::Number(_),
378380
) => {
379381
let ch = char::from(format_type);
380382
Err(FormatSpecError::UnspecifiedFormat('_', ch))
@@ -386,7 +388,7 @@ impl FormatSpec {
386388
fn get_separator_interval(&self) -> usize {
387389
match self.format_type {
388390
Some(FormatType::Binary | FormatType::Octal | FormatType::Hex(_)) => 4,
389-
Some(FormatType::Decimal | FormatType::Number | FormatType::FixedPoint(_)) => 3,
391+
Some(FormatType::Decimal | FormatType::Number(_) | FormatType::FixedPoint(_)) => 3,
390392
None => 3,
391393
_ => panic!("Separators only valid for numbers!"),
392394
}
@@ -430,12 +432,12 @@ impl FormatSpec {
430432
| Some(FormatType::Octal)
431433
| Some(FormatType::Hex(_))
432434
| Some(FormatType::String)
433-
| Some(FormatType::Character) => {
435+
| Some(FormatType::Character)
436+
| Some(FormatType::Number(Case::Upper)) => {
434437
let ch = char::from(self.format_type.as_ref().unwrap());
435438
Err(FormatSpecError::UnknownFormatCode(ch, "float"))
436439
}
437-
Some(FormatType::Number) => Err(FormatSpecError::NotImplemented('n', "float")),
438-
Some(FormatType::GeneralFormat(case)) => {
440+
Some(FormatType::GeneralFormat(case)) | Some(FormatType::Number(case)) => {
439441
let precision = if precision == 0 { 1 } else { precision };
440442
Ok(float_ops::format_general(
441443
precision,
@@ -531,7 +533,10 @@ impl FormatSpec {
531533
Ok(result)
532534
}
533535
},
534-
Some(FormatType::Number) => self.format_int_radix(magnitude, 10),
536+
Some(FormatType::Number(Case::Lower)) => self.format_int_radix(magnitude, 10),
537+
Some(FormatType::Number(Case::Upper)) => {
538+
Err(FormatSpecError::UnknownFormatCode('N', "int"))
539+
}
535540
Some(FormatType::String) => Err(FormatSpecError::UnknownFormatCode('s', "int")),
536541
Some(FormatType::Character) => match (self.sign, self.alternate_form) {
537542
(Some(_), _) => Err(FormatSpecError::NotAllowed("Sign")),

extra_tests/snippets/builtin_str.py

+29
Original file line numberDiff line numberDiff line change
@@ -611,6 +611,35 @@ def try_mutate_str():
611611
assert '{:g}'.format(1.020e-13) == '1.02e-13'
612612
assert "{:g}".format(1.020e-4) == '0.000102'
613613

614+
# Test n & N formatting
615+
assert '{:n}'.format(999999.1234) == '999999'
616+
assert '{:n}'.format(9999.1234) == '9999.12'
617+
assert '{:n}'.format(-1000000.1234) == '-1e+06'
618+
assert '{:n}'.format(1000000.1234) == '1e+06'
619+
assert '{:.1n}'.format(1000000.1234) == '1e+06'
620+
assert '{:.2n}'.format(1000000.1234) == '1e+06'
621+
assert '{:.3n}'.format(1000000.1234) == '1e+06'
622+
assert '{:.4n}'.format(1000000.1234) == '1e+06'
623+
assert '{:.5n}'.format(1000000.1234) == '1e+06'
624+
assert '{:.6n}'.format(1000000.1234) == '1e+06'
625+
assert '{:.7n}'.format(1000000.1234) == '1000000'
626+
assert '{:.8n}'.format(1000000.1234) == '1000000.1'
627+
assert '{:.10n}'.format(1000000.1234) == '1000000.123'
628+
assert '{:.11n}'.format(1000000.1234) == '1000000.1234'
629+
assert '{:.11n}'.format(-1000000.1234) == '-1000000.1234'
630+
assert '{:0n}'.format(-1000000.1234) == '-1e+06'
631+
assert '{:n}'.format(-1000000.1234) == '-1e+06'
632+
assert '{:-1n}'.format(-1000000.1234) == '-1e+06'
633+
634+
with AssertRaises(ValueError, msg="Unknown format code 'N' for object of type 'float'"):
635+
'{:N}'.format(999999.1234)
636+
with AssertRaises(ValueError, msg="Unknown format code 'N' for object of type 'float'"):
637+
'{:.1N}'.format(1000000.1234)
638+
with AssertRaises(ValueError, msg="Unknown format code 'N' for object of type 'float'"):
639+
'{:0N}'.format(-1000000.1234)
640+
with AssertRaises(ValueError, msg="Unknown format code 'N' for object of type 'float'"):
641+
'{:-1N}'.format(-1000000.1234)
642+
614643
# remove*fix test
615644
def test_removeprefix():
616645
s = 'foobarfoo'

0 commit comments

Comments
 (0)