Allowing `str.format` to format one or more parameters instead of all parameters
Consider the following string: x = r"\mathjax{{color}}{{text}}" string `x` contains two parameters named `color` and the other named `text`. Currently, python requires that the string class method `str.format` contain key-word arguments for *all *parameters, not just *one* parameter result = r"\mathjax{{color}}{{text}}".format(color = "blue" , text = "Spanish") result = "\mathjax{blue}{Spanish}" Can we change str.format so that it is possible to change only one string parameter, but leave the other parameters alone? # pfr is partially_formatted_result pfr = r"\mathjax{{color}}{{text}}".format(color = "blue") # ERROR! missing parameter `text` result = r"\mathjax{{color}}{{text}}".format(text = "Spanish") # ERROR! missing parameter `color` The implementation requires fewer than ten lines of code in python, probably less than fifty lines in C, or a different implementation language. class str: def format(self, **kwargs): for key in kwargs: x = "{"+key+"}" ostr = kwargs[key].join(self.split(x)) return ostr # output string As an example, everywhere a string contained `{text}` it will now say `*Spanish*` . *Samuel Muldoon* *(720) 653 -2408* *muldoonsamuel@gmail.com <muldoonsamuel@gmail.com>*
i'm all for it. it reduces the amount of code needed in day to day usage. it increases flexibility in usage. the concept doesn't seem to have a downside.
On 22/04/23 10:20 am, Samuel Muldoon wrote:
Can we change str.formatso that it is possible to change only one string parameter, but leave the other parameters alone?
That would have the effect that every use of str.format for everyone would start producing partially-formatted strings if an argument is accidentally omitted instead of raising an error. Some people might not like that. It would be better to write a separate function for doing partial formatting. -- Greg
What's the use-case for this? Have you looked into using functools.partial instead? On Sat, 22 Apr 2023, 06:23 Samuel Muldoon, <muldoonsamuel@gmail.com> wrote:
Consider the following string:
x = r"\mathjax{{color}}{{text}}"
string `x` contains two parameters named `color` and the other named `text `.
Currently, python requires that the string class method `str.format` contain key-word arguments for *all *parameters, not just *one* parameter
result = r"\mathjax{{color}}{{text}}".format(color = "blue" , text = "Spanish")
result = "\mathjax{blue}{Spanish}"
Can we change str.format so that it is possible to change only one string parameter, but leave the other parameters alone?
# pfr is partially_formatted_result
pfr = r"\mathjax{{color}}{{text}}".format(color = "blue") # ERROR! missing parameter `text`
result = r"\mathjax{{color}}{{text}}".format(text = "Spanish") # ERROR! missing parameter `color`
The implementation requires fewer than ten lines of code in python, probably less than fifty lines in C, or a different implementation language.
class str: def format(self, **kwargs): for key in kwargs: x = "{"+key+"}" ostr = kwargs[key].join(self.split(x)) return ostr # output string
As an example, everywhere a string contained `{text}` it will now say `*Spanish*` .
*Samuel Muldoon*
*(720) 653 -2408*
*muldoonsamuel@gmail.com <muldoonsamuel@gmail.com>*
_______________________________________________ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-leave@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/2A6RTX... Code of Conduct: http://python.org/psf/codeofconduct/
That would have the effect that every use of str.format for everyone would start producing partially-formatted strings if an argument is accidentally omitted instead of raising an error. Some people might not like that.
On 21/04/2023 23:20, Samuel Muldoon wrote:
# pfr is partially_formatted_result pfr =r"\mathjax{{color}}{{text}}".format(color = "blue") # ERROR! missing parameter `text` result =r"\mathjax{{color}}{{text}}".format(text = "Spanish") # ERROR! missing parameter `color`
Is there any reason you can't write pfr =r"\mathjax{{color}}{{text}}".replace("{color}", "blue") result =r"\mathjax{{color}}{{text}}".replace("{text}", "Spanish") Best wishes Rob Cliffe
On Sat, Apr 22, 2023 at 10:06 AM Damian Cross <damnedboy92@gmail.com> wrote:
That would have the effect that every use of str.format for everyone would start producing partially-formatted strings if an argument is accidentally omitted instead of raising an error. Some people might not like that. _______________________________________________
If that is all there is for a downside, this is actually quite weak. You just changed my mind to +1 on the proposal. Worst case scenario, one goes from one non-running program to a running program producing partially incorrect output. Any legacy code that was not working in the first place, is obviously, clearly, not critical for anyone, otherwise it would have been fixed already. We can't stal all augmenting to language functionalities because "some is used with the fact writing incorrect code in this way used to produce an error before". Ultimately, by this logic, it would be impossible to add even any new keyword only parameters to any stdlib call, because "there might be some code out there using this parameter, and that used to raise an error"
On Wed, 26 Apr 2023 at 11:18, Joao S. O. Bueno <gwidion@gmail.com> wrote:
Worst case scenario, one goes from one non-running program to a running program producing partially incorrect output.
Wording that another way: Buggy code, instead of raising an immediate exception, now produces wrong output. This is a very bad thing. ChrisA
On 2023-04-26 02:16, Joao S. O. Bueno wrote:
On Sat, Apr 22, 2023 at 10:06 AM Damian Cross <damnedboy92@gmail.com <mailto:damnedboy92@gmail.com>> wrote:
That would have the effect that every use of str.format for everyone would start producing partially-formatted strings if an argument is accidentally omitted instead of raising an error. Some people might not like that. _______________________________________________
If that is all there is for a downside, this is actually quite weak. You just changed my mind to +1 on the proposal.
Worst case scenario, one goes from one non-running program to a running program producing partially incorrect output. Any legacy code that was not working in the first place, is obviously, clearly, not critical for anyone, otherwise it would have been fixed already.
We can't stal all augmenting to language functionalities because "some is used with the fact writing incorrect code in this way used to produce an error before". Ultimately, by this logic, it would be impossible to add even any new keyword only parameters to any stdlib call, because "there might be some code out there using this parameter, and that used to raise an error"
The problem is that the resulting string might or might not be fully formatted, but you wouldn't be sure. The original post itself almost demonstrates the issue. I say "almost" because it has:
r"\mathjax{{color}}{{text}}".format(color="blue", text="Spanish")
which is '\\mathjax{color}{text}', not "\\mathjax{blue}{Spanish}", because "{{" and "}}" are literals. After correction:
pfr = r"\mathjax{{{color}}}{{{text}}}".format(color="blue")
So, pfr == r"\mathjax{blue}{{{text}}}". That looks like a format string with 2 placeholders, "{blue}" and "{text}". And what happens if the partially-formatted string isn't a valid format string? So I'm -1 on the idea. You'd be better off creating a new Format class that parses a format string and lets you insert values:
fmt = Format(r"\mathjax{{{color}}}{{{text}}}") fmt Format('\\mathjax{{{color}}}{{{text}}}')
(Calling it "Format" has the disadvantage that it's too close to the build-in function "format".) Placeholders can be positional or named, which is like the arguments of function calls, so maybe it's a callable:
fmt = fmt(color="blue") fmt Format('\\mathjax{{{color}}}{{{text}}}', color='blue') fmt = fmt(text="Spanish") fmt Format('\\mathjax{{{color}}}{{{text}}}', color='blue', text='Spanish') str(fmt) '\\mathjax{blue}{Spanish}' print(fmt) \mathjax{blue}{Spanish}
The advantages of leaving it as a format each time are 1) it can ignore unneeded values and 2) it consistently returns an instance of the same type.
On 2023-04-26 11:03 a.m., MRAB wrote:
On 2023-04-26 02:16, Joao S. O. Bueno wrote:
On Sat, Apr 22, 2023 at 10:06 AM Damian Cross <damnedboy92@gmail.com <mailto:damnedboy92@gmail.com>> wrote:
That would have the effect that every use of str.format for everyone would start producing partially-formatted strings if an argument is accidentally omitted instead of raising an error. Some people might not like that. _______________________________________________
If that is all there is for a downside, this is actually quite weak. You just changed my mind to +1 on the proposal.
Worst case scenario, one goes from one non-running program to a running program producing partially incorrect output. Any legacy code that was not working in the first place, is obviously, clearly, not critical for anyone, otherwise it would have been fixed already.
We can't stal all augmenting to language functionalities because "some is used with the fact writing incorrect code in this way used to produce an error before". Ultimately, by this logic, it would be impossible to add even any new keyword only parameters to any stdlib call, because "there might be some code out there using this parameter, and that used to raise an error"
The problem is that the resulting string might or might not be fully formatted, but you wouldn't be sure.
The original post itself almost demonstrates the issue. I say "almost" because it has:
r"\mathjax{{color}}{{text}}".format(color="blue", text="Spanish")
which is '\\mathjax{color}{text}', not "\\mathjax{blue}{Spanish}", because "{{" and "}}" are literals.
After correction:
pfr = r"\mathjax{{{color}}}{{{text}}}".format(color="blue")
So, pfr == r"\mathjax{blue}{{{text}}}".
That looks like a format string with 2 placeholders, "{blue}" and "{text}".
It's probably worse than that. I would suspect/expect pfr to be r"\mathjax{blue}{text}"; I see no reason why the brace literals surrounding {text} would be left unescaped and the other ones escaped.
You'd be better off creating a new Format class that parses a format string and lets you insert values:
fmt = Format(r"\mathjax{{{color}}}{{{text}}}") fmt Format('\\mathjax{{{color}}}{{{text}}}')
(Calling it "Format" has the disadvantage that it's too close to the build-in function "format".)
Placeholders can be positional or named, which is like the arguments of function calls, so maybe it's a callable:
fmt = fmt(color="blue") fmt Format('\\mathjax{{{color}}}{{{text}}}', color='blue') fmt = fmt(text="Spanish") fmt Format('\\mathjax{{{color}}}{{{text}}}', color='blue', text='Spanish') str(fmt) '\\mathjax{blue}{Spanish}' print(fmt) \mathjax{blue}{Spanish}
The advantages of leaving it as a format each time are 1) it can ignore unneeded values and 2) it consistently returns an instance of the same type.
Doesn't that essentially already exist as `string.Template` (albeit with a different though configurable identifier substitution language).
import string
string.Template(r'\mathjax{$color}{$text}').safe_substitute(color='blue') r'\mathjax{blue}{$text}'
On 2023-04-26 17:41, Alexandre Brault wrote:
On 2023-04-26 11:03 a.m., MRAB wrote:
On 2023-04-26 02:16, Joao S. O. Bueno wrote:
On Sat, Apr 22, 2023 at 10:06 AM Damian Cross <damnedboy92@gmail.com <mailto:damnedboy92@gmail.com>> wrote:
That would have the effect that every use of str.format for everyone would start producing partially-formatted strings if an argument is accidentally omitted instead of raising an error. Some people might not like that. _______________________________________________
If that is all there is for a downside, this is actually quite weak. You just changed my mind to +1 on the proposal.
Worst case scenario, one goes from one non-running program to a running program producing partially incorrect output. Any legacy code that was not working in the first place, is obviously, clearly, not critical for anyone, otherwise it would have been fixed already.
We can't stal all augmenting to language functionalities because "some is used with the fact writing incorrect code in this way used to produce an error before". Ultimately, by this logic, it would be impossible to add even any new keyword only parameters to any stdlib call, because "there might be some code out there using this parameter, and that used to raise an error"
The problem is that the resulting string might or might not be fully formatted, but you wouldn't be sure.
The original post itself almost demonstrates the issue. I say "almost" because it has:
r"\mathjax{{color}}{{text}}".format(color="blue", text="Spanish")
which is '\\mathjax{color}{text}', not "\\mathjax{blue}{Spanish}", because "{{" and "}}" are literals.
After correction:
pfr = r"\mathjax{{{color}}}{{{text}}}".format(color="blue")
So, pfr == r"\mathjax{blue}{{{text}}}".
That looks like a format string with 2 placeholders, "{blue}" and "{text}".
It's probably worse than that. I would suspect/expect pfr to be r"\mathjax{blue}{text}"; I see no reason why the brace literals surrounding {text} would be left unescaped and the other ones escaped.
You'd be better off creating a new Format class that parses a format string and lets you insert values:
fmt = Format(r"\mathjax{{{color}}}{{{text}}}") fmt Format('\\mathjax{{{color}}}{{{text}}}')
(Calling it "Format" has the disadvantage that it's too close to the build-in function "format".)
Placeholders can be positional or named, which is like the arguments of function calls, so maybe it's a callable:
fmt = fmt(color="blue") fmt Format('\\mathjax{{{color}}}{{{text}}}', color='blue') fmt = fmt(text="Spanish") fmt Format('\\mathjax{{{color}}}{{{text}}}', color='blue', text='Spanish') str(fmt) '\\mathjax{blue}{Spanish}' print(fmt) \mathjax{blue}{Spanish}
The advantages of leaving it as a format each time are 1) it can ignore unneeded values and 2) it consistently returns an instance of the same type.
Doesn't that essentially already exist as `string.Template` (albeit with a different though configurable identifier substitution language).
import string
string.Template(r'\mathjax{$color}{$text}').safe_substitute(color='blue') r'\mathjax{blue}{$text}'
It allows partial substitution, but the result is a string, so it suffers from the same problem.
What is the use case for this? Does it have any use case that's not already served by functools.partial? As far as I can tell, this proposal would turn buggy code that currently throws an obvious exception into code that silently does the wrong thing. This seems more appropriate for PHP or JavaScript (or C) than for Python. On Sat, 22 Apr 2023, 06:23 Samuel Muldoon, <muldoonsamuel@gmail.com> wrote:
Consider the following string:
x = r"\mathjax{{color}}{{text}}"
string `x` contains two parameters named `color` and the other named `text `.
Currently, python requires that the string class method `str.format` contain key-word arguments for *all *parameters, not just *one* parameter
result = r"\mathjax{{color}}{{text}}".format(color = "blue" , text = "Spanish")
result = "\mathjax{blue}{Spanish}"
Can we change str.format so that it is possible to change only one string parameter, but leave the other parameters alone?
# pfr is partially_formatted_result
pfr = r"\mathjax{{color}}{{text}}".format(color = "blue") # ERROR! missing parameter `text`
result = r"\mathjax{{color}}{{text}}".format(text = "Spanish") # ERROR! missing parameter `color`
The implementation requires fewer than ten lines of code in python, probably less than fifty lines in C, or a different implementation language.
class str: def format(self, **kwargs): for key in kwargs: x = "{"+key+"}" ostr = kwargs[key].join(self.split(x)) return ostr # output string
As an example, everywhere a string contained `{text}` it will now say `*Spanish*` .
*Samuel Muldoon*
*(720) 653 -2408*
*muldoonsamuel@gmail.com <muldoonsamuel@gmail.com>*
_______________________________________________ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-leave@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/2A6RTX... Code of Conduct: http://python.org/psf/codeofconduct/
It's actually much worse than making obviously buggy code pass silently. It can also make uncommon bugs almost impossible to detect. Some code looks like `mystring.format(**values)`. Whether values contains the needed keys can vary at runtime now. It might be fine under most code paths, but fail in other cases. That's already somewhat hard to catch, but the proposed change of passing silently disguises even the intermittent glimpse into the error. On Thu, Apr 27, 2023, 9:05 AM Matthias Görgens <matthias.goergens@gmail.com> wrote:
What is the use case for this?
Does it have any use case that's not already served by functools.partial?
As far as I can tell, this proposal would turn buggy code that currently throws an obvious exception into code that silently does the wrong thing.
This seems more appropriate for PHP or JavaScript (or C) than for Python.
On Sat, 22 Apr 2023, 06:23 Samuel Muldoon, <muldoonsamuel@gmail.com> wrote:
Consider the following string:
x = r"\mathjax{{color}}{{text}}"
string `x` contains two parameters named `color` and the other named ` text`.
Currently, python requires that the string class method `str.format` contain key-word arguments for *all *parameters, not just *one* parameter
result = r"\mathjax{{color}}{{text}}".format(color = "blue" , text = "Spanish")
result = "\mathjax{blue}{Spanish}"
Can we change str.format so that it is possible to change only one string parameter, but leave the other parameters alone?
# pfr is partially_formatted_result
pfr = r"\mathjax{{color}}{{text}}".format(color = "blue") # ERROR! missing parameter `text`
result = r"\mathjax{{color}}{{text}}".format(text = "Spanish") # ERROR! missing parameter `color`
The implementation requires fewer than ten lines of code in python, probably less than fifty lines in C, or a different implementation language.
class str: def format(self, **kwargs): for key in kwargs: x = "{"+key+"}" ostr = kwargs[key].join(self.split(x)) return ostr # output string
As an example, everywhere a string contained `{text}` it will now say `*Spanish*` .
*Samuel Muldoon*
*(720) 653 -2408*
*muldoonsamuel@gmail.com <muldoonsamuel@gmail.com>*
_______________________________________________ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-leave@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/2A6RTX... Code of Conduct: http://python.org/psf/codeofconduct/
_______________________________________________ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-leave@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/3HHUQV... Code of Conduct: http://python.org/psf/codeofconduct/
What if it's done not by format method but by a separete method, say, format_partially or something? The method is different from format also in that it should leave "{{" and "}}" unaltered. On Fri, 28 Apr 2023 at 00:05, Matthias Görgens <matthias.goergens@gmail.com> wrote:
Does it have any use case that's not already served by functools.partial?
I guess you mean given partially_formatted_string = unformatted_string.format(color="blue") that partially_formatted_string.format would be equivalent to partial(unformatted_string.format, color="blue") However, I think a partially formatted string can help since it will have other methods than format as well. For instance, given unformatted_string = '{color}{text}' doing the following thing only with functools.partial could require more care than you would be willing to give. string = (unformatted_string.format(color="blue") + unformatted_string ).format(text="Spanish", color="red") (One of the easiest ways might be ``` from functools import partial from operator import call format_ = unformatted_string.format string = "".join(map(partial(call, text="Spanish"), (partial(format_, color="blue"), partial(format_, color="red"), ))) ``` However, note the following, more straight-forward code doesn't work: ``` string = "".join(map(partial(call, text="Spanish", color="red"), (partial(format_, color="blue"), format_, ))) ``` ) Now, how about this? ``` format_ = '{a}{b}{c}'.format string = ((format_(a=a0) + format_(b=b0)).format(c=c0) + (format_(a=a1) + format_(c=c1)).format(b=b1) + (format_(b=b2) + format_(c=c2)).format(a=a2) ).format(a=a3, b=b3, c=c3) ``` (For instance, the following code fails: ``` from itertools import chain string = "".join(map(partial(call, a=a3, b=b3, c=c3), chain.from_iterable( map(map, (partial(partial, c=c0), partial(partial, b=b1), partial(partial, a=a2), ), ((partial(format_, a=a0), partial(format_, b=b0), ), (partial(format_, a=a1), partial(format_, c=c1), ), (partial(format_, b=b2), partial(format_, c=c2), ), )) ))) ``` ) Best regards, Takuo Matsuoka
On 2023-04-28 15:25, Matsuoka Takuo wrote:
What if it's done not by format method but by a separete method, say, format_partially or something? The method is different from format also in that it should leave "{{" and "}}" unaltered.
On Fri, 28 Apr 2023 at 00:05, Matthias Görgens <matthias.goergens@gmail.com> wrote:
Does it have any use case that's not already served by functools.partial?
I guess you mean given
partially_formatted_string = unformatted_string.format(color="blue")
that
partially_formatted_string.format
would be equivalent to
partial(unformatted_string.format, color="blue")
However, I think a partially formatted string can help since it will have other methods than format as well. For instance, given
unformatted_string = '{color}{text}'
doing the following thing only with functools.partial could require more care than you would be willing to give.
string = (unformatted_string.format(color="blue") + unformatted_string ).format(text="Spanish", color="red")
(One of the easiest ways might be
``` from functools import partial from operator import call
format_ = unformatted_string.format string = "".join(map(partial(call, text="Spanish"), (partial(format_, color="blue"), partial(format_, color="red"), ))) ```
However, note the following, more straight-forward code doesn't work:
``` string = "".join(map(partial(call, text="Spanish", color="red"), (partial(format_, color="blue"), format_, ))) ``` )
Now, how about this?
``` format_ = '{a}{b}{c}'.format
string = ((format_(a=a0) + format_(b=b0)).format(c=c0) + (format_(a=a1) + format_(c=c1)).format(b=b1) + (format_(b=b2) + format_(c=c2)).format(a=a2) ).format(a=a3, b=b3, c=c3) ```
(For instance, the following code fails:
``` from itertools import chain
string = "".join(map(partial(call, a=a3, b=b3, c=c3), chain.from_iterable( map(map, (partial(partial, c=c0), partial(partial, b=b1), partial(partial, a=a2), ), ((partial(format_, a=a0), partial(format_, b=b0), ), (partial(format_, a=a1), partial(format_, c=c1), ), (partial(format_, b=b2), partial(format_, c=c2), ), )) ))) ``` )
What happens if you do '{open}...{close}'.partial_format(open='{close}'? You get '{close}...{close}', and you're going to have a problem using that as a format string and replacing only the second '{close}'. Or how about '{open}...{close}'.partial_format(open='{')? You get '{...{close}'. Try using that as a format string! That's why I think that the result of a partial format should be an instance of a new class and not a string.
I suggest you guys implement this as a library, if you want it. You don't need to make your `partial_format` a method, it can just be a normal function. There's no need to fiddle with the built-in string or format function for this. On Fri, 28 Apr 2023, 22:27 Matsuoka Takuo, <motogeomtop@gmail.com> wrote:
What if it's done not by format method but by a separete method, say, format_partially or something? The method is different from format also in that it should leave "{{" and "}}" unaltered.
On Fri, 28 Apr 2023 at 00:05, Matthias Görgens <matthias.goergens@gmail.com> wrote:
Does it have any use case that's not already served by functools.partial?
I guess you mean given
partially_formatted_string = unformatted_string.format(color="blue")
that
partially_formatted_string.format
would be equivalent to
partial(unformatted_string.format, color="blue")
However, I think a partially formatted string can help since it will have other methods than format as well. For instance, given
unformatted_string = '{color}{text}'
doing the following thing only with functools.partial could require more care than you would be willing to give.
string = (unformatted_string.format(color="blue") + unformatted_string ).format(text="Spanish", color="red")
(One of the easiest ways might be
``` from functools import partial from operator import call
format_ = unformatted_string.format string = "".join(map(partial(call, text="Spanish"), (partial(format_, color="blue"), partial(format_, color="red"), ))) ```
However, note the following, more straight-forward code doesn't work:
``` string = "".join(map(partial(call, text="Spanish", color="red"), (partial(format_, color="blue"), format_, ))) ``` )
Now, how about this?
``` format_ = '{a}{b}{c}'.format
string = ((format_(a=a0) + format_(b=b0)).format(c=c0) + (format_(a=a1) + format_(c=c1)).format(b=b1) + (format_(b=b2) + format_(c=c2)).format(a=a2) ).format(a=a3, b=b3, c=c3) ```
(For instance, the following code fails:
``` from itertools import chain
string = "".join(map(partial(call, a=a3, b=b3, c=c3), chain.from_iterable( map(map, (partial(partial, c=c0), partial(partial, b=b1), partial(partial, a=a2), ), ((partial(format_, a=a0), partial(format_, b=b0), ), (partial(format_, a=a1), partial(format_, c=c1), ), (partial(format_, b=b2), partial(format_, c=c2), ), )) ))) ``` )
Best regards, Takuo Matsuoka _______________________________________________ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-leave@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/K5RPB4... Code of Conduct: http://python.org/psf/codeofconduct/
On Tue, Apr 25, 2023 at 6:16 PM Joao S. O. Bueno <gwidion@gmail.com> wrote:
Worst case scenario, one goes from one non-running program to a running program producing partially incorrect output. Any legacy code that was not working in the first place, is obviously, clearly, not critical for anyone, otherwise it would have been fixed already.
Worst case scenario: use of this feature introduces bugs. For example, security holes. Generally, formatting and parsing are not idempotent and you should not reformat or reparse already processed strings. See http://google-gruyere.appspot.com/ to learn more about the pitfalls and in particular http://google-gruyere.appspot.com/part5#5__information_disclosure_bug_3 On Fri, Apr 28, 2023 at 8:49 AM MRAB <python@mrabarnett.plus.com> wrote:
What happens if you do '{open}...{close}'.partial_format(open='{close}'? You get '{close}...{close}', and you're going to have a problem using that as a format string and replacing only the second '{close}'.
To take this further, suppose you write 'Hello {username} from {company}'.format(userdata).format(companydata) where the user has set their name to "Dr. {secret} Evil" where {secret} is something in companydata that should not be exposed. The presence of this bug is going to be very hard to find. This seems like an obvious case of a non-solution to a non-problem that's actually worse than no solution at all. --- Bruce
On 29/04/23 6:59 am, Bruce Leban wrote:
To take this further, suppose you write 'Hello {username} from {company}'.format(userdata).format(companydata) where the user has set their name to "Dr. {secret} Evil" where {secret} is something in companydata that should not be exposed.
More generally, a format string should be treated as code, and doing anything that could result in untrusted user data being treated as code is a Bad Idea. -- Greg
On Sat, 29 Apr 2023 at 00:52, MRAB <python@mrabarnett.plus.com> wrote:
What happens if you do '{open}...{close}'.partial_format(open='{close}'? You get '{close}...{close}', and you're going to have a problem using that as a format string and replacing only the second '{close}'.
Or how about '{open}...{close}'.partial_format(open='{')? You get '{...{close}'. Try using that as a format string!
That's why I think that the result of a partial format should be an instance of a new class and not a string.
That's a quite subtle point. I think '{open}...{close}'.partial_format(open='{close}') could be the string '{open}...{close}'.format(open='{{close}}', close='{close}') and '{open}...{close}'.partial_format(open='{') could be '{open}...{close}'.format(open='{{', close='{close}') Best regards, Takuo Matsuoka
On 2023-04-29 08:31, Matsuoka Takuo wrote:
On Sat, 29 Apr 2023 at 00:52, MRAB <python@mrabarnett.plus.com> wrote:
What happens if you do '{open}...{close}'.partial_format(open='{close}'? You get '{close}...{close}', and you're going to have a problem using that as a format string and replacing only the second '{close}'.
Or how about '{open}...{close}'.partial_format(open='{')? You get '{...{close}'. Try using that as a format string!
That's why I think that the result of a partial format should be an instance of a new class and not a string.
That's a quite subtle point. I think '{open}...{close}'.partial_format(open='{close}') could be the string
'{open}...{close}'.format(open='{{close}}', close='{close}')
and '{open}...{close}'.partial_format(open='{') could be '{open}...{close}'.format(open='{{', close='{close}')
You might not know what the replacements are until runtime, so: '{open}...{close}'.partial_format(open=opening_item)
On Sat, 29 Apr 2023 at 23:36, MRAB <python@mrabarnett.plus.com> wrote:
On 2023-04-29 08:31, Matsuoka Takuo wrote:
On Sat, 29 Apr 2023 at 00:52, MRAB <python@mrabarnett.plus.com> wrote:
What happens if you do '{open}...{close}'.partial_format(open='{close}'? You get '{close}...{close}', and you're going to have a problem using that as a format string and replacing only the second '{close}'.
Or how about '{open}...{close}'.partial_format(open='{')? You get '{...{close}'. Try using that as a format string!
That's why I think that the result of a partial format should be an instance of a new class and not a string.
That's a quite subtle point. I think '{open}...{close}'.partial_format(open='{close}') could be the string
'{open}...{close}'.format(open='{{close}}', close='{close}')
and '{open}...{close}'.partial_format(open='{') could be '{open}...{close}'.format(open='{{', close='{close}')
You might not know what the replacements are until runtime, so:
'{open}...{close}'.partial_format(open=opening_item)
A good point, but that's not a problem. Escape of braces can and must be done after the argument is formatted. I hope the expression '{open}...{close}'.format( open=re.sub('([{}])', r'\1\1', f'{opening_item}'), close='{close}' ) looks better. (I'm only describing the imaginable result here, and not the exact procedure to get to it. I can only say there is at least one way to get to it.)
participants (13)
-
Alexandre Brault
-
Bruce Leban
-
Chris Angelico
-
Damian Cross
-
David Mertz, Ph.D.
-
Greg Ewing
-
Joao S. O. Bueno
-
KL5L
-
Matsuoka Takuo
-
Matthias Görgens
-
MRAB
-
Rob Cliffe
-
Samuel Muldoon