Repository navigation
Forbid shlex.quote returning a quoted empty string (”””) for falsey non-str data #149280
Description
Activity
- addedtype-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error
on May 2, 2026 - addedstdlibStandard Library Python modules in the Lib/ directoryStandard Library Python modules in the Lib/ directorytype-featureA feature request or enhancementA feature request or enhancementand removedtype-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error
on May 2, 2026 - changed the title
[-]shlex.quote returns a quoted empty string (`”””`) for falsey non-`str` data[/-][+]Forbid shlex.quote returning a quoted empty string (`”””`) for falsey non-`str` data[/+]on May 2, 2026 I think I was the one who suggested raising the TypeError explicitly because I wanted to prevent exceptions types changing, not because I wanted to preserve the None -> "" behavior (if I said so, though, I was wrong then: ideally, we should avoid changing raised exceptions).
I can think of people doing
list(map(shlex.quote, ...))and by chance, there is an item that is an empty list, and instead of having, say, no argument at all, you end up with some quoted argument. So, I would suggest deprecating non-string because the docs say:Return a shell-escaped version of the string s. The returned value is a string that can safely be used as one token in a shell command line, for cases where you cannot use a list.
Yeah I guess the explicit raising of
TypeError, implemented in #138809 (addressing #138804), was the correct thing to do to keep things consistent, but it leads to a weird situation whereshlex.quotelooks like it is intended to work for falsey non-str data, egNone. It's worked for falsey data since before and after both #138809 (raiseTypeError) and #132036 (PR which causedAttributeErroretc instead ofTypeError).The manual raising of
TypeErrorwas just about making the type of exception raised for data of an incorrect type consistent between versions. The behavior ofquotefor falsey non-str data is just an artefact of not wanting to break compatibility, not purposely trying to permit a special case.It was this review post of #138809 that decided to not raise
TypeErrorfor falsey data as it would be a breaking change, but it does make one think: now that we have the type check, should it come before the special case, and deprecate falsey non-str data being treated nicely? I can take it or leave it 😅 :I gave a couple of examples in the discussion of why we may or may not want to treat
None->"''"as a feature rather than a bug lest we break existing workflows, albeit that we don't currently and shouldn't in the future encourage it in the docs.
For the record:
Tag and comparison for the deprecation route.
Tag and comparison for the hard-break route, though I wouldn't recommend this version; we're better deprecating than breaking. The deprecation tag is based off of this one.
Metadata
Metadata
Assignees
Labels
Projects
- StatusShow more project fieldsNo status
Bug report
Bug description:
Full discussion and history of the bug is on discuss.python.org.
tldr:
shlex.quote's opening check for the empty string as a special case is still placed before theisinstancetype check. This is intentional as when theisinstancecheck was added, the patch was intended to not break compatibility with eg people expectingshlex.quote(None)to return"''", implicitly coercingNoneto the empty string""and then quoting it as"''".We think either of the following is a best course of action:
DeprecationWarningwhen one callsquoteon falsey non-strdataOr we could do a hard-break and just swap the order of the
isinstanceandif not schecks around, which would break anybody relying onNone -> "''"(not recommended!).I have a couple of git tags that I will link below with reference implementation for 'fixing' this issue (if it needs to be fixed). I just need the
gh-number of this issue first for the blurb entries.CPython versions tested on:
CPython main branch
Operating systems tested on:
No response