Opened 16 years ago
Closed 13 years ago
#9483 closed Bug (wontfix)
Title template filter is broken
Reported by: | Henk de Vries | Owned by: | Henk de Vries |
---|---|---|---|
Component: | Template system | Version: | dev |
Severity: | Normal | Keywords: | title template filter |
Cc: | Triage Stage: | Design decision needed | |
Has patch: | yes | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description
There's a bug in Django ( trunk ) |title template filter:
This:
'foo;bar'|title
Gets converted into this:
Foo;Bar
This isn't the behavior it should have.
The correct behavior should be:
Foo;bar
Attachments (4)
Change History (20)
comment:1 by , 16 years ago
comment:2 by , 16 years ago
Owner: | changed from | to
---|---|
Status: | new → assigned |
comment:3 by , 16 years ago
Has patch: | set |
---|
comment:4 by , 16 years ago
milestone: | → post-1.0 |
---|
comment:5 by , 16 years ago
patch_1.diff is a patch against trunk. I will post a patch soon that is for the 1.0.X branch.
comment:6 by , 16 years ago
Why is there a great need to change this. We do what Python at does at the moment, which isn't unreasonable. This is an edge-case and whilst it doesn't necessarily do what you personally expect, it isn't de-facto wrong (normal written text won't have a semi-colon without a space following it).
So, what is the use-case that doesn't work without this change being made?
comment:7 by , 16 years ago
Well, normal text will often contain apostrophes, and I see Python most definitely gets this wrong, too:
>>> m = "something ain't right here" >>> m.title() "Something Ain'T Right Here"
The str.title() documentation says the method should "return a titlecased version of the string: words start with uppercase characters, all remaining cased characters are lowercase." If you speak strictly in regular expression terms, that's exactly what it's doing; but it's clearly not the intent.
With this post being my first foray into the Django community, I don't know what SOP is when Python appears to be broken. But it does seem sensible to accept the patch, so that title-casing works as expected for Django template authors.
(Related Python bug report: Issue 995422: title case bug — strangely rejected four years ago on the basis that "capitalization conventions vary from language to language," accompanied by an example from French... whose capitalization conventions are the same as ours. Might be worth trying to re-open the issue.)
comment:8 by , 16 years ago
Patch needs improvement: | set |
---|
Maybe we are using the wrong Python function here:
>>> import string >>> m = "something ain't right here" >>> string.capwords(m) "Something Ain't Right Here"
That would do what we want and it would perfectly be Python.
by , 16 years ago
Attachment: | patch_2_trunk.diff added |
---|
New patch with string.capwords(value) against trunk.
comment:9 by , 16 years ago
Kanuck54: Thanks for your support regarding this patch. I couldn't come up with a usecase that fast :-).
by , 16 years ago
Attachment: | patch_2_1.0.X.diff added |
---|
New patch with string.capwords(value) against 1.0.X.
comment:10 by , 16 years ago
These patches introduce dependencies against the 'string' module. I'm not a Python guru, so I don't know if this is a problem.
follow-up: 12 comment:11 by , 16 years ago
Patch needs improvement: | unset |
---|
comment:12 by , 16 years ago
Replying to hdevries:
There's also another side effect here: string.capwords() uses split(), which means that runs of multiple spaces will get converted to one space. That likely won't be a problem for most, as HTML tends not to care about such things, but it's not backwards-compatible.
comment:13 by , 16 years ago
Triage Stage: | Unreviewed → Design decision needed |
---|
Out of interest:
>>> import timeit >>> # Don'T Do It, Harold! It'S A Hyper-Trap! >>> timeit.Timer("s.title()", 's="Don\'t do it, Harold! It\'s a hyper-trap!"').timeit() 1.9782196480278917 >>> # Don't Do It, Harold! It's A Hyper-trap! >>> timeit.Timer("string.capwords(s)", 's="Don\'t do it, Harold! It\'s a hyper-trap!";import string').timeit() 6.9016400129066682 >>> # Don't Do It, Harold! It's A Hyper-trap! >>> timeit.Timer("r.sub(cap,s)", 's="Don\'t do it, Harold! It\'s a hyper-trap!"; import re;r=re.compile(r"(\s|^)\w");cap=lambda x: x.group().upper()').timeit() 13.67118104395945
comment:15 by , 14 years ago
Severity: | → Normal |
---|---|
Type: | → Bug |
comment:16 by , 13 years ago
Easy pickings: | unset |
---|---|
Resolution: | → wontfix |
Status: | assigned → closed |
UI/UX: | unset |
As pointed out by Malcolm, the initial example is rather artificial and doesn't warrant a change.
Furthermore Django handles correctly the example given in comment 7:
>>> from django.template.defaultfilters import title >>> m = "something ain't right here" >>> title(m) u"Something Ain't Right Here"
(There's some specific code to handle the apostrophe, and it appears in the patches uploaded above, which means it already existed when this ticket was opened.)
Absent a sufficiently convincing use case to break backwards compatibility, and given the lack of interest for this ticket over the last three years, I think we'd better keep the current implementation and I'm going to close this ticket.
It's easy enough to implement your own title
tag if the builtin doesn't match exactly your requirements.
Addendum:
I discovered this is a 'feature' of the Python string.title function. The above behavior also occurs with strings that have a '&' or "'" or '"'.
This would be a good solution: