Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python 3 backward compatability (shlex.quote vs pipes.quote)

One of my projects uses shlex.quote which is available since python 3.3. But that shlex.quote is the same as pipes.quote which is deprecated after moving to shlex.

Now for compatibility I am using this code:

def cmd_quote(string):
    import sys
    if int(sys.version[2]) < 3:
        import pipes
        return pipes.quote(string)
    else:
        import shlex
        return shlex.quote(string)

Are any better practices exists?

like image 332
Victor Polevoy Avatar asked Nov 06 '14 22:11

Victor Polevoy


1 Answers

First, if you want to do numerical comparisons against version, use version_info, don't try to parse the string in version.*

This also means you can take advantage of the way tuples are compared and write code like:

if sys.version_info < (3, 3):

… and it won't break if Python gets to 3.10.0 or 4.0 ever come out.

* Unless you need to worry about 1.5 vs. 2.0, in which case you've obviously got a time-machine gatewaying between Usenet and StackOverflow, and surely you can think of better uses for that.


Anyway, it's probably better to just test for shlex.quote existing in the first place. That way, it's obvious to the reader what you're doing: using shlex.quote if possible, falling back to pipes.quote if not.

You'll see that pattern all over the place—even in the stdlib, where code is imported from C accelerator modules if possible, but fallback code is used if not (e.g., if you're using PyPy instead of CPython).


Also, note that pipes.quote is only documented in 2.7. Not 3.0-3.2 (which is what it seems like you care about…), or 2.6, or any other version. You're relying on something that happens to be there in a particular implementation. (Well, practically, in all of them,* but still, why rely on that if you don't have to?)

* As far as I know, there aren't any 3.2 implementations that have pipes and shlex but don't have pipes.quote. And there probably won't be too many new 3.2 implementations created in the future.


Also, while it can occasionally be useful to import in the middle of a function, it's kind of a weird thing to do. If there's a problem with the installation on a machine you deploy this on, would you really expect to be able to import your module successfully, but then later get an ImportError on calling some function? That's the kind of thing people get baffled by and run to SO for help with all the time. :) (It's also obviously a bit of a performance hit to do all this looking in sys.modules and converting strings to ints and so on when you don't need to, but I doubt that's going to matter.)


So, I think the way I'd write it would be:

try:
    from shlex import quote as cmd_quote
except ImportError:
    from pipes import quote as cmd_quote
like image 87
abarnert Avatar answered Sep 20 '22 12:09

abarnert