Python - handling windows path with '\' characters

Hi,
I’ve been struggling with windows path for a while because of Python regex.

When I need my user to input a path variable in a tool, if they give a classical windows path Python will convert ‘’ because of regex. os.path.normpath don’t seem to work.

path = 'L:\sandbox\20_lookdev\10_asset\character\assetName\model\scenes\publish'
os.path.normpath(path)
>>>> 'L:\\sandbox\x10_lookdev\x08_asset\\character\x07ssetName\\model\\scenes\\publish' #

I modified the function ‘rawString’ found on the internet which is supposed to clean those nasty ‘’, but it works randomly:

def slashPath(path):
    """
    param: str file path
    return: str file path with "\\" replaced by '/' 
    """
    path = rawString(path)
    raw_path = r"{}".format(path)
    separator = os.path.normpath("/")
    changeSlash = lambda x: '/'.join(x.split(separator))

    if raw_path.startswith('\\'):
        return '/' + changeSlash(raw_path)
    else:
        return changeSlash(raw_path)


def rawString(strVar):
    """Returns a raw string representation of strVar.
    Will replace '\\' with '/'
    :param: str String to change to raw
    """
    if type(strVar) is str:
        strVarRaw = r'%s' % strVar

        new_string=''
        escape_dict={'\a':r'\a', '\b':r'\b', '\c':r'\c', '\f':r'\f', '\n':r'\n',
                    '\r':r'\r', '\t':r'\t', '\v':r'\v', '\'':r'\'', '\"':r'\"',
                    '\0':r'\0', '\1':r'\1', '\2':r'\2', '\3':r'\3', '\4':r'\4',
                    '\5':r'\5', '\6':r'\6', '\7':r'\7', '\8':r'\8', '\9':r'\9'}
        for char in strVarRaw:
            try: new_string+=escape_dict[char]
            except KeyError: new_string+=char
        return new_string
    else:
        return strVar

But same problem:

slashPath(path)
>>>> 'L:/sandbox\x10_lookdev/b_asset/character/7ssetName/model/scenes/publish'

Does anyone know how we are supposed to work with those path? I’m searching for a solution that works 100% of the time.

Thanks

How are you gathering the path from the user? It may be better to attack this problem at the source instead of downstream. Capturing the path as a raw string or using pathlib (if you’re on a version of Python that supports it) may help.

I think that’s the problem: the path will definitly be usable if the string is created as raw, but once created it’s impossible to change back. It’s pretty easy to deal with when you are creating an UI (just take the string as raw when the user input it), but when I have to query existing path (let’s say through Shotgun API) I always get problems.

Maybe one solution would be to create a function which inverts what regex \ do?

Ok, I think there’s some confusion to what a raw string is since you found a function called rawString.
Python has a built-in raw string literal where you put the letter r in front of your opening quote, and then none of the backslashes (with some small exceptions) are interpreted, like so:
path = r'L:\sandbox\20_lookdev\10_asset\character\assetName\model\scenes\publish'
After that, you can just use path.replace(os.sep, '/') to change to forward slashes if you need.

If you are reading paths from some api as text through code, you should be getting the backslash character directly, so this shouldn’t be a problem. If you’re copy-pasting the paths (without the r), or using one of the python exec-ish functions, then those backslashes will get re-interpreted as escape characters, and you’re gonna have a bad time.

When you’re getting the paths from the shotgun api, how exactly are you doing that? My best guess is that’s where the problem lies.

I’ve been self learning Python, there are probably some confusion there!
Shotgun API was a bad exemple actually, I imagined the case when I want to query a path inputed by a user (basically he would just copy and paste his path) but I did not test this.

Let’s imagine I create a window in maya with a text input: will Python query the text as a raw string?

Thanks for your answers!

Not a problem at all! A good rule of thumb is that backslashes only behave strangely when they’re part of code, not when they’re part of the input. Of course there are special cases, but it’s a good start.

So, typing path = 'string\with\backslashes' into a python interpreter or file means those backslashes behave as escape characters because that whole thing is a line of python code. That means you get to choose to use r'' style string if you don’t want the escape behavior.

However, if you get some kind of input, by using raw_input(), or a UI, or an API call, then what they typed is exactly what you get.

1 Like

It clears up the confusion! Thanks for those explanations.

Just a headsup:
If working with Maya.cmds then your UI controls will return raw strings when you query things like fields.
But if you work with PyMEL you need to be vary, as you get unicode strings: u’someString’ instead of r’someString’

Maya will also return unicode strings when it actually contains unicode characters.
And as we roll into the eventually python3 universe, we shouldn’t be dealing with bytes nearly as often, and if we are, then we need to push back on autodesk to actually handle it properly.

You can try the replace method, like this:
path = ‘L:\sandbox\20_lookdev\10_asset\character\assetName\model\scenes\publish’

path.replace(’\’,’/’) # The first parameter has two slashes, so I don’t know why it only shows one

results:
L:/sandbox_lookde_asset/characterssetName/model/scenes/publish

I usually use this one, there are no exceptions

path.replace('\', '/') actually won’t work, you need to escape the backslash so instead you’d use path.replace('\\', '/').
But really both of those aren’t optimal. Instead you should use the already defined constants in the os module, so path.replace(os.pathsep, os.altsep) will ensure you get forward slashes no matter what platform you’re writing code for, and path.replace(os.sep, os.altsep) will get you backslashes on windows and forward slashes on POSIX systems.

1 Like

Aha! I have never used that method you mentioned before, but I think what you said makes sense. It seems very rigorous. I prefer it. Thank you, I learned another knowledge ^^~

Hey, I think using os.pathsep is wrong there. That one’s a semicolon on windows, and a colon on linux.

BenWall asked about Windows~

You are correct, I meant os.sep this is what I get for posting tired.

we use a modifed verison of pypi.org/project/path/, which I altered to always return unix style paths. Users can enter whatever slashes they want into my guis, or lists can be generated with windows slashes, but the strings get converted to Path() objects and the value always comes out unix.

our legacy code uses a lot string replacements, though.

If you’re interested in using a path library.


provides a backport of the standard libraries pathlib module that they introduced in 3.4 I think?

I’ve been using this for the past months:

import os

import re

def slashPath(path):

    """

    param: str file path

    return: str file path with "\\" replaced by '/' 

    """

    path = rawString(path)

    raw_path = r"{}".format(path)

    separator = os.path.normpath("/")

    changeSlash = lambda x: '/'.join(x.split(separator))

    if raw_path.startswith('\\'):

        return '/' + changeSlash(raw_path)

    else:

        return changeSlash(raw_path)

def rawString(strVar):

    """Returns a raw string representation of strVar.

    Will replace '\\' with '/'

    :param: str String to change to raw

    """

    if type(strVar) is str:

        strVarRaw = r'%s' % strVar

        new_string=''

        escape_dict={'\a':r'\a', '\b':r'\b', '\c':r'\c', '\f':r'\f', '\n':r'\n',

                    '\r':r'\r', '\t':r'\t', '\v':r'\v', '\'':r'\'', '\"':r'\"',

                    '\0':r'\0', '\1':r'\1', '\2':r'\2', '\3':r'\3', '\4':r'\4',

                    '\5':r'\5', '\6':r'\6', '\7':r'\7', '\8':r'\8', '\9':r'\9'}

        for char in strVarRaw:

            try: new_string+=escape_dict[char]

            except KeyError: new_string+=char

        return new_string

    else:

        return strVar

slashPath(path) will always give a path with ‘/’ as sep.