I have a little problem with ~ in my paths.
This code example creates some directories called ~/some_dir and do not understand that I wanted to create some_dir in my home directory.
my_dir = "~/some_dir"
if not os.path.exists(my_dir):
os.makedirs(my_dir)
Note this is on a Linux-based system.
You need to expand the tilde manually:
my_dir = os.path.expanduser('~/some_dir')
The conversion of ~/some_dir to $HOME/some_dir is called tilde expansion and is a common user interface feature. The file system does not know anything about it.
In Python, this feature is implemented by os.path.expanduser:
my_dir = os.path.expanduser("~/some_dir")
That's probably because Python is not Bash and doesn't follow same conventions. You may use this:
homedir = os.path.expanduser('~')
Related
python has recently added the pathlib module (which i like a lot!).
there is just one thing i'm struggling with: is it possible to normalize a path to a file or directory that does not exist? i can do that perfectly well with os.path.normpath. but wouldn't it be absurd to have to use something other than the library that should take care of path related stuff?
the functionality i would like to have is this:
from os.path import normpath
from pathlib import Path
pth = Path('/tmp/some_directory/../i_do_not_exist.txt')
pth = Path(normpath(str(pth)))
# -> /tmp/i_do_not_exist.txt
but without having to resort to os.path and without having to type-cast to str and back to Path. also pth.resolve() does not work for non-existing files.
is there a simple way to do that with just pathlib?
is it possible to normalize a path to a file or directory that does not exist?
Starting from 3.6, it's the default behavior. See https://docs.python.org/3.6/library/pathlib.html#pathlib.Path.resolve
Path.resolve(strict=False)
...
If strict is False, the path is resolved as far as possible and any remainder is appended without checking whether it exists
As of Python 3.5: No, there's not.
PEP 0428 states:
Path resolution
The resolve() method makes a path absolute, resolving
any symlink on the way (like the POSIX realpath() call). It is the
only operation which will remove " .. " path components. On Windows,
this method will also take care to return the canonical path (with the
right casing).
Since resolve() is the only operation to remove the ".." components, and it fails when the file doesn't exist, there won't be a simple means using just pathlib.
Also, the pathlib documentation gives a hint as to why:
Spurious slashes and single dots are collapsed, but double dots ('..')
are not, since this would change the meaning of a path in the face of
symbolic links:
PurePath('foo//bar') produces PurePosixPath('foo/bar')
PurePath('foo/./bar') produces PurePosixPath('foo/bar')
PurePath('foo/../bar') produces PurePosixPath('foo/../bar')
(a naïve approach would make PurePosixPath('foo/../bar') equivalent to PurePosixPath('bar'), which is wrong if foo is a symbolic link to another directory)
All that said, you could create a 0 byte file at the location of your path, and then it'd be possible to resolve the path (thus eliminating the ..). I'm not sure that's any simpler than your normpath approach, though.
If this fits you usecase(e.g. ifle's directory already exists) you might try to resolve path's parent and then re-append file name, e.g.:
from pathlib import Path
p = Path()/'hello.there'
print(p.parent.resolve()/p.name)
Old question, but here is another solution in particular if you want POSIX paths across the board (like nix paths on Windows too).
I found pathlib resolve() to be broken as of Python 3.10, and this method is not currently exposed by PurePosixPath.
What I found worked was to use posixpath.normpath(). Also found PurePosixPath.joinpath() to be broken. I.E. It will not join ".." with "myfile.txt" as expected. It will return just "myfile.txt". But posixpath.join() works perfectly; will return "../myfile.txt".
Note this is in path strings, but easily back to pathlib.Path(my_posix_path) et al for an OOP container.
And easily transpose to Windows platform paths too by just constructing this way, as the module takes care of the platform independence for you.
Might be the solution for others with Python file path woes..
I have a script in Python which i get 3 arguments from the user
One of the arguments is a folder path in which there are some files i need to use
Since my program is designed for all OS, i would like to know how to use the path from the argument correctly to get to my required files
I.E.
if i get the following path :
c:\windows
i would like to be able to get 1.exe in this folder,
In windows it will be slash or backslash but in unix systems it will be probably different,
As i understand there is a const or defined var from 'os' module in which i can use as this subdir sign, where can i find it ?
Thank you
Just use os.path.join and Python will take care of the slash for you:
path = os.path.join(sys.argv[1], '1.exe')
The platform-specific path separator is stored as os.sep.
Use os.path.join(). For example:
os.path.join(dirname, "1.exe")
I have a directory structure like this:
--bin/
--lib/
--data/
So basically, the executable script is in bin and it calls the files in lib.. but lib has to communicate with the text files in data
Usually this use to work:
TO read a file in usually i use to do this
file_path = os.path.join(os.path.dirname(__file__))+ "/../" +"data/"+filename
f = open(file_path,"r")
But, in this instance, if i do:
print os.path.join(os.path.dirname(__file__))
returns nothing?
What am i doing wrong..
Thanks
I guess with nothing you mean an empty string? This could only be the case, if __file__ was an empty string in the first place. Did you accidentally overwrite __file__?
One other comment in addition to the others...the point of os.path.join is to avoid things like
mypath=dir + '/' + subdir + '/'+filename
This is done much more cleanly using
mypath=os.path.join(dir,subdir,filename) # can have as many arguments as you want!
Also, you can avoid explicit '..' and '.' in path names by using os.pardir and os.curdir. (e.g.)
file_path = os.path.join(os.path.dirname(__file__),os.pardir,'data',filename)
This should increase the portability of your code (and is a good habit to get into even if you don't plan on running this script anywhere else).
It depends on how you start your script, for example:
if /bin/script.py contains:
import os
print os.path.dirname(__file__) #no reason to use os.path.join()
then:
$> python /bin/script.py
/bin
$> cd /bin
$> python script.py
#nothing
$>
It'a a better idea to use the following:
file_path = os.path.abspath(__file__)
and then do whatever you want with that.
Using Python, how does one parse/access files with Linux-specific features, like "~/.mozilla/firefox/*.default"? I've tried this, but it doesn't work.
Thanks
This
import glob, os
glob.glob(os.path.expanduser('~/.mozilla/firefox/*.default'))
will give you a list of all files ending in ".default" in the current user's ~/.mozilla/firefox directory using os.path.expanduser to expand the ~ in the path and glob.glob to match the *.default file pattern.
~ is expanded by the shell and not a real path. As such you have to navigate there manually.
import os
homeDir = os.environ['HOME']
f = open( homeDir + '/.mozilla/firefox/*.default' )
# ...
It's important to remember:
use of the tilde ~ expands the home directory as per Poke's answer
use of the forward slash / is the separator for linux / *nix directories
by default, *nix systems such as linux for example has a wild card globbing in the shell, for instance echo *.* will return back all files that match the asterisk dot asterisk (as per Will McCutcheon's answer!)
http://docs.python.org/library/os.html
Gives a complete reference if you would like to change directory or give paths.
You can for example give relative paths and access specific files.
If you would like to execute commands then http://docs.python.org/library/commands.html provides nice wrappers for the os.popen() function
Hey. I've got a project in Python, whose directory layout is the following:
root
|-bin
|-conf
|-[project]
Python files in [project] need to be able to read configuration data from the 'conf' directory, but I cannot guarantee the location of root, plus it may be used on both Linux, Mac and Windows machines so I am trying to relatively address the conf directory from the root directory.
At the minute it's working with a dirty hack (from root/bin, particular python filename is 8 chars long):
path = os.path.abspath(__file__)[:-8]
os.chdir(path)
os.chdir("..")
[projectclass].config('config/scans.json') #for example
But this is particularly horrid and is giving me nightmares. Is there a better way to accomplish what I'm trying to achieve that doesn't feel so dirty? I feel like I'm missing something very obvious. Thanks in advance.
Instead of:
path = os.path.abspath(__file__)[:-8]
use:
path = os.path.dirname(os.path.abspath(__file__))
See the docs here.