Opened 7 years ago

Closed 6 years ago

#29412 closed Bug (fixed)

django.utils.text.slugify() shouldn't return a SafeString

Reported by: Andreas Pelme Owned by: Tim Graham <timograham@…>
Component: Utilities Version: 2.0
Severity: Normal Keywords:
Cc: Triage Stage: Ready for checkin
Has patch: yes Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

https://github.com/django/django/commit/ccfd1295f986cdf628d774937d0b38a14584721f changed SafeString.__str__ to return itself rather than a native string.

This works fine in most places. However, interning (sys.intern) a SafeString does not work, it needs to be converted to a regular string first.

I use slugify to generate file names and passing it on to pathlib.Path. Path interns strings and this breaks:

>>> from django.utils.text import slugify
>>> import pathlib
>>> pathlib.Path(slugify('foo'))
Traceback (most recent call last):
  File "<input>", line 1, in <module>
  File "/usr/local/Cellar/python/3.6.5/Frameworks/Python.framework/Versions/3.6/lib/python3.6/pathlib.py", line 999, in __new__
    self = cls._from_parts(args, init=False)
  File "/usr/local/Cellar/python/3.6.5/Frameworks/Python.framework/Versions/3.6/lib/python3.6/pathlib.py", line 656, in _from_parts
    drv, root, parts = self._parse_args(args)
  File "/usr/local/Cellar/python/3.6.5/Frameworks/Python.framework/Versions/3.6/lib/python3.6/pathlib.py", line 649, in _parse_args
    return cls._flavour.parse_parts(parts)
  File "/usr/local/Cellar/python/3.6.5/Frameworks/Python.framework/Versions/3.6/lib/python3.6/pathlib.py", line 69, in parse_parts
    parsed.append(sys.intern(rel))
TypeError: can't intern SafeText
>>> pathlib.Path(str(slugify('foo')))
Traceback (most recent call last):
  File "<input>", line 1, in <module>
  File "/usr/local/Cellar/python/3.6.5/Frameworks/Python.framework/Versions/3.6/lib/python3.6/pathlib.py", line 999, in __new__
    self = cls._from_parts(args, init=False)
  File "/usr/local/Cellar/python/3.6.5/Frameworks/Python.framework/Versions/3.6/lib/python3.6/pathlib.py", line 656, in _from_parts
    drv, root, parts = self._parse_args(args)
  File "/usr/local/Cellar/python/3.6.5/Frameworks/Python.framework/Versions/3.6/lib/python3.6/pathlib.py", line 649, in _parse_args
    return cls._flavour.parse_parts(parts)
  File "/usr/local/Cellar/python/3.6.5/Frameworks/Python.framework/Versions/3.6/lib/python3.6/pathlib.py", line 69, in parse_parts
    parsed.append(sys.intern(rel))
TypeError: can't intern SafeText
>>> pathlib.Path(slugify('foo') + '') # workaround
PosixPath('foo')

The only way to work around this is to use some kind of string operation that will turn it into a native string but that feels like a workaround.

Maybe the problem is not SafeString but rather that django.utils.text.slugify that does return a SafeString instead of a regular string? The builtin slugify filter could still return a safe string?

Change History (5)

comment:1 by Claude Paroz, 7 years ago

Triage Stage: UnreviewedAccepted

I would also question the usage of mark_safe in slugify. I think the only backwards incompatibility would be that the result of adding a SafeString to a slugify() value would not be safe. I don't think it's much of an issue, if it's documented in release notes.

comment:3 by Claude Paroz, 6 years ago

Type: UncategorizedBug

comment:4 by Claude Paroz, 6 years ago

Has patch: set
Owner: nobody removed
Last edited 6 years ago by Claude Paroz (previous) (diff)

comment:5 by Tim Graham, 6 years ago

Summary: django.utils.text.slugify / SafeStringdjango.utils.text.slugify() shouldn't return a SafeString
Triage Stage: AcceptedReady for checkin

comment:6 by Tim Graham <timograham@…>, 6 years ago

Owner: set to Tim Graham <timograham@…>
Resolution: fixed
Status: newclosed

In b004bd62:

Fixed #29412 -- Stopped marking slugify() result as HTML safe.

Note: See TracTickets for help on using tickets.
Back to Top