under Linux I put my configs in "~/.programname". Where should I place it in windows?
What would be the recommendated way of opening the config file OS independent in python?
Thanks!
Nathan
On Windows, you store it in os.environ['APPDATA']. On Linux, however, it's now recommended to store config files in os.environ['XDG_CONFIG_HOME'], which defaults to ~/.config. So, for example, building on JAB's example:
if 'APPDATA' in os.environ:
confighome = os.environ['APPDATA']
elif 'XDG_CONFIG_HOME' in os.environ:
confighome = os.environ['XDG_CONFIG_HOME']
else:
confighome = os.path.join(os.environ['HOME'], '.config')
configpath = os.path.join(confighome, 'programname')
The XDG base directory standard was created so that configuration could all be kept in one place without cluttering your home directory with dotfiles. Most new Linux apps support it.
Some improvements over LeadStorm's great answer:
Code can be simpler using os.environ.get() and short-circuiting or:
configpath = os.path.join(
os.environ.get('APPDATA') or
os.environ.get('XDG_CONFIG_HOME') or
os.path.join(os.environ['HOME'], '.config'),
"programname"
)
Additionally, if you're willing to use the external libraries, xdg package can make things even easier on Linux and Mac:
import xdg.BaseDirectory as xdg
configpath = os.path.join(os.environ.get('APPDATA') or xdg.xdg_config_home,
"programname")
But this only solves part of your problem: you still need to create that directory if it does not exists, right?
On Windows, you're on your own. But on Linux and Mac, xdg.save_config_path() do os.path.join() for you, and create the directory with appropriate permissions, if needed, and return its path, all in a single step. Awesome!
if 'APPDATA' in os.environ:
configpath = os.path.join(os.environ['APPDATA'], "programname")
os.makedirs(configpath, exist_ok=True)
else:
configpath = xdg.save_config_path("programname")
Try:
os.path.expanduser('~/.programname')
On linux this will return:
>>> import os
>>> os.path.expanduser('~/.programname')
'/home/user/.programname'
On windows this will return:
>>> import os
>>> os.path.expanduser('~/.programname')
'C:\\Documents and Settings\\user/.programname'
Which is a little ugly, so you'll probably want to do this:
>>> import os
>>> os.path.join(os.path.expanduser('~'), '.programname')
'C:\\Documents and Settings\\user\\.programname'
EDIT: For what it's worth, the following apps on my Windows machine create their config folders in my Documents and Settings\user folder:
Android
AgroUML
Gimp
IPython
EDIT 2: Oh wow, I just noticed I put /user/.programname instead of /home/user/.programname for the linux example. Fixed.
My approach when using Python's Pathlib library:
config = environ.get('APPDATA') or environ.get('XDG_CONFIG_HOME')
config = Path(config) if config else Path.home() / ".config"
Generally, configuration and data files for programs on Windows go in the %APPDATA% directory (or are supposed to), usually in a subdirectory with the name of the program. "%APPDATA%", of course, is just an environment variable that maps to the current user's Application Data folder. I don't know if it exists on Linux (though I assume it doesn't), so to do it across platforms (Windows/Linux/MacOS)...
import os
if 'APPDATA' in os.environ.keys():
envar = 'APPDATA'
else:
envar = 'HOME'
configpath = os.path.join(os.environ[envar], '.programname')
Related
How can I get the path to the %APPDATA% directory in Python?
import os
print os.getenv('APPDATA')
You may use os.path.expandvars(path):
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}.
This comes handy when combining the expanded value with other path components.
Example:
from os import path
sendto_dir = path.expandvars(r'%APPDATA%\Microsoft\Windows\SendTo')
dumps_dir = path.expandvars(r'%LOCALAPPDATA%\CrashDumps')
Although the question clearly asks about the Windows-specific %APPDATA% directory, perhaps you have ended up here looking for a cross-platform solution for getting the application data directory for the current user, which varies by OS.
As of Python 3.11, somewhat surprisingly, there is no built-in function to find this directory. However, there are third-party packages, the most popular of which seems to be appdirs, which provides functions to retrieve paths such as:
user data dir (user_data_dir)
user config dir (user_config_dir)
user cache dir (user_cache_dir)
site data dir (site_data_dir)
site config dir (site_config_dir)
user log dir (user_log_dir)
You can try doing:
import os
path = os.getenv('APPDATA')
array = os.listdir(path)
print array
You can use module called appdata. It was developed to get access to different paths for your application, including app data folder. Install it:
pip install appdata
And after that you can use it this way:
from appdata import AppDataPaths
app_paths = AppDataPaths()
app_paths.app_data_path # for your app data path
app_paths.logs_path # for logs folder path for your application
It allows to to get not only app data folder and logs folder but has other features to manage paths like managing config files paths. And it's customizable.
Links:
Read the Docs - documentation.
GitHub - source code.
PyPI - package manager (pip).
I printed this page and am gratfull for this.
Also tryed to configure "%APPDATA%"in this Dispositive,
using: "notepad", doesn't knowing to archive the sugested condiguration. Also copied sotoz and Aominé contribuiters. tks.
efk14it.
We are working on an add-on that writes to a log file and we need to figure out where the default var/log directory is located (the value of the ${buildout:directory} variable).
Is there an easy way to accomplish this?
In the past I had a similar use case.
I solved it by declaring the path inside the zope.conf:
zope-conf-additional +=
<product-config pd.prenotazioni>
logfile ${buildout:directory}/var/log/prenotazioni.log
</product-config>
See the README of this product:
https://github.com/PloneGov-IT/pd.prenotazioni/
This zope configuration can then be interpreted with this code:
from App.config import getConfiguration
product_config = getattr(getConfiguration(), 'product_config', {})
config = product_config.get('pd.prenotazioni', {})
logfile = config.get('logfile')
See the full example
here: https://github.com/PloneGov-IT/pd.prenotazioni/blob/9a32dc6d2863b5bfb5843d441e652101406d9a2c/pd/prenotazioni/init.py#L17
Worth noting is the fact that the initial return avoids multiple logging if the init function is mistakenly called more than once.
Anyway, if you do not want to play with buildout and custom zope configuration, you may want to get the default event log location.
It is specified in the zope.conf. You should have something like this:
<eventlog>
level INFO
<logfile>
path /path/to/plone/var/log/instance.log
level INFO
</logfile>
</eventlog>
I was able to obtain the path with this code:
from App.config import getConfiguration
import os
eventlog = getConfiguration().eventlog
logpath = eventlog.handler_factories[0].instance.baseFilename
logfolder = os.path.split(logpath)[0]
Probably looking at in the App module code you will find a more straightforward way of getting this value.
Another possible (IMHO weaker) solution would be store (through buildout or your prefered method) the logfile path into an environment variable.
You could let buildout set it in parts/instance/etc/zope.conf in an environment variable:
[instance]
recipe = plone.recipe.zope2instance
environment-vars =
BUILDOUT_DIRECTORY ${buildout:directory}
Check it in Python code with:
import os
buildout_directory = os.environ.get('BUILDOUT_DIRECTORY', '')
By default you already have the INSTANCE_HOME environment variable, which might be enough.
I am using OpenCV for various object detectors, and I am finding it difficult to write portable code.
For instance, to load a face detector, on a mac with OpenCV installed via homebrew, I have to write:
haar=cv.Load('/usr/local/Cellar/opencv/2.4.2/share/OpenCV/haarcascades/haarcascade_frontalface_default.xml')
This is not portable; if I wish to change to another machine I'll have to determine another absolute path and change this code.
Is there a variable that holds the OpenCV root for OpenCV? That way I could write something like:
haar=cv.Load(os.path.join(OpenCVRoot, "haarcascades",
"haarcascade_frontalface_default.xml"))
UPDATE: It looks like this is not just a problem for me; it is also a problem for the OpenCV documentation. The documentation contains the following broken example code:
>>> import cv
>>> image = cv.LoadImageM("lena.jpg", cv.CV_LOAD_IMAGE_GRAYSCALE)
>>> cascade = cv.Load("../../data/haarcascades/haarcascade_frontalface_alt.xml")
>>> print cv.HaarDetectObjects(image, cascade, cv.CreateMemStorage(0), 1.2, 2, 0, (20, 20))
[((217, 203, 169, 169), 24)]
This would be simple to avoid if there was a way to infer where examples like lena.jpg and the pre-trained classifiers were installed.
Source: http://opencv.willowgarage.com/documentation/python/objdetect_cascade_classification.html (Retrieved 3/5/13)
You can use cv2.__file__ to get path to the module and then use os.path to resolve symlinks and do some path manipulation. This line of code returns the directory of the haarcascades files on my Mac OS homebrew installation. It may work on other installations too.
from os.path import realpath, normpath
normpath(realpath(cv2.__file__) + '../../../../../share/OpenCV/haarcascades')
It seems there is little hope of having a single mechanism which would be portable across time and space (versions and platforms/environments), but there is some progress - I don't know which version introduced it, but 4.0 has it:
cv2.data.haarcascades - string pointing to a directory, e.g.:
>>> import cv2
>>> cv2.data
<module 'cv2.data' from 'C:\\Users\\USERNAME\\Anaconda3\\envs\\py36\\lib\\site-packages\\cv2\\data\\__init__.py'>
>>> cv2.data.haarcascades
'C:\\Users\\USERNAME\\Anaconda3\\envs\\py36\\lib\\site-packages\\cv2\\data\\'
>>> cv2.__version__
'4.0.0'
But unfortunately, for 3.2.x and 3.4.x there is no such module...
So you could do:
if hasattr(cv2, 'data'):
print('Cascades are here:', cv2.data.haarcascades)
else:
print('This may not work:')
print(normpath(realpath(cv2.__file__) + '../../../../../share/OpenCV/haarcascades'))
check this link
You can use sys.platform to determine the platform and set a different default path depending on the return from sys.platform
I'm in the same boat, and it is an annoying boat.
One convention you can use to deal with such portability issues is use configuration files. In your case, you could have a file ~/.myprojectrc, which could contain:
[cv]
cvroot = '/usr/local/Cellar/opencv/2.4.2/share/OpenCV/`
Files in this format can be read by ConfigParser objects, which should go something like:
import ConfigParser
import os
CONFIG = ConfigParser.ConfigParser()
config_path = os.path.join(os.path.expanduser('~'), '.myprojectrc')
if not os.path.exists(config_path):
raise Exception('You need to make a "~/.myprojectrc" file with your cv path or something')
CONFIG.read(config_path)
...
cv_root = CONFIG.get('cv', 'cvroot')
Then at least when someone uses the code on another machine they don't have to modify any code, they just need to create the config file with the opencv path, and they get a clear error message telling them to do so.
Why don't just copy that folder containing the xml files to your local workspace folder and use the relative path? As I remember, it does not cost much space on your hard drive
I need to get the location of the home directory of the current logged-on user. Currently, I've been using the following on Linux:
os.getenv("HOME")
However, this does not work on Windows. What is the correct cross-platform way to do this ?
You want to use os.path.expanduser.
This will ensure it works on all platforms:
from os.path import expanduser
home = expanduser("~")
If you're on Python 3.5+ you can use pathlib.Path.home():
from pathlib import Path
home = str(Path.home())
I found that pathlib module also supports this.
from pathlib import Path
>>> Path.home()
WindowsPath('C:/Users/XXX')
I know this is an old thread, but I recently needed this for a large scale project (Python 3.8). It had to work on any mainstream OS, so therefore I went with the solution #Max wrote in the comments.
Code:
import os
print(os.path.expanduser("~"))
Output Windows:
PS C:\Python> & C:/Python38/python.exe c:/Python/test.py
C:\Users\mXXXXX
Output Linux (Ubuntu):
rxxx#xx:/mnt/c/Python$ python3 test.py
/home/rxxx
I also tested it on Python 2.7.17 and that works too.
This can be done using pathlib, which is part of the standard library, and treats paths as objects with methods, instead of strings.
Path.expanduser()
Path.home()
from pathlib import Path
home: str = str(Path('~').expanduser())
This doesn't really qualify for the question (it being tagged as cross-platform), but perhaps this could be useful for someone.
How to get the home directory for effective user (Linux specific).
Let's imagine that you are writing an installer script or some other solution that requires you to perform certain actions under certain local users. You would most likely accomplish this in your installer script by changing the effective user, but os.path.expanduser("~") will still return /root.
The argument needs to have the desired user name:
os.path.expanduser(f"~{USERNAME}/")
Note that the above works fine without changing EUID, but if the scenario previously described would apply, the example below shows how this could be used:
import os
import pwd
import grp
class Identity():
def __init__(self, user: str, group: str = None):
self.uid = pwd.getpwnam(user).pw_uid
if not group:
self.gid = pwd.getpwnam(user).pw_gid
else:
self.gid = grp.getgrnam(group).gr_gid
def __enter__(self):
self.original_uid = os.getuid()
self.original_gid = os.getgid()
os.setegid(self.uid)
os.seteuid(self.gid)
def __exit__(self, type, value, traceback):
os.seteuid(self.original_uid)
os.setegid(self.original_gid)
if __name__ == '__main__':
with Identity("hedy", "lamarr"):
homedir = os.path.expanduser(f"~{pwd.getpwuid(os.geteuid())[0]}/")
with open(os.path.join(homedir, "install.log"), "w") as file:
file.write("Your home directory contents have been altered")
Is there a cross-platform way of getting the path to the temp directory in Python 2.6?
For example, under Linux that would be /tmp, while under XP C:\Documents and settings\[user]\Application settings\Temp.
That would be the tempfile module.
It has functions to get the temporary directory, and also has some shortcuts to create temporary files and directories in it, either named or unnamed.
Example:
import tempfile
print tempfile.gettempdir() # prints the current temporary directory
f = tempfile.TemporaryFile()
f.write('something on temporaryfile')
f.seek(0) # return to beginning of file
print f.read() # reads data back from the file
f.close() # temporary file is automatically deleted here
For completeness, here's how it searches for the temporary directory, according to the documentation:
The directory named by the TMPDIR environment variable.
The directory named by the TEMP environment variable.
The directory named by the TMP environment variable.
A platform-specific location:
On RiscOS, the directory named by the Wimp$ScrapDir environment variable.
On Windows, the directories C:\TEMP, C:\TMP, \TEMP, and \TMP, in that order.
On all other platforms, the directories /tmp, /var/tmp, and /usr/tmp, in that order.
As a last resort, the current working directory.
This should do what you want:
print(tempfile.gettempdir())
For me on my Windows box, I get:
c:\temp
and on my Linux box I get:
/tmp
I use:
from pathlib import Path
import platform
import tempfile
tempdir = Path("/tmp" if platform.system() == "Darwin" else tempfile.gettempdir())
This is because on MacOS, i.e. Darwin, tempfile.gettempdir() and os.getenv('TMPDIR') return a value such as '/var/folders/nj/269977hs0_96bttwj2gs_jhhp48z54/T'; it is one that I do not always want.
The simplest way, based on #nosklo's comment and answer:
import tempfile
tmp = tempfile.mkdtemp()
But if you want to manually control the creation of the directories:
import os
from tempfile import gettempdir
tmp = os.path.join(gettempdir(), '.{}'.format(hash(os.times())))
os.makedirs(tmp)
That way you can easily clean up after yourself when you are done (for privacy, resources, security, whatever) with:
from shutil import rmtree
rmtree(tmp, ignore_errors=True)
This is similar to what applications like Google Chrome and Linux systemd do. They just use a shorter hex hash and an app-specific prefix to "advertise" their presence.
Why so many complex answers?
I just use this
(os.getenv("TEMP") if os.name=="nt" else "/tmp") + os.path.sep + "tempfilename.tmp"