Using %systemdrive% in python - python

I would like to open and work with a file with Python however I would like to use Windows %systemdrive% when referring to a file instead of full path.
This piece of code works:
if not os.path.isfile('C:\\Work\\test\sample.txt'):
This does not:
if not os.path.isfile('%systemdrive%\\Work\\test\\sample.txt'):
Any idea? Thank you in advance!

There is a dedicated function for solving this problem named os.path.expandvars.
Return the argument with environment variables expanded. Substrings of
the form $name or ${name} are replaced by the value of environment
variable name. Malformed variable names and references to non-existing
variables are left unchanged.
On Windows, %name% expansions are supported in addition to $name and
${name}.
if not os.path.isfile(os.path.expandvars('%systemdrive%\\Work\\test\\sample.txt')):
pass # do something

You can use os.environ
import os
import os.path
fn = r'{0}\Work\test\sample.txt'.format( os.environ['systemdrive'] )
if not os.path.isfile(fn):
...

Related

Windows Python path.join - The system cannot find the path specified [duplicate]

I believe that running an external command with a slightly modified environment is a very common case. That's how I tend to do it:
import subprocess, os
my_env = os.environ
my_env["PATH"] = "/usr/sbin:/sbin:" + my_env["PATH"]
subprocess.Popen(my_command, env=my_env)
I've got a gut feeling that there's a better way; does it look alright?
I think os.environ.copy() is better if you don't intend to modify the os.environ for the current process:
import subprocess, os
my_env = os.environ.copy()
my_env["PATH"] = "/usr/sbin:/sbin:" + my_env["PATH"]
subprocess.Popen(my_command, env=my_env)
That depends on what the issue is. If it's to clone and modify the environment one solution could be:
subprocess.Popen(my_command, env=dict(os.environ, PATH="path"))
But that somewhat depends on that the replaced variables are valid python identifiers, which they most often are (how often do you run into environment variable names that are not alphanumeric+underscore or variables that starts with a number?).
Otherwise you'll could write something like:
subprocess.Popen(my_command, env=dict(os.environ,
**{"Not valid python name":"value"}))
In the very odd case (how often do you use control codes or non-ascii characters in environment variable names?) that the keys of the environment are bytes you can't (on python3) even use that construct.
As you can see the techniques (especially the first) used here benefits on the keys of the environment normally is valid python identifiers, and also known in advance (at coding time), the second approach has issues. In cases where that isn't the case you should probably look for another approach.
With Python 3.5 you could do it this way:
import os
import subprocess
my_env = {**os.environ, 'PATH': '/usr/sbin:/sbin:' + os.environ['PATH']}
subprocess.Popen(my_command, env=my_env)
Here we end up with a copy of os.environ and overridden PATH value.
It was made possible by PEP 448 (Additional Unpacking Generalizations).
Another example. If you have a default environment (i.e. os.environ), and a dict you want to override defaults with, you can express it like this:
my_env = {**os.environ, **dict_with_env_variables}
you might use my_env.get("PATH", '') instead of my_env["PATH"] in case PATH somehow not defined in the original environment, but other than that it looks fine.
To temporarily set an environment variable without having to copy the os.envrion object etc, I do this:
process = subprocess.Popen(['env', 'RSYNC_PASSWORD=foobar', 'rsync', \
'rsync://username#foobar.com::'], stdout=subprocess.PIPE)
The env parameter accepts a dictionary. You can simply take os.environ, add a key (your desired variable) (to a copy of the dict if you must) to that and use it as a parameter to Popen.
I know this has been answered for some time, but there are some points that some may want to know about using PYTHONPATH instead of PATH in their environment variable. I have outlined an explanation of running python scripts with cronjobs that deals with the modified environment in a different way (found here). Thought it would be of some good for those who, like me, needed just a bit more than this answer provided.
In certain circumstances you may want to only pass down the environment variables your subprocess needs, but I think you've got the right idea in general (that's how I do it too).
This could be a solution :
new_env = dict([(k,(':'.join([env[k], v]) if k in env else v)) for k,v in os.environ.items()])

Setting environment variables when calling Linux commands from Python [duplicate]

I believe that running an external command with a slightly modified environment is a very common case. That's how I tend to do it:
import subprocess, os
my_env = os.environ
my_env["PATH"] = "/usr/sbin:/sbin:" + my_env["PATH"]
subprocess.Popen(my_command, env=my_env)
I've got a gut feeling that there's a better way; does it look alright?
I think os.environ.copy() is better if you don't intend to modify the os.environ for the current process:
import subprocess, os
my_env = os.environ.copy()
my_env["PATH"] = "/usr/sbin:/sbin:" + my_env["PATH"]
subprocess.Popen(my_command, env=my_env)
That depends on what the issue is. If it's to clone and modify the environment one solution could be:
subprocess.Popen(my_command, env=dict(os.environ, PATH="path"))
But that somewhat depends on that the replaced variables are valid python identifiers, which they most often are (how often do you run into environment variable names that are not alphanumeric+underscore or variables that starts with a number?).
Otherwise you'll could write something like:
subprocess.Popen(my_command, env=dict(os.environ,
**{"Not valid python name":"value"}))
In the very odd case (how often do you use control codes or non-ascii characters in environment variable names?) that the keys of the environment are bytes you can't (on python3) even use that construct.
As you can see the techniques (especially the first) used here benefits on the keys of the environment normally is valid python identifiers, and also known in advance (at coding time), the second approach has issues. In cases where that isn't the case you should probably look for another approach.
With Python 3.5 you could do it this way:
import os
import subprocess
my_env = {**os.environ, 'PATH': '/usr/sbin:/sbin:' + os.environ['PATH']}
subprocess.Popen(my_command, env=my_env)
Here we end up with a copy of os.environ and overridden PATH value.
It was made possible by PEP 448 (Additional Unpacking Generalizations).
Another example. If you have a default environment (i.e. os.environ), and a dict you want to override defaults with, you can express it like this:
my_env = {**os.environ, **dict_with_env_variables}
you might use my_env.get("PATH", '') instead of my_env["PATH"] in case PATH somehow not defined in the original environment, but other than that it looks fine.
To temporarily set an environment variable without having to copy the os.envrion object etc, I do this:
process = subprocess.Popen(['env', 'RSYNC_PASSWORD=foobar', 'rsync', \
'rsync://username#foobar.com::'], stdout=subprocess.PIPE)
The env parameter accepts a dictionary. You can simply take os.environ, add a key (your desired variable) (to a copy of the dict if you must) to that and use it as a parameter to Popen.
I know this has been answered for some time, but there are some points that some may want to know about using PYTHONPATH instead of PATH in their environment variable. I have outlined an explanation of running python scripts with cronjobs that deals with the modified environment in a different way (found here). Thought it would be of some good for those who, like me, needed just a bit more than this answer provided.
In certain circumstances you may want to only pass down the environment variables your subprocess needs, but I think you've got the right idea in general (that's how I do it too).
This could be a solution :
new_env = dict([(k,(':'.join([env[k], v]) if k in env else v)) for k,v in os.environ.items()])

How do I execute all the code inside a python file?

How do I execute all the code inside a python file so I can use def's in my current code? I have about 100 scripts that were all written like the script below.
For a simple example, I have a python file called:
D:/bt_test.py
His code looks like this:
def bt_test():
test = 2;
test += addFive(test)
return(test)
def addFive(test):
return(test+5)
Now, I want to from a completely new file, run bt_test()
I've tried doing this:
def openPyFile(script):
execfile(script)
openPyFile('D:/bt_test.py')
bt_test()
But this doesn't work.
I've tried doing this as well:
sys.path.append('D:/')
def openPyFile(script):
name = script.split('/')[-1].split('.')[0]
command = 'from ' + name + ' import *'
exec command
openPyFile('D:/bt_test.py')
bt_test()
Does anyone know why this isn't working?
Here's a link to a quicktime video that will help explain what's happening.
https://dl.dropbox.com/u/1612489/pythonHelp.mp4
You should put those files somewhere on your Python path, and then import them. That's what the import statement is for. BTW: the same directory as your main program is on the Python path, that could be a good place to put them.
# Find and execute bt_test.py, and make a module object of it.
import bt_test
# Use the bt_test function in the bt_test module.
bt_test.bt_test()
The reason that execfile doesn't work is because the functions inside bt_test are limited by the scope of the openPyFile function. One simple test would be to try to run bt_test() from inside openPyFile. Since openPyFile doesn't really do anything other than execfile you could get rid of it altogether, or you could alias execfile
openPyFile=execfile
Note putting the file in your python path and importing it is definitely your best bet -- I only post this answer here to hopefully point out why you're not seeing what you want to see.
In addition to Ned's answer, __import__() might be useful if you don't want the file names hardcoded.
http://docs.python.org/library/functions.html#__import__
Update based on the video.
I don't have access to Maya, but i can try and speculate.
cmds.button(l='print', c='bt_press()') is where the issue seems to lurk. bt_press() is passed as a string object, and whatever way the interpreter uses to resolve that identifier doesn't look in the right namespace.
1) Try passing bt_press() with the module prepended: cmds.button(l='print', c='bt_test.bt_press()')
2) See if you can bind c directly to the function object: cmds.button(l='print', c=bt_press)
Good luck.
>>> from bt_test import bt_test
>>> bt_test()

os.path.basename works with URLs, why?

>>> os.path.basename('http://example.com/file.txt')
'file.txt'
.. and I thought os.path.* work only on local paths and not URLs? Note that the above example was run on Windows too .. with similar result.
In practice many functions of os.path are just string manipulation functions (which just happen to be especially handy for path manipulation) -- and since that's innocuous and occasionally handy, while formally speaking "incorrect", I doubt this will change anytime soon -- for more details, use the following simple one-liner at a shell/command prompt:
$ python -c"import sys; import StringIO; x = StringIO.StringIO(); sys.stdout = x; import this; sys.stdout = sys.__stdout__; print x.getvalue().splitlines()[10][9:]"
Or, for Python 3:
$ python -c"import sys; import io; x = io.StringIO(); sys.stdout = x; import this; sys.stdout = sys.__stdout__; print(x.getvalue().splitlines()[10][9:])"
On windows, look at the source code: C:\Python25\Lib\ntpath.py
def basename(p):
"""Returns the final component of a pathname"""
return split(p)[1]
os.path.split (in the same file) just split "\" (and sth. else)
Beware of URLs with parameters, anchors or anything that isn't a "plain" URL:
>>> import os.path
>>> os.path.basename("protocol://fully.qualifie.host/path/to/file.txt")
'file.txt'
>>> os.path.basename("protocol://fully.qualifie.host/path/to/file.txt?param1&param1#anchor")
'file.txt?param1&param1#anchor'
Use the source Luke:
def basename(p):
"""Returns the final component of a pathname"""
i = p.rfind('/') + 1
return p[i:]
Edit (response to clarification):
It works for URLs by accident, that's it. Because of that, exploiting its behaviour could be considered code smell by some.
Trying to "fix" it (check if passed path is not url) is also surprisingly difficult
www.google.com/test.php
me#other.place.com/12
./src/bin/doc/goto.c
are at the same time correct pathnames and URLs (relative), so is the http:/hello.txt (one /, and only on linux, and it's kinda stupid :)). You could "fix" it for absolute urls but relative ones will still work. Handling one special case in differently is a big no no in the python world.
To sum it up: import this
Forward slash is also an acceptable path delimiter in Windows.
It is merely that the command line does not accept paths that begin with a / because that character is reserved for args switches.
Why? Because it's useful for parsing URLs as well as local file paths. Why not?

Python: Platform independent way to modify PATH environment variable

Is there a way to modify the PATH environment variable in a platform independent way using python?
Something similar to os.path.join()?
You should be able to modify os.environ.
Since os.pathsep is the character to separate different paths, you should use this to append each new path:
os.environ["PATH"] += os.pathsep + path
or, if there are several paths to add in a list:
os.environ["PATH"] += os.pathsep + os.pathsep.join(pathlist)
As you mentioned, os.path.join can also be used for each individual path you have to append in the case you have to construct them from separate parts.
Please note that os.environ is not actually a dictionary. It's a special dictionary-like object which actually sets environment variables in the current process using setenv.
>>> os.environ.__class__
<class os._Environ at 0x100472050>
>>> import os
>>> os.environ["HELLO"] = "WORLD"
>>> os.getenv("HELLO")
'WORLD'
This means that PATH (and other environment variables) will be visible to C code run in the same process.
(Since comments can't contain formatting, I have to put this in an answer, but I feel like it's an important point to make. This is really a comment on the comment about there being no equivalent to 'export'.)
The caveat to be aware of with modifying environment variables in Python, is that there is no equivalent of the "export" shell command. There is no way of injecting changes into the current process, only child processes.
You could refresh it like this
os.environ["PATH"] = os.environ["PATH"]

Categories