Reputation: 359905
How can I protect against Python's os.path.expandvars()
treatment of null/unset environment variables?
From os.path:
Malformed variable names and references to non-existing variables are left unchanged.
>>> os.path.expandvars('$HOME/stuff')
'/home/dennis/stuff'
>>> os.path.expandvars('foo/$UNSET/bar')
'foo/$UNSET/bar'
I could perform this step separately from other path processing (expanduser()
, realpath(),
normpath()
, etc.) instead of chaining them all together and check to see if the result is unchanged, but that is normal when there are no variables present - so I would also have to parse the string to see if it has any variables. I fear that may not be robust enough.
The issue comes into play when creating a file using the result. I end up with a file with the variable name as a literal part of the file's name. I want to instead reject the input with an exception.
Upvotes: 2
Views: 790
Reputation: 3511
Extending on Jason's:
def expand_user_vars(s, variants='$%s ${%s} %%%s%%'):
'''Return a string expanded for both leading "~/" or "~username/" and
environment variables in the forms given by variants.
>>> s = "~roland/.local/%XYZ%$XYZ${XYZ}"
>>> expand_user_vars(s)
'/home/roland/.local/'
>>> s = "$HOME/.local/%XYZ%$XYZ${XYZ}"
>>> expand_user_vars(s)
'/home/roland/.local/'
>>> s = "$EDITOR"
>>> 'EDITOR' not in expand_user_vars(s)
True
'''
s = os.path.expanduser(s)
#python2 does not have KeyError in str(e)
remx = re.compile(r"(?:KeyError:)?\s*'(\w+)'")
while True:
try:
s = string.Template(s).substitute(os.environ)
break
except KeyError as e:
reme = str(e)
remxo = remx.match(reme)
if remxo:
g1 = remxo.group(1)
for v in variants.split():
s = s.replace(v%g1,'')
continue
return s
Else, echo
is there on Linux and MacOS and Windows.
Replace below example with ...'echo '+s...
:
import subprocess
netrc_file = subprocess.check_output('echo ${NETRC:-~/.netrc}',shell=True)
Upvotes: 0
Reputation: 13779
You could use string.Template
, which uses a similar dollar-sign syntax for interpolation of variables but will raise KeyError
if something doesn't exist rather than leaving it in.
import os
from string import Template
print(Template('$HOME/stuff').substitute(os.environ))
Upvotes: 4