When changing directory with the OS module , the change is made globally. Is there a way to change directory locally?
EDIT:Yea, sorry . Locally in another thread. The normal chdir changes the working directory over all threads when you use the thread module.
It's not very difficult to write a decorator/context-manager to do this using contextlib2.contextmanager.
import contextlib2
import os
#contextlib2.contextmanager
def restore_chdir(dir_):
orig= os.getcwd()
os.chdir(dir_)
try:
yield
finally:
os.chdir(orig)
You can use this now as:
with restore_chdir('/foo'):
...
or as a function decorator.
You can simply define a function with os module, which can restore the directory.
import os
def func():
original = os.getcwd()
os.chdir("Your Directory Name")
## Do something here
os.chdir(original)
Related
I need to perform an action without changing the global working directory. My case is I have a few folders, and in each, there are a few files. I need to do some computations using those files. Initially, I tried the following:
with os.chdir('/directory'):
...some code needing execution inside
but got AttributeError: __enter__. After reading up online using with seems not to be an option. Therefore I'm looking to find another elegant way of doing so.
I also tried just using os statements like so:
cwd = os.getcwd()
os.chdir('/directory')
..run code inside directory
os.chdir(cwd)
but this is a pain during debugging and seems like a bad practice.
You can write your own context manager to temporarily change the working directory.
import contextlib
#contextlib.contextmanager
def new_cd(x):
d = os.getcwd()
# This could raise an exception, but it's probably
# best to let it propagate and let the caller
# deal with it, since they requested x
os.chdir(x)
try:
yield
finally:
# This could also raise an exception, but you *really*
# aren't equipped to figure out what went wrong if the
# old working directory can't be restored.
os.chdir(d)
with new_cd('/directory'):
...
Consider spawning a subprocess:
import subprocess
subprocess.run(cmd, cwd="/directory")
See https://docs.python.org/3/library/subprocess.html.
You can make your own context manager. This answer is similar #chepner 's, but will still change back the current working directory in case of error.
import contextlib
import os
#contextlib.contextmanager
#temporarily change to a different working directory
def temporaryWorkingDirectory(path):
_oldCWD = os.getcwd()
os.chdir(os.path.abspath(path))
try:
yield
finally:
os.chdir(_oldCWD)
I tested it using this
#test
print(os.getcwd())
with temporaryWorkingDirectory("../"):
print(os.getcwd())
print(os.getcwd())
I'm writing a clean up script from one of our applications and I need a few variables from a python file in a separate directory.
Now normally I would go:
from myfile import myvariable
print myvariable
However this doesn't work for files outside of the directory. I'd like a more targeted solution than:
sys.path.append('/path/to/my/dir)
from myfile import myvariable
As this directory has a lot of other files, unfortunately it doesn't seem like module = __import__('/path/to/myfile.py') works either. Any suggestions. I'm using python 2.7
EDIT, this path is unfortunately a string from os.path.join(latest, "myfile.py")
You can do a more targeted import using the imp module. While it has a few functions, I found the only one that allowed me access to internal variables was load_source.
import imp
import os
filename = 'variables_file.py'
path = '/path_to_file/'
full_path = os.path.join(path_to_file, filename)
foo = imp.load_source(filename, full_path)
print foo.variable_a
print foo.variable_b
...
I want to pass my program a file and get a function out of it.
For example, I have a file, foo.py, who's location is not known until run time (it will be passed to to code by the command line or something like that), can be anywhere on my system and looks like this:
def bar():
return "foobar"
how can I get my code to run the function bar?
If the location was known before run time I could do this:
import sys
sys.path.append("path_to_foo")
import foo
foo.bar()
I could create an init.py file in the folder where foo.py is and use importlib or imp but it seems messy. I can't use __import__ as I get ImportError: Import by filename is not supported.
You could open the file and execute it using exec.
f = open('foo.py')
source = f.read()
exec(source)
print bar()
You could even look for the specific function using re
You can write a dummy function and call it everywhere you need, to bypass checking:
def bar():
pass
at run-time override the function with the one you actually intend to, and automatically everywhere it will be used.
Note: This is more messy than using the importlib.
If foo.py is in the same directory as your main file, you can use
from . import foo
(Python 3). This works because . is the directory of your file, and Python will import files in the same directory for you. You can then use
foo.bar()
If it is not, you need to find it, and then execute it:
import os
from os.path import join
lookfor = "foo.py"
for root, dirs, files in os.walk('C:\\'): # or '/' for Linux / OSX
if lookfor in files:
execfile(join(root, lookfor)) # Python 2, or
with open(join(root, lookfor)) as file:
exec(''.join(file.readlines()))
break
foo.bar()
Credits: Martin Stone. I did not just copy the code, I understand the code, and could've made it myself.
I have put the question in the figure below:
EDIT
The question put next to the figure is:
How do I make script_A1 import a function from script_B2?
Similar questions have been asked before. But most answers suggest to add the module/script/package(whatever) to the PATH variable. For example:
sys.path.append('...')
But adding the module to the PATH variable just feels so wrong. I do not want to alter my system in any way. When my application closes, I want my Python environment to be clean and 'untouched'. I'm afraid that adding uncontrolled modules to the PATH variables on my system will cause headaches later on.
Thank you for helping me out :-)
You can use a trick of adding the top folder to path:
import sys
sys.path.append('..')
import folderB.something
You can also use imp.load_source if you prefer.
I think I solved the issue.
In the following way, you can append the parent directory to the PATH. Put this at the top of script_A1:
import sys
import os
myDir = os.path.dirname(os.path.abspath(__file__))
parentDir = os.path.split(myDir)[0]
if(sys.path.__contains__(parentDir)):
print('parent already in path')
pass
else:
print('parent directory added')
sys.path.append(parentDir)
# Now comes the rest of your script
You can verify that the parent directory myProject is indeed added to the PATH by printing out:
print(sys.path)
Since the parent directory myProject is now part of the PATH, you can import scripts/modules/whatever from any of its subdirectories. This is how you import script_B2 from folder_B:
import folder_B.script_B2 as script_B2
After closing your application, you can verify if your Python environment is restored to its initial state. just print the PATH again and check if the directory you had appended is gone.
Put this at the top of script_A1;
from folderB.script_B2 import YourClass as your_class
shutil.rmtree will not delete read-only files on Windows. Is there a python equivalent of "rm -rf" ? Why oh why is this such a pain?
shutil.rmtree can take an error-handling function that will be called when it has problem removing a file. You can use that to force the removal of the problematic file(s).
Inspired by http://mail.python.org/pipermail/tutor/2006-June/047551.html and http://techarttiki.blogspot.com/2008/08/read-only-windows-files-with-python.html:
import os
import stat
import shutil
def remove_readonly(func, path, excinfo):
os.chmod(path, stat.S_IWRITE)
func(path)
shutil.rmtree(top, onerror=remove_readonly)
(I haven't tested that snippet out, but it should be enough to get you started)
If you import win32api from PyWin32, you can use:
win32api.SetFileAttributes(path, win32con.FILE_ATTRIBUTE_NORMAL)
To make files cease to be read-only.
Another way is to define rmtree on Windows as
rmtree = lambda path: subprocess.check_call(['cmd', '/c', 'rd', '/s', '/q', path])
There's a comment at the ActiveState site that says:
shutil.rmtree has its shortcomings. Although it is true you can use shutil.rmtree() in many cases, there are some cases where it does not work. For example, files that are marked read-only under Windows cannot be deleted by shutil.rmtree().
By importing the win32api and win32con modules from PyWin32 and adding line like "win32api.SetFileAttributes(path, win32con.FILE_ATTRIBUTE_NORMAL" to the rmgeneric() function, this obstacle can be overcome. I used this approach to fix the hot-backup.py script of Subversion 1.4 so it will work under Windows. Thank you for the recipe.
I don't use Windows so can't verify whether this works or not.
This will presumably be fixed with the release of Python 3.5 (currently - June 2015 - still in development) in the sense of giving a hint about this in the documentation.
You can find the bugreport here. And this is the according changeset.
See the newly added example from the Python 3.5 docs:
import os, stat
import shutil
def remove_readonly(func, path, _):
"Clear the readonly bit and reattempt the removal"
os.chmod(path, stat.S_IWRITE)
func(path)
shutil.rmtree(directory, onerror=remove_readonly)
Here is a variant of what Steve posted, it uses the same basic mechanism, and this one is tested :-)
What user do python scripts run as in windows?
I had this issue on Python 3.7 when invoking rmtree() and worked around it by explicitly fixing the permissions before exiting the TemporaryDirectory() context manager. See akaihola/darker#453 for details. Here's a copy of the implementation:
import os
import sys
from pathlib import Path
from typing import Union
WINDOWS = sys.platform.startswith("win")
def fix_py37_win_tempdir_permissions(dirpath: Union[str, Path]) -> None:
"""Work around a `tempfile` clean-up issue on Windows with Python 3.7
Call this before exiting a ``with TemporaryDirectory():`` block or in teardown for
a Pytest fixture which creates a temporary directory.
See discussion in https://github.com/akaihola/darker/pull/393
Solution borrowed from https://github.com/python/cpython/pull/10320
:param dirpath: The root path of the temporary directory
"""
if not WINDOWS or sys.version_info >= (3, 8):
return
for root, dirs, files in os.walk(dirpath):
for name in dirs + files:
path = os.path.join(root, name)
try:
os.chflags(path, 0) # type: ignore[attr-defined]
except AttributeError:
pass
os.chmod(path, 0o700)
and here's how to use it in Pytest unit tests or when creating a temporary directory using tempfile:
import pytest
from my_utils import fix_py37_win_tempdir_permissions
#pytest.fixture
def myfixture(tmp_path):
# setup code here
yield tmp_path
fix_py37_win_tempdir_permissions(tmp_path)
def myfunc():
with TemporaryDirectory() as tmpdir:
# work on the temporary directory here
fix_py37_win_tempdir_permissions(tmp_path)