summary of transitioning from % to {} formatting
I thought it might be useful for those who don't have time to read a million posts to have a summary of what's happened in the formatting discussion. The basic problem is that many APIs in the standard library and elsewhere support only %-formatting and not {}-formatting, e.g. logging.Formatter accepts:: logging.Formatter(fmt="%(asctime)s - %(name)s") but not:: logging.Formatter(fmt="{asctime} - {name}") There seems to be mostly agreement that these APIs should at least support both formatting styles, and a sizable group (including Guido) believe that %-formatting should eventually be phased out (e.g. by Python 4). There are a number of competing proposals on how to allow such APIs to start accepting {}-format strings: * Add a parameter which declares the type of format string:: logging.Formatter(fmt="{asctime} - {name}", format=BRACES) The API code would then switch between %-format and {}-format based on the value of that parameter. If %-formatting is to be deprecated, this could be done by first deprecating format=PERCENTS and requiring format=BRACES, and then changing the default to format=BRACES. * Create string subclasses which convert % use to .format calls:: __ = brace_fmt logging.Formatter(fmt=__("{asctime} - {name}")) The API code wouldn't have to change at all at first, as applying % to brace_fmt objects would call .format() instead. If %-formatting is to be deprecated, this could be done by first deprecating plain strings and requiring brace_fmt strings, and then allowing plain strings again but assuming they are {}-format strings. * Teach the API to accept callables as well as strings:: logging.Formatter(fmt="{asctime} - {name}".format) The API code would just call the object with .format() style arguments if a callable was given instead of a string. If %-formatting is to be deprecated, this could be done by first deprecating plain strings and requiring callables, and then allowing plain strings again but assuming they are {}-format strings * Create translators between %-format and {}-format:: assert to_braces("%(asctime)s") == "{asctime}" assert to_percents("{asctime}") == "%(asctime)s" these could then either be used outside of the API:: logging.Formatter(fmt=to_percents("{asctime} - {name}")) or they could be used within the API combined with some sort of heuristic for guessing whether a {}-format string or a %-format string was passed in:: logging.Formatter(fmt="{asctime} - {name}") If %-formatting is to be deprecated, the transition strategy here is trivial. However, no one has yet written translators, and it is not clear what heuristics should be used, e.g. should the method just try %-formatting first and then {}-formatting if it fails? I don't think there is consensus yet on which of these proposals should be the "blessed" one. Steve -- Where did you get that preposterous hypothesis? Did Steve tell you that? --- The Hiphopopotamus
Steven Bethard <steven.bethard <at> gmail.com> writes:
If %-formatting is to be deprecated, the transition strategy here is trivial. However, no one has yet written translators, and it is not clear what heuristics should be used, e.g. should the method just try %-formatting first and then {}-formatting if it fails?
This would be a reasonable heuristic. It should be done only on the first call, though, and then the result remembered (for both performance reasons and consistency). The cases where a format string would function in both formatting styles and expect the same parameters must be very rare in the real world. Regards Antoine.
2009/10/3 Antoine Pitrou <solipsis@pitrou.net>:
Steven Bethard <steven.bethard <at> gmail.com> writes:
If %-formatting is to be deprecated, the transition strategy here is trivial. However, no one has yet written translators, and it is not clear what heuristics should be used, e.g. should the method just try %-formatting first and then {}-formatting if it fails?
This would be a reasonable heuristic. It should be done only on the first call, though, and then the result remembered (for both performance reasons and consistency).
The cases where a format string would function in both formatting styles and expect the same parameters must be very rare in the real world.
Define "fails":
"{a} {b} c" % {'a':12} '{a} {b} c'
That didn't fail... Paul.
On Sat, 3 Oct 2009 at 17:08, Paul Moore wrote:
2009/10/3 Antoine Pitrou <solipsis@pitrou.net>:
Steven Bethard <steven.bethard <at> gmail.com> writes:
� If %-formatting is to be deprecated, the transition strategy here � is trivial. However, no one has yet written translators, and it is � not clear what heuristics should be used, e.g. should the method � just try %-formatting first and then {}-formatting if it fails?
This would be a reasonable heuristic. It should be done only on the first call, though, and then the result remembered (for both performance reasons and consistency).
The cases where a format string would function in both formatting styles and expect the same parameters must be very rare in the real world.
Define "fails":
"{a} {b} c" % {'a':12} '{a} {b} c'
That didn't fail...
Also, what if both fail? Which failure's error message gets printed? --David (RDM)
Define "fails":
"{a} {b} c" % {'a':12} '{a} {b} c'
That didn't fail...
Ah, my bad. I had completely overlooked that formatting was laxist when faced with unused named parameters. Then we need something smarter, like counting the number of unescaped "%" characters, the number of pairs of braces, and try first the formatting style expecting the greatest number of parameters. It can either be done cheaply in Python, or more rigourously by providing an extra API to the existing C parsing routines. This might look fragile, but we should not forget that we are talking about uses - logging, etc. - which will most of time involve very simple format strings, such that making an automatic decision is not too difficult. In the more undecideable cases, the heuristic might decide to raise an exception and require the developer to specify the formatting style explicitly (by adding e.g. style='%' or style='{}' to the method call). Regards Antoine.
On Oct 3, 2009, at 11:41 AM, Steven Bethard wrote:
I thought it might be useful for those who don't have time to read a million posts to have a summary of what's happened in the formatting discussion.
The basic problem is that many APIs in the standard library and elsewhere support only %-formatting and not {}-formatting, e.g. logging.Formatter accepts:: logging.Formatter(fmt="%(asctime)s - %(name)s") but not:: logging.Formatter(fmt="{asctime} - {name}")
I'd like to at least keep in mind $-strings. I don't have any experience with {}-strings w.r.t. i18n translators, but I'm very confident that $-strings are better for translators than %-strings. OT1H {}-strings don't suffer from the #1 problem of %-strings: leaving off the trailing 's' or whatever. OTOH, I suspect that $-strings are still easier for the simple substitution case; for example, it's conceivable that translators may forget the trailing close brace. Since we're likely to have multiple formatting styles at least for Python 3's lifetime, I'd like any solution we come up with to at least not preclude the use of $-strings. I also don't think this is a case of anti-TOOWTDI. For most situations {}-strings are great (IMO), but in the specific translation domain, I suspect $-strings are still better. -Barry
Barry Warsaw wrote:
I also don't think this is a case of anti-TOOWTDI. For most situations {}-strings are great (IMO), but in the specific translation domain, I suspect $-strings are still better.
I agree that keeping string.Template around is valid due to its focus on being very simple to use (especially for non-coders producing translation templates) However, string.Template is already set up to work for the relevant APIs in that domain so I don't think it will really be affected by any changes to the underlying language and library support for brace formatting. Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia ---------------------------------------------------------------
On Oct 4, 2009, at 4:11 AM, Nick Coghlan wrote:
Barry Warsaw wrote:
I also don't think this is a case of anti-TOOWTDI. For most situations {}-strings are great (IMO), but in the specific translation domain, I suspect $-strings are still better.
I agree that keeping string.Template around is valid due to its focus on being very simple to use (especially for non-coders producing translation templates)
However, string.Template is already set up to work for the relevant APIs in that domain so I don't think it will really be affected by any changes to the underlying language and library support for brace formatting.
What if you wanted to translate log messages? Printing to a StringIO first really isn't a very good solution. -Barry
Barry Warsaw wrote:
On Oct 4, 2009, at 4:11 AM, Nick Coghlan wrote:
Barry Warsaw wrote:
I also don't think this is a case of anti-TOOWTDI. For most situations {}-strings are great (IMO), but in the specific translation domain, I suspect $-strings are still better.
I agree that keeping string.Template around is valid due to its focus on being very simple to use (especially for non-coders producing translation templates)
However, string.Template is already set up to work for the relevant APIs in that domain so I don't think it will really be affected by any changes to the underlying language and library support for brace formatting.
What if you wanted to translate log messages? Printing to a StringIO first really isn't a very good solution.
Oh, I see what you meant now - you were pointing out that lazy formatting APIs (such as logging) already don't work properly for alternative formatting mechanisms (such as string.Template). (Although printing to a String IO doesn't seem necessary - simply pre-formatting the message seems like it should work, just as preformatting brace formatted messages already works today). The idea of adding an optional "fmt_style" callable to these APIs (defaulting to None, which would imply the use of the mod operator) is becoming more appealing... Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia ---------------------------------------------------------------
On Oct 5, 2009, at 4:41 PM, Nick Coghlan wrote:
Oh, I see what you meant now - you were pointing out that lazy formatting APIs (such as logging) already don't work properly for alternative formatting mechanisms (such as string.Template).
Yep.
(Although printing to a String IO doesn't seem necessary - simply pre-formatting the message seems like it should work, just as preformatting brace formatted messages already works today).
Yep. :)
The idea of adding an optional "fmt_style" callable to these APIs (defaulting to None, which would imply the use of the mod operator) is becoming more appealing...
-Barry
Nick Coghlan <ncoghlan <at> gmail.com> writes:
Oh, I see what you meant now - you were pointing out that lazy formatting APIs (such as logging) already don't work properly for alternative formatting mechanisms (such as string.Template).
Logging doesn't work automatically with string.Template as it pre-dates string.Template, but it can be made to work without too much trouble: (a) Subclass Formatter to use $-formatting instead of %-formatting for e.g. the lines written to log files, and (b) Use a class like DollarMessage which I mentioned elsewhere in this thread, to format logging call format strings and arguments. Both of these approaches will also work for {}-formatting. The present thread really started out with a view to suggesting that the stdlib start adopting {}-format as "native", rather than %-format. Would it be helpful if I added a section to the Python docs about how to use alternative formatting systems with logging? Regards, Vinay Sajip
Vinay Sajip wrote:
Both of these approaches will also work for {}-formatting. The present thread really started out with a view to suggesting that the stdlib start adopting {}-format as "native", rather than %-format.
Would it be helpful if I added a section to the Python docs about how to use alternative formatting systems with logging?
That would probably be a good idea. Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia ---------------------------------------------------------------
On Sat, Oct 3, 2009 at 4:41 PM, Steven Bethard <steven.bethard@gmail.com> wrote:
I thought it might be useful for those who don't have time to read a million posts to have a summary of what's happened in the formatting discussion.
Definitely useful. Thanks for the summary! [...]
* Add a parameter which declares the type of format string:: logging.Formatter(fmt="{asctime} - {name}", format=BRACES) The API code would then switch between %-format and {}-format based on the value of that parameter. If %-formatting is to be deprecated, this could be done by first deprecating format=PERCENTS and requiring format=BRACES, and then changing the default to format=BRACES.
+1.
* Create string subclasses which convert % use to .format calls:: __ = brace_fmt logging.Formatter(fmt=__("{asctime} - {name}")) The API code wouldn't have to change at all at first, as applying % to brace_fmt objects would call .format() instead. If %-formatting is to be deprecated, this could be done by first deprecating plain strings and requiring brace_fmt strings, and then allowing plain strings again but assuming they are {}-format strings.
Uurgh. This just feels... icky. A badly-rationalized -1 from me.
* Teach the API to accept callables as well as strings:: logging.Formatter(fmt="{asctime} - {name}".format) The API code would just call the object with .format() style arguments if a callable was given instead of a string. If %-formatting is to be deprecated, this could be done by first deprecating plain strings and requiring callables, and then allowing plain strings again but assuming they are {}-format strings
+0.5. Seems like it could work, but the first solution feels cleaner.
* Create translators between %-format and {}-format:: assert to_braces("%(asctime)s") == "{asctime}" assert to_percents("{asctime}") == "%(asctime)s" these could then either be used outside of the API:: logging.Formatter(fmt=to_percents("{asctime} - {name}")) or they could be used within the API combined with some sort of heuristic for guessing whether a {}-format string or a %-format string was passed in:: logging.Formatter(fmt="{asctime} - {name}") If %-formatting is to be deprecated, the transition strategy here is trivial. However, no one has yet written translators, and it is not clear what heuristics should be used, e.g. should the method just try %-formatting first and then {}-formatting if it fails?
I'm reserving judgement on this one until it becomes clear how feasible it is. Without having thought about it too hard, this sounds potentially tricky and bug-prone. Mark
Mark Dickinson wrote:
On Sat, Oct 3, 2009 at 4:41 PM, Steven Bethard <steven.bethard@gmail.com> wrote:
I thought it might be useful for those who don't have time to read a million posts to have a summary of what's happened in the formatting discussion.
Definitely useful. Thanks for the summary!
[...]
* Add a parameter which declares the type of format string:: logging.Formatter(fmt="{asctime} - {name}", format=BRACES) The API code would then switch between %-format and {}-format based on the value of that parameter. If %-formatting is to be deprecated, this could be done by first deprecating format=PERCENTS and requiring format=BRACES, and then changing the default to format=BRACES.
+1. [snip] 'fmt' (which is an abbreviation for 'format') and 'format'? Maybe 'fmt' and 'style' instead?
Steven Bethard wrote:
I thought it might be useful for those who don't have time to read a million posts to have a summary of what's happened in the formatting discussion.
The basic problem is that many APIs in the standard library and elsewhere support only %-formatting and not {}-formatting, e.g. logging.Formatter accepts:: logging.Formatter(fmt="%(asctime)s - %(name)s") but not:: logging.Formatter(fmt="{asctime} - {name}")
There seems to be mostly agreement that these APIs should at least support both formatting styles, and a sizable group (including Guido) believe that %-formatting should eventually be phased out (e.g. by Python 4). There are a number of competing proposals on how to allow such APIs to start accepting {}-format strings:
* Add a parameter which declares the type of format string:: logging.Formatter(fmt="{asctime} - {name}", format=BRACES) The API code would then switch between %-format and {}-format based on the value of that parameter. If %-formatting is to be deprecated, this could be done by first deprecating format=PERCENTS and requiring format=BRACES, and then changing the default to format=BRACES.
* Create string subclasses which convert % use to .format calls:: __ = brace_fmt logging.Formatter(fmt=__("{asctime} - {name}")) The API code wouldn't have to change at all at first, as applying % to brace_fmt objects would call .format() instead. If %-formatting is to be deprecated, this could be done by first deprecating plain strings and requiring brace_fmt strings, and then allowing plain strings again but assuming they are {}-format strings.
* Teach the API to accept callables as well as strings:: logging.Formatter(fmt="{asctime} - {name}".format) The API code would just call the object with .format() style arguments if a callable was given instead of a string. If %-formatting is to be deprecated, this could be done by first deprecating plain strings and requiring callables, and then allowing plain strings again but assuming they are {}-format strings
I'm not keen on deprecating strings in favour of callables and then callables in favour of strings.
* Create translators between %-format and {}-format:: assert to_braces("%(asctime)s") == "{asctime}" assert to_percents("{asctime}") == "%(asctime)s" these could then either be used outside of the API:: logging.Formatter(fmt=to_percents("{asctime} - {name}")) or they could be used within the API combined with some sort of heuristic for guessing whether a {}-format string or a %-format string was passed in:: logging.Formatter(fmt="{asctime} - {name}") If %-formatting is to be deprecated, the transition strategy here is trivial. However, no one has yet written translators, and it is not clear what heuristics should be used, e.g. should the method just try %-formatting first and then {}-formatting if it fails?
Another possibility: A StringFormat class with subclasses PercentStringFormat, BraceStringFormat, and perhaps DollarStringFormat. Or: A StringFormat class with methods parse_percent_format, parse_brace_format, and parse_dollar_format. There could also be a format-guesser method.
I don't think there is consensus yet on which of these proposals should be the "blessed" one.
MRAB <python <at> mrabarnett.plus.com> writes:
Another possibility:
A StringFormat class with subclasses PercentStringFormat, BraceStringFormat, and perhaps DollarStringFormat.
Or:
A StringFormat class with methods parse_percent_format, parse_brace_format, and parse_dollar_format. There could also be a format-guesser method.
I'm sorry to say this, but I think these suggestions are getting foolish. We core developers might have an interest in transitioning users from one formatting style to another, but the users mostly don't care and don't want to bother. Imposing on users the explicit use of such wrapper classes, moreover with such awfully long-winded names, is not helpful to them at all, and it will earn Python the reputation of a language which imposes silly constructs in the name of purity. If we can't find a way to make things almost transparent, we should IMO abandon the whole idea of a transition. Regards Antoine.
Antoine Pitrou wrote:
MRAB <python <at> mrabarnett.plus.com> writes:
Another possibility:
A StringFormat class with subclasses PercentStringFormat, BraceStringFormat, and perhaps DollarStringFormat.
Or:
A StringFormat class with methods parse_percent_format, parse_brace_format, and parse_dollar_format. There could also be a format-guesser method.
I'm sorry to say this, but I think these suggestions are getting foolish. We core developers might have an interest in transitioning users from one formatting style to another, but the users mostly don't care and don't want to bother. Imposing on users the explicit use of such wrapper classes, moreover with such awfully long-winded names, is not helpful to them at all, and it will earn Python the reputation of a language which imposes silly constructs in the name of purity.
Fair enough. The purpose of the post was really just so that we cover as many possibilities as we can so that if at some time in the future someone asks why we didn't consider such-and-such then we won't be saying "Oh, never thought of that!". :-)
If we can't find a way to make things almost transparent, we should IMO abandon the whole idea of a transition.
Antoine Pitrou wrote:
If we can't find a way to make things almost transparent, we should IMO abandon the whole idea of a transition.
Yep - this is the reason some attempts at actual format translation implementations started up as a result of the previous discussion. Without that, I suspect any API transitions are going to be too much hassle to be worthwhile. Regards, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia ---------------------------------------------------------------
On Sun, 4 Oct 2009 01:41:36 am Steven Bethard wrote:
I thought it might be useful for those who don't have time to read a million posts to have a summary of what's happened in the formatting discussion.
The basic problem is that many APIs in the standard library and elsewhere support only %-formatting and not {}-formatting, e.g. logging.Formatter accepts:: logging.Formatter(fmt="%(asctime)s - %(name)s") but not:: logging.Formatter(fmt="{asctime} - {name}")
Why is this a problem? Is it because the APIs require extra functionality that only {} formatting can provide? Possibly, but I doubt it -- I expect that the reason is: (1) Some people would like to deprecate % formatting, and they can't while the std lib uses % internally. (2) Some APIs in the std lib are tightly coupled to their internal implementation, and so you can't change their implementation without changing the API as well. Remove either of these issues, and the problem becomes a non-problem, and no action is needed. Personally, I'd like to see no further talk about deprecating % until at least Python 3.2, that is, the *earliest* we would need to solve this issue would be 3.3. As the Zen says, "Although never is often better than *right* now."
There seems to be mostly agreement that these APIs should at least support both formatting styles, and a sizable group (including Guido) believe that %-formatting should eventually be phased out (e.g. by Python 4).
-1 on that. Time will tell if I change my mind in a couple of years, but I suspect not -- for simple formatting, I far prefer %. Judging by the reaction on comp.lang.python when this has been discussed in the past, I think a large (or at least loud) proportion of Python programmers agree with me.
There are a number of competing proposals on how to allow such APIs to start accepting {}-format strings:
* Add a parameter which declares the type of format string:: logging.Formatter(fmt="{asctime} - {name}", format=BRACES) The API code would then switch between %-format and {}-format based on the value of that parameter. If %-formatting is to be deprecated, this could be done by first deprecating format=PERCENTS and requiring format=BRACES, and then changing the default to format=BRACES.
+0.5
* Create string subclasses which convert % use to .format calls:: __ = brace_fmt logging.Formatter(fmt=__("{asctime} - {name}"))
There are a few problems with this approach: - Nobody has yet demonstrated that this brace_fmt class is even possible. It should be easy to handle a restricted set of simple templates (e.g. of the form "%(name)s" only), but what of the full range of behaviour supported by % formatting? - Even if it is doable, it is a wrapper class, which means the module will suffer a performance hit on every call. At this time, we have no idea what the magnitude of that hit will be, but .format() is already slower than % so it will likely be significant. - It strikes me as hideously ugly. I for one would delay using it as long as possible, no matter how many DepreciationWarnings I got. I'd drag my feet and avoid changing and complain loudly and then become sullen and resentful when I couldn't avoid making the change. I'd much rather go straight from %-based templates to {} in a single step than have this Frankenstein monster intermediate. [...]
* Teach the API to accept callables as well as strings:: logging.Formatter(fmt="{asctime} - {name}".format) The API code would just call the object with .format() style arguments if a callable was given instead of a string.
+0.5
* Create translators between %-format and {}-format:: assert to_braces("%(asctime)s") == "{asctime}" assert to_percents("{asctime}") == "%(asctime)s"
+1, assuming such translators are even possible. Being optimistic, such translators would have one additional benefit: they would enable modules to completely decouple the API they offer from their internal implementation, without paying a runtime cost on every call, just a single once-off translation at initialisation time. In theory, this could mean that modules could, if they choose, continue to offer an API based on % long after str.__mod__ is removed from the language. -- Steven D'Aprano
On Sat, Oct 3, 2009 at 11:01, Steven D'Aprano <steve@pearwood.info> wrote:
On Sun, 4 Oct 2009 01:41:36 am Steven Bethard wrote:
I thought it might be useful for those who don't have time to read a million posts to have a summary of what's happened in the formatting discussion.
The basic problem is that many APIs in the standard library and elsewhere support only %-formatting and not {}-formatting, e.g. logging.Formatter accepts:: logging.Formatter(fmt="%(asctime)s - %(name)s") but not:: logging.Formatter(fmt="{asctime} - {name}")
Why is this a problem? Is it because the APIs require extra functionality that only {} formatting can provide? Possibly, but I doubt it -- I expect that the reason is:
(1) Some people would like to deprecate % formatting, and they can't while the std lib uses % internally.
(2) Some APIs in the std lib are tightly coupled to their internal implementation, and so you can't change their implementation without changing the API as well.
Remove either of these issues, and the problem becomes a non-problem, and no action is needed. Personally, I'd like to see no further talk about deprecating % until at least Python 3.2, that is, the *earliest* we would need to solve this issue would be 3.3. As the Zen says, "Although never is often better than *right* now."
No one is saying we should deprecate % any time soon on strings themselves or anywhere. This discussion is purely in regards to argparse and logging to transition *their* APIs over to {} formatting which would most likely involve some deprecation for *using* % formatting in those APIs. But % formatting on strings themselves is not directly being discussed here. -Brett
Brett Cannon <brett <at> python.org> writes:
No one is saying we should deprecate % any time soon on strings themselves or anywhere. This discussion is purely in regards to argparse and logging to transition *their* APIs over to {} formatting which would most likely involve some deprecation for *using* % formatting in those APIs. But % formatting on strings themselves is not directly being discussed here.
While I have no problem with supporting {}-formatting in logging if we find a good way of doing it, one thing that bothers me about transitioning the logging API to deprecate or otherwise de-emphasise %-formatting is the question of performance. Now, str.format is more flexible than str.__mod__ and so some performance loss may be tolerable in many scenarios. However, in the feedback I regularly get about logging, people are concerned about performance. No-one ever comes up with any hard numbers, but logging is often bashed as slow (see e.g. Andrii Mishkovskyi's LoggingPackage page on the Python wiki). I don't especially want to add fuel to the fire, as any performance degradation caused by supporting {}-formatting will likely just result in more finger-pointing at logging in general. Regards, Vinay Sajip
Brett Cannon wrote:
No one is saying we should deprecate % any time soon on strings themselves or anywhere. This discussion is purely in regards to argparse and logging to transition *their* APIs over to {} formatting which would most likely involve some deprecation for *using* % formatting in those APIs. But % formatting on strings themselves is not directly being discussed here.
Actually, I think percent formatting and brace formatting should remain fully supported peers for the life of 3.x (including in APIs such as argparse and logging). No matter how much we might like the new formatting system (and I certainly prefer it), there's a long period of evangelisation and performance improvements that needs to happen before we can realistically start to deprecate percent formatting based APIs in any way shape or form. Until that happens, then users do have the right to dig in their heels and say "look, the limitations on percent formatting really don't bother us, certainly not enough to switch to a new formatting system". Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia ---------------------------------------------------------------
Steven Bethard wrote:
I thought it might be useful for those who don't have time to read a million posts to have a summary of what's happened in the formatting discussion.
definitely
The basic problem is that many APIs in the standard library and elsewhere support only %-formatting and not {}-formatting, e.g. logging.Formatter accepts:: logging.Formatter(fmt="%(asctime)s - %(name)s") but not:: logging.Formatter(fmt="{asctime} - {name}")
There seems to be mostly agreement that these APIs should at least support both formatting styles, and a sizable group (including Guido) believe that %-formatting should eventually be phased out (e.g. by Python 4). There are a number of competing proposals on how to allow such APIs to start accepting {}-format strings:
* Add a parameter which declares the type of format string:: logging.Formatter(fmt="{asctime} - {name}", format=BRACES) The API code would then switch between %-format and {}-format based on the value of that parameter. If %-formatting is to be deprecated, this could be done by first deprecating format=PERCENTS and requiring format=BRACES, and then changing the default to format=BRACES.
...
* Create translators between %-format and {}-format:: assert to_braces("%(asctime)s") == "{asctime}" assert to_percents("{asctime}") == "%(asctime)s" these could then either be used outside of the API:: logging.Formatter(fmt=to_percents("{asctime} - {name}")) or they could be used within the API combined with some sort of heuristic for guessing whether a {}-format string or a %-format string was passed in:: logging.Formatter(fmt="{asctime} - {name}")
How about combining these two. Add an optional form or style=xxx parameter -- which could also allow DOLLARS for $-formats -- for resolving ambiguities. If not present, make a reasonable guess. IE, if string has no '%' and multiple {} pairs, or no {} pairs and multiple %s, the guess is at least .999 sure. which is to not, not hardly a guess. The extra arg can be supplied if and when needed. The machinery for this should be not be logging specific, so it can be used through throughout the library, and exposed so that others can use it. Terry Jan Reedy
Terry Reedy wrote:
Steven Bethard wrote:
I thought it might be useful for those who don't have time to read a million posts to have a summary of what's happened in the formatting discussion.
definitely
The basic problem is that many APIs in the standard library and elsewhere support only %-formatting and not {}-formatting, e.g. logging.Formatter accepts:: logging.Formatter(fmt="%(asctime)s - %(name)s") but not:: logging.Formatter(fmt="{asctime} - {name}")
There seems to be mostly agreement that these APIs should at least support both formatting styles, and a sizable group (including Guido) believe that %-formatting should eventually be phased out (e.g. by Python 4). There are a number of competing proposals on how to allow such APIs to start accepting {}-format strings:
* Add a parameter which declares the type of format string:: logging.Formatter(fmt="{asctime} - {name}", format=BRACES) The API code would then switch between %-format and {}-format based on the value of that parameter. If %-formatting is to be deprecated, this could be done by first deprecating format=PERCENTS and requiring format=BRACES, and then changing the default to format=BRACES.
...
* Create translators between %-format and {}-format:: assert to_braces("%(asctime)s") == "{asctime}" assert to_percents("{asctime}") == "%(asctime)s" these could then either be used outside of the API:: logging.Formatter(fmt=to_percents("{asctime} - {name}")) or they could be used within the API combined with some sort of heuristic for guessing whether a {}-format string or a %-format string was passed in:: logging.Formatter(fmt="{asctime} - {name}")
How about combining these two. Add an optional form or style=xxx parameter -- which could also allow DOLLARS for $-formats -- for resolving ambiguities. If not present, make a reasonable guess. IE, if string has no '%' and multiple {} pairs, or no {} pairs and multiple %s, the guess is at least .999 sure. which is to not, not hardly a guess. The extra arg can be supplied if and when needed.
Maybe if the style is a callable then that's the formatting function? (Or is that asking for trouble? :-)) In that case the style could default to a function which guesses which style is being used and then the appropriate function.
The machinery for this should be not be logging specific, so it can be used through throughout the library, and exposed so that others can use it.
participants (12)
-
Antoine Pitrou
-
Barry Warsaw
-
Brett Cannon
-
Mark Dickinson
-
MRAB
-
Nick Coghlan
-
Paul Moore
-
R. David Murray
-
Steven Bethard
-
Steven D'Aprano
-
Terry Reedy
-
Vinay Sajip