Skip to content
Merged
2 changes: 0 additions & 2 deletions Lib/test/test_enum.py
Original file line number Diff line number Diff line change
Expand Up @@ -529,8 +529,6 @@ def test_format_enum_date(self):
self.assertFormatIsValue('{:%Y %m}', Holiday.IDES_OF_MARCH)
self.assertFormatIsValue('{:%Y %m %M:00}', Holiday.IDES_OF_MARCH)

# TODO: RUSTPYTHON
@unittest.expectedFailure
def test_format_enum_float(self):
Konstants = self.Konstants
self.assertFormatIsValue('{}', Konstants.TAU)
Expand Down
2 changes: 0 additions & 2 deletions Lib/test/test_format.py
Original file line number Diff line number Diff line change
Expand Up @@ -420,8 +420,6 @@ def test_non_ascii(self):
self.assertEqual(format(1+2j, "\u2007^8"), "\u2007(1+2j)\u2007")
self.assertEqual(format(0j, "\u2007^4"), "\u20070j\u2007")

# TODO: RUSTPYTHON
@unittest.expectedFailure
def test_locale(self):
try:
oldloc = locale.setlocale(locale.LC_ALL)
Expand Down
25 changes: 15 additions & 10 deletions common/src/format.rs
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ pub enum FormatType {
Character,
Decimal,
Octal,
Number,
Number(Case),
Hex(Case),
Exponent(Case),
GeneralFormat(Case),
Expand All @@ -142,7 +142,8 @@ impl From<&FormatType> for char {
FormatType::Character => 'c',
FormatType::Decimal => 'd',
FormatType::Octal => 'o',
FormatType::Number => 'n',
FormatType::Number(Case::Lower) => 'n',
FormatType::Number(Case::Upper) => 'N',
FormatType::Hex(Case::Lower) => 'x',
FormatType::Hex(Case::Upper) => 'X',
FormatType::Exponent(Case::Lower) => 'e',
Expand All @@ -165,7 +166,8 @@ impl FormatParse for FormatType {
Some('c') => (Some(Self::Character), chars.as_str()),
Some('d') => (Some(Self::Decimal), chars.as_str()),
Some('o') => (Some(Self::Octal), chars.as_str()),
Some('n') => (Some(Self::Number), chars.as_str()),
Some('n') => (Some(Self::Number(Case::Lower)), chars.as_str()),
Some('N') => (Some(Self::Number(Case::Upper)), chars.as_str()),
Some('x') => (Some(Self::Hex(Case::Lower)), chars.as_str()),
Some('X') => (Some(Self::Hex(Case::Upper)), chars.as_str()),
Some('e') => (Some(Self::Exponent(Case::Lower)), chars.as_str()),
Expand Down Expand Up @@ -367,14 +369,14 @@ impl FormatSpec {
| FormatType::Binary
| FormatType::Octal
| FormatType::Hex(_)
| FormatType::Number,
| FormatType::Number(_),
) => {
let ch = char::from(format_type);
Err(FormatSpecError::UnspecifiedFormat(',', ch))
}
(
Some(FormatGrouping::Underscore),
FormatType::String | FormatType::Character | FormatType::Number,
FormatType::String | FormatType::Character | FormatType::Number(_),
) => {
let ch = char::from(format_type);
Err(FormatSpecError::UnspecifiedFormat('_', ch))
Expand All @@ -386,7 +388,7 @@ impl FormatSpec {
fn get_separator_interval(&self) -> usize {
match self.format_type {
Some(FormatType::Binary | FormatType::Octal | FormatType::Hex(_)) => 4,
Some(FormatType::Decimal | FormatType::Number | FormatType::FixedPoint(_)) => 3,
Some(FormatType::Decimal | FormatType::Number(_) | FormatType::FixedPoint(_)) => 3,
None => 3,
_ => panic!("Separators only valid for numbers!"),
}
Expand Down Expand Up @@ -430,12 +432,12 @@ impl FormatSpec {
| Some(FormatType::Octal)
| Some(FormatType::Hex(_))
| Some(FormatType::String)
| Some(FormatType::Character) => {
| Some(FormatType::Character)
| Some(FormatType::Number(Case::Upper)) => {
let ch = char::from(self.format_type.as_ref().unwrap());
Err(FormatSpecError::UnknownFormatCode(ch, "float"))
}
Some(FormatType::Number) => Err(FormatSpecError::NotImplemented('n', "float")),
Some(FormatType::GeneralFormat(case)) => {
Some(FormatType::GeneralFormat(case)) | Some(FormatType::Number(case)) => {
let precision = if precision == 0 { 1 } else { precision };
Ok(float_ops::format_general(
precision,
Expand Down Expand Up @@ -531,7 +533,10 @@ impl FormatSpec {
Ok(result)
}
},
Some(FormatType::Number) => self.format_int_radix(magnitude, 10),
Some(FormatType::Number(Case::Lower)) => self.format_int_radix(magnitude, 10),
Some(FormatType::Number(Case::Upper)) => {
Err(FormatSpecError::UnknownFormatCode('N', "int"))
}
Some(FormatType::String) => Err(FormatSpecError::UnknownFormatCode('s', "int")),
Some(FormatType::Character) => match (self.sign, self.alternate_form) {
(Some(_), _) => Err(FormatSpecError::NotAllowed("Sign")),
Expand Down
29 changes: 29 additions & 0 deletions extra_tests/snippets/builtin_str.py
Original file line number Diff line number Diff line change
Expand Up @@ -611,6 +611,35 @@ def try_mutate_str():
assert '{:g}'.format(1.020e-13) == '1.02e-13'
assert "{:g}".format(1.020e-4) == '0.000102'

# Test n & N formatting
assert '{:n}'.format(999999.1234) == '999999'
assert '{:n}'.format(9999.1234) == '9999.12'
assert '{:n}'.format(-1000000.1234) == '-1e+06'
assert '{:n}'.format(1000000.1234) == '1e+06'
assert '{:.1n}'.format(1000000.1234) == '1e+06'
assert '{:.2n}'.format(1000000.1234) == '1e+06'
assert '{:.3n}'.format(1000000.1234) == '1e+06'
assert '{:.4n}'.format(1000000.1234) == '1e+06'
assert '{:.5n}'.format(1000000.1234) == '1e+06'
assert '{:.6n}'.format(1000000.1234) == '1e+06'
assert '{:.7n}'.format(1000000.1234) == '1000000'
assert '{:.8n}'.format(1000000.1234) == '1000000.1'
assert '{:.10n}'.format(1000000.1234) == '1000000.123'
assert '{:.11n}'.format(1000000.1234) == '1000000.1234'
assert '{:.11n}'.format(-1000000.1234) == '-1000000.1234'
assert '{:0n}'.format(-1000000.1234) == '-1e+06'
assert '{:n}'.format(-1000000.1234) == '-1e+06'
assert '{:-1n}'.format(-1000000.1234) == '-1e+06'

with AssertRaises(ValueError, msg="Unknown format code 'N' for object of type 'float'"):
'{:N}'.format(999999.1234)
with AssertRaises(ValueError, msg="Unknown format code 'N' for object of type 'float'"):
'{:.1N}'.format(1000000.1234)
with AssertRaises(ValueError, msg="Unknown format code 'N' for object of type 'float'"):
'{:0N}'.format(-1000000.1234)
with AssertRaises(ValueError, msg="Unknown format code 'N' for object of type 'float'"):
'{:-1N}'.format(-1000000.1234)

# remove*fix test
def test_removeprefix():
s = 'foobarfoo'
Expand Down