-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Add support for indexing and attribute access inside format strings #2053
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add support for indexing and attribute access inside format strings #2053
Conversation
vm/src/format.rs
Outdated
fn parse_part( | ||
chars: &mut impl PeekingNext<Item = char>, | ||
) -> Result<FieldNamePart, FormatParseError> { | ||
let ch = chars.next().unwrap(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Adding comment about safety guarantee from outside will be great
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I managed to avoid the need for this unwrap
here by changing the return type to Result<Option<FieldNamePart>, FormatParseError>
, which also made the use of this function more idiomatic.
vm/src/format.rs
Outdated
if ch == '.' { | ||
let mut attribute = String::new(); | ||
for ch in chars.peeking_take_while(|ch| *ch != '.' && *ch != '[') { | ||
attribute.push(ch); | ||
} | ||
if attribute.is_empty() { | ||
Err(FormatParseError::EmptyAttribute) | ||
} else { | ||
Ok(FieldNamePart::Attribute(attribute)) | ||
} | ||
} else if ch == '[' { | ||
let mut index = String::new(); | ||
for ch in chars { | ||
if ch == ']' { | ||
return if index.is_empty() { | ||
Err(FormatParseError::EmptyAttribute) | ||
} else if let Ok(index) = index.parse::<usize>() { | ||
Ok(FieldNamePart::Index(index)) | ||
} else { | ||
Ok(FieldNamePart::StringIndex(index)) | ||
}; | ||
} | ||
index.push(ch); | ||
} | ||
Err(FormatParseError::MissingRightBracket) | ||
} else { | ||
Err(FormatParseError::InvalidCharacterAfterRightBracket) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using match would be better to avoid chaining ch comparision.
match ch {
...
}
Let me know if this is a straight-forward port of CPython if chaining implementation. In that case, we'd better to keep CPython related form.
vm/src/format.rs
Outdated
pub(crate) field_type: FieldType, | ||
pub(crate) parts: Vec<FieldNamePart>, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
pub(crate) field_type: FieldType, | |
pub(crate) parts: Vec<FieldNamePart>, | |
pub field_type: FieldType, | |
pub parts: Vec<FieldNamePart>, |
The fields are always pub(crate)
due to the struct visibility
vm/src/format.rs
Outdated
#[derive(Debug, PartialEq)] | ||
pub(crate) struct FormatString { | ||
format_parts: Vec<FormatPart>, | ||
pub(crate) format_parts: Vec<FormatPart>, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
pub(crate) format_parts: Vec<FormatPart>, | |
pub format_parts: Vec<FormatPart>, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This PR is full of nice works. This version of format/format_map looks a lot better than before.
argument = vm.get_attribute(argument, attribute.as_str())?; | ||
} | ||
FieldNamePart::Index(index) => { | ||
// TODO Implement DictKey for usize so we can pass index directly |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It could be done without DictKey once #2035 is merged.
impl FromIterator<PyObjectRef> for PyList { | ||
fn from_iter<T: IntoIterator<Item = PyObjectRef>>(iter: T) -> Self { | ||
Vec::from_iter(iter).into() | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a really good idea.
a259e0f
to
928bca8
Compare
"{a.attr}".format(...)
and"{l[0]}".format(...)
string.Formatter
For #1983