I am not going to pardon you for jumping into a discussion that is many posts deep, responding to one of the first, clearly not having read any other potentially relevant posts; my position is clear, I am not going to repeat myself here. (You can disagree that my suggestion is easier, but that needs you to firsr put in the small amount of effort required to figure out what my suggestion is)
If that is unsafe (and probably it is), why is Template + string permitted?
t"a" + "b"
Template(strings=('ab',), interpolations=())
this should be disallowed as well.
I agree that it should be disallowed; Sadly it has to be allowed to support strings right next to each other like
template = (t"hello {name}"
"This is a greeting")
Not supporting this kind of syntax would be asymmetric with f-strings and so it was decided to support it even if it’s not exactly ideal. The discussion around this should be somewhere in the PEP thread; I haven’t actually checked if any of this discussion made it into the PEP itself.
I fail to see the relation between implicit concatenation of two literal strings, which is handled by the parser, and the __add__ operator, which is handled by the interpreter.
Of course Template.join() could check the content of the sequence and throw an exception if it contains anything but a template… exactly like str.join() does, discarding any element including ones that can actually be concatenated to a string.
>>> "" + t""
Template(strings=('',), interpolations=())
>>> "".join([t""])
Traceback (most recent call last):
File "<python-input-42>", line 1, in <module>
"".join([t""])
~~~~~~~^^^^^^^
TypeError: sequence item 0: expected str instance, string.templatelib.Template found
It seems clear to me here, that z and w, if they are plain strings and not Template objects, should be escaped before being joined into x. Pretty obvious, and as safe as anything. Why?
z = "{evil}"
x = t", ".join(t"{good}", z, "{ugly}")
# the only interpolation is "good" and {evil} and { ugly} are just text content on the strings.
Ok, I am bowing out. Nothing good is going to come from further interactions from my side in this thread.
I have opened a separate topic about the str + Template issue: PEP 750: disallow str + Template because it’s unrelated to whether to have or not Template.join() (and much more serious IMO).
Count me as a firm +1 for a Template.join method that operates only on Template objects.
I can think of 2 reasons, only one of which has been discussed here.
- Support building larger templates. I often build long, multiline strings by building a list of lines, then ending with a
"\n".join(lines)to produce the final string. (This is especially useful if some of the lines are optional or depend on business logic.) Since Template strings are intended for DSL uses, I can easily imagine wanting to build long, multiline templates (e.g. SQL queries) in this way.
I also learned early not to build strings via repeated addition - it seems odd to now explicitly encourage doing just that for templates (even if the same performance considerations no longer apply). - Combine a list of parameters like @dvarrazzo already suggested. While one could use a minilang in the format (like @MegaIng suggested) or a separate function to do this (like @layday suggested), neither of these options should preclude using something like
t" AND ".join(…)for a lower-level interface that performs escaping but otherwise lets the caller handle the detailed SQL query.
——————
That leaves a question of what types join should operate on.
Realistically, since join is just repeated addition, it should accept the same types as __add__. The direction of PEP 750: disallow str + Template strongly suggests addition will just be between Template objects, which means the same should apply to join.
Then x is t"{good}, {evil}, {ugly}" but is different than x = t"{good}, {evil}, {ugly}" → This is a paradox !
… But it can be solved by setting an option to join() which would specify behavior : raise error (probably default option for safety), OR add escape characters to { and } OR add the new interpolations.
In the past, these things would be resolved from a principle of caution.
It is easier to add features than to remove them, so new Python features would start out with maybe a few more restrictions than necessary, with the idea that the restrictions could always to relaxed later, if it was found to be necessary.
An example is decorators: Originally, only very limited types of expressions were allowed as the decorator expression. Later, the minor nuisance of having to explain the restrictions, combined with examples being presented of other kinds of expressions being useful, led to the restrictions being relaxed. The change was perfectly backwards compatible, making this the easiest change ever - most people didn’t even notice anything was changed, unless they’d read about it on a mailing list.
Once added, removing the ability to add t-strings and regular strings will not
be as easy.
Considering the potential that it has to undermine the intended safety gains from using t-strings, I am surprised that the principle of caution was not employed in this case.
In the PEP it’s half a sentence, no discussion. Very easy to overlook on a casual reading. I’m not sure it was discussed at all.
Then
xist"{good}, {evil}, {ugly}"but is different thanx = t"{good}, {evil}, {ugly}"→ This is a paradox !
No - x is not that - rather is a template string, containing "{good} " as an interpolation and ('', '{evil}{ugly}') as its .strings values.
It is not even easy to print a Template string back - trying to rebuild how it would be typed - but if one do, it would should be preinted as : t"{good}, {{evil}}, {{ugly}}" in this case.
@dkp As there is a chance to fix the str+Template issue by beta, is there a chance that the PEP 750 team could look into this idea too? Or has it been discussed and rejected?
Thank you very much!
The str+Template issue struck us as a spec bug and so, even at this late stage, we were willing to go to the SC for it. On the other hand, join() is new functionality; I think we’d want a new PEP for it.