On 2/11/2022 2:01 PM, Paul Moore wrote:
On Fri, 11 Feb 2022 at 16:37, Christopher Barker <python...@gmail.com> wrote:
On Fri, Feb 11, 2022 at 12:28 AM Serhiy Storchaka <storch...@gmail.com> wrote:
expandvars() does not operate on paths, it operates on strings and
bytestrings. There is nothing path-specific here. Expanding environment
variables consists of three distinct steps:
sure -- but it does live in os.paths now, the docs talk about paths, and it is 
useful for paths -- so it seems a fine idea to have that functionality in 
pathlib.
One way that tying it to paths is bad is that it ignores the path
structure. If environment variable a is "d1/f1" and b is "d2/f2" then
"${a}x${b}" is "d1/f1xd2/f2", which could be very confusing to someone
who sees the value of b and expects the result to be a file in a
directory called d2. Yes, I know that the documentation could make
this clear (the docs in os.path don't, BTW) and I know that it's no
different than the os.path version, but adding an expandvars method to
pathlib feels like throwing good money after bad...

Let's leave it where it is and keep the status quo, or fix it
*properly* and put it somewhere more logical like shlex. Personally I
don't use it that often, so I'm fine with just leaving it alone.

I'd like to see a Path.expandvars(), something like:

--------------------------------------

import os


def _expand_part(part, allow_sep_in_env_var):
    # Expand environment variables in 'part'.  If allow_sep_in_env_var is
    # False, the resulting string cannot contain a path separator.
    s = os.path.expandvars(part)
    if s == part:
        return part
    if not allow_sep_in_env_var and os.path.sep in s:
        raise ValueError(f"expanded variable {part!r} may not contain a path separator")
    return s


def expandvars(path, allow_sep_in_env_var=False):
    return type(path)(
        *list(_expand_part(part, allow_sep_in_env_var) for part in path.parts)
    )


from pathlib import Path

os.environ["USER"] = "foo"
os.environ["a"] = "d1/f1"
os.environ["b"] = "d1/f1"

print(f'{expandvars(Path("/usr/local/bin")) = }')
print(f'{expandvars(Path("/home/${USER}")) = }')
print(f'{expandvars(Path("${a}x${b}"), True) = }')
print(f'{expandvars(Path("${a}x${b}")) = }')

--------------------------------------

Output:

expandvars(Path("/usr/local/bin")) = PosixPath('/usr/local/bin')
expandvars(Path("/home/${USER}")) = PosixPath('/home/foo')
expandvars(Path("${a}x${b}"), True) = PosixPath('d1/f1xd1/f1')
Traceback (most recent call last):
  File "expandpaths.py", line 26, in <module>
    print(f'{expandvars(Path("${a}x${b}")) = }')
  File "expandpaths.py", line 14, in expandvars
    return type(path)(*list(_expand_part(part, allow_sep_in_env_var) for part in path.parts))
  File "expandpaths.py", line 14, in <genexpr>
    return type(path)(*list(_expand_part(part, allow_sep_in_env_var) for part in path.parts))
  File "expandpaths.py", line 10, in _expand_part
    raise ValueError(f'expanded variable {part!r} may not contain a path separator')
ValueError: expanded variable '${a}x${b}' may not contain a path separator

It would no doubt have to do something trickier with forward and back slash detection after the expansion.

Eric

_______________________________________________
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/RQYAAGKGYAVG74X5QCFABKRJBJUL5P35/
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to