Where should I place a config.txt in my python project - python

The project folder hierarchy looks like
ProjectName
->src
->Project.sikuli
->myFile.py
->config.txt
Now, I have all the settings variables being stores in my config.txt and I'm using ConfigParser to fetch the values from it. The reason why I'm using this config file here is that, when this sikuli script is moved to another machine for running I can just change the values in it (like paths, username, password) rather than editing the main python script 'myFile.py'.
But the issue I'm encountering now is that I don't want the config file to be placed some where outside the project so that in my script when I try to fetch the values from it, I don't have to mention the absolute path again in the myFile.txt like:
configParser = ConfigParser.RawConfigParser()
configfilePath = r'D:\MyWorkspace\ProjectName\src\Project.sikuli\config.txt'
Instead I want to have the relative path here so that while migrating the project from machine to machine I don't have to do any manipulations in the main script 'myFile.py'
So what I'm trying to achieve is like:
I should be able to refer the config.txt file by giving it's relative path:
configfilePath = r'D:\MyWorkspace\ProjectName\src\Project.sikuli\config.txt'

If it's going to be kept in the same folder as myFile.py, then in that Python script you could use something like this:
configfilePath = os.path.join(os.path.dirname(__file__), 'config.txt')

The best way to do this is to put the file inside your .sikuli bundle, just as you have done in your example, and then get the path to your file like this:
configFilePath = os.path.join(getBundlePath(), 'config.txt')

I know you can fetch variables and value from a python file by importing it...
import config
I would put it in the root repertory of the project

First, get the path of the currently executed python script:
myPath = os.path.abspath(os.path.dirname(sys.argv[0]))
and then do a join of myPath and 'config.txt'
configfilePath = os.path.join(myPath, 'config.txt')

Related

Regarding file io in Python

I mistakenly, typed the following code:
f = open('\TestFiles\'sample.txt', 'w')
f.write('I just wrote this line')
f.close()
I ran this code and even though I have mistakenly typed the above code, it is however a valid code because the second backslash ignores the single-quote and what I should get, according to my knowledge is a .txt file named "\TestFiles'sample" in my project folder. However when I navigated to the project folder, I could not find a file there.
However, if I do the same thing with a different filename for example. Like,
f = open('sample1.txt', 'w')
f.write('test')
f.close()
I find the 'sample.txt' file created in my folder. Is there a reason for the file to not being created even though the first code was valid according to my knowledge?
Also is there a way to mention a file relative to my project folder rather than mentioning the absolute path to a file? (For example I want to create a file called 'sample.txt' in a folder called 'TestFiles' inside my project folder. So without mentioning the absolute path to TestFiles folder, is there a way to mention the path to TestFiles folder relative to the project folder in Python when opening files?)
I am a beginner in Python and I hope someone could help me.
Thank you.
What you're looking for are relative paths, long story short, if you want to create a file called 'sample.txt' in a folder 'TestFiles' inside your project folder, you can do:
import os
f = open(os.path.join('TestFiles', 'sample1.txt'), 'w')
f.write('test')
f.close()
Or using the more recent pathlib module:
from pathlib import Path
f = open(Path('TestFiles', 'sample1.txt'), 'w')
f.write('test')
f.close()
But you need to keep in mind that it depends on where you started your Python interpreter (which is probably why you're not able to find "\TestFiles'sample" in your project folder, it's created elsewhere), to make sure everything works fine, you can do something like this instead:
from pathlib import Path
sample_path = Path(Path(__file__).parent, 'TestFiles', 'sample1.txt')
with open(sample_path, "w") as f:
f.write('test')
By using a [context manager]{https://book.pythontips.com/en/latest/context_managers.html} you can avoid using f.close()
When you create a file you can specify either an absolute filename or a relative filename.
If you start the file path with '\' (on Win) or '/' it will be an absolute path. So in your first case you specified an absolute path, which is in fact:
from pathlib import Path
Path('\Testfile\'sample.txt').absolute()
WindowsPath("C:/Testfile'sample.txt")
Whenever you run some code in python, the relative paths that will be generate will be composed by your current folder, which is the folder from which you started the python interpreter, which you can check with:
import os
os.getcwd()
and the relative path that you added afterwards, so if you specify:
Path('Testfiles\sample.txt').absolute()
WindowsPath('C:/Users/user/Testfiles/sample.txt')
In general I suggest you use pathlib to handle paths. That makes it safer and cross platform. For example let's say that your scrip is under:
project
src
script.py
testfiles
and you want to store/read a file in project/testfiles. What you can do is get the path for script.py with __file__ and build the path to project/testfiles
from pathlib import Path
src_path = Path(__file__)
testfiles_path = src_path.parent / 'testfiles'
sample_fname = testfiles_path / 'sample.txt'
with sample_fname.open('w') as f:
f.write('yo')
As I am running the first code example in vscode, I'm getting a warning
Anomalous backslash in string: '\T'. String constant might be missing an r prefix.
And when I am running the file, it is also creating a file with the name \TestFiles'sample.txt. And it is being created in the same directory where the .py file is.
now, if your working tree is like this:
project_folder
-testfiles
-sample.txt
-something.py
then you can just say: open("testfiles//hello.txt")
I hope you find it helpful.

How to access a file a path level below from a subfolder

Let's say I have a file called credentials.json in my current directory, an environment variable MY_CREDENTIALS=credentials.json and a script main.py that uses this environment variable via os.getenv('MY_CREDENTIALS').
Now suppose I create a subfolder and put something there like this: /subfolder/my_other_script.py.
If I print os.getenv('MY_CREDENTIALS') then I get indeed credentials.json but I can't use this file as it is in my root directory (not in /subfolder). So, how can I use this file although it is in the root directory? The only thing that works for me is to make a copy of credentials.json in /subfolder, but then I would have multiple copies of this file and I don't want that.
Thanks for your response!
Something like this could work:
from pathlib import Path
import os
FILENAME = os.getenv('MY_CREDENTIALS')
filePath = Path(FILENAME)
if filePath.exists() and filePath.is_file():
print("Success: File exists")
print(filePath.read_text())
else:
print("Error: File does not exist. Getting file from level below.")
print((filePath.absolute().parent.parent / filePath.name).read_text())
Basically, you check whether your file exists in the current folder. This will be the case, if your script is in your root folder. If it is not, you assume that you are in a subfolder. So you try to get the file from one level below (your root).
It's not totally production ready, but for the specific case you mentioned it should work. In production you should think about cases where you might have nested subfolder or your file is missing for good.
You can create symbolic link
os.symlink('<root>', '<subfolder>')
https://docs.python.org/3/library/os.html#os.symlink

FILE (.json) NOT FOUND

This is my directory where i have activated a virtual environment:
I'm working on a flask project to create a rest API, and I have a JSON credential file (google vision file), but when I run the code it says file not found even if it's in the same directory. I've activated a virtualenv for this particular project. mainone.py is the code I'm trying to run.
This is the error I am getting:
"File {} was not found.".format(filename)
google.auth.exceptions.DefaultCredentialsError: File date_scanner.json was not found.
And this is the code block where I am using accessing the particular file:
from flask import Flask,request,jsonify
import os,io,re,glob,base64
from google.cloud import vision
from google.cloud.vision import types
from PIL import Image
os.environ['GOOGLE_APPLICATION_CREDENTIALS']=r'date_scanner.json'
client=vision.ImageAnnotatorClient()
This is likely because the "working folder" of the Python process is not the same as where the file is located. There is a small (albeit convoluted) way to generate filenames which will always work:
Use __file__ to get the filename of the Python file where this is called.
Strip the filename from that path using os.path.dirname
Append the filename that you want to open using os.path.join
from os.path import dirname, join
def get_filename(filename):
here = dirname(__file__)
output = join(here, filename)
return output
Some food for thought
However, in this case there is something you should be careful about: The file contains security credentials and should not live in your source code. So while the above example will solve the immediate problem, the security of this should be addressed.
The best way for this is to externalise the filename of the credentials file into a config file. Say, for example you would use a .ini file as config file, you could have something like this in your code somewhere:
config = configparser.ConfigParser()
config.read('config.ini')
vision_creds_file = config.get('google_vision', 'filename')
and then place the following into config.ini:
[google_vision]
filename = /path/to/filename.json
This still requires you to place the config.ini file somewhere which should be documented in your application, as you still cannot add this to the source code (maybe a sample file with defaults).

Specifying a custom logging Linux filepath in Python 2

I'm trying to understand how logfiles work with the Python 2 logging module.
I know that I can save the log output to a text file using something like:
logging.basicConfig(filename='example.log',level=logging.DEBUG)
It's not clear to me from the documentation on:
Whether or not absolute filename paths are valid
The proper syntax for specifying relative paths (assuming that ../example.log is valid).
If I execute this script from /home/bob, how do I specify that I want the logfile saved to the /tmp directory instead - using both absolute and relative paths?
Is logging.basicConfig(filename='../../tmp/example.log') valid?
Similarly, is logging.basicConfig(filename='/tmp/example.log') valid?
When stating just the filename, it would be written to the current directory.
Using Python IDLE you can check that as follows
>>> import logging
>>> logging.basicConfig(filename='relative.log')
>>> logging.info('test')
C:\Python27\relative.log
My working dir is Python27, and I have a file there named relative.log with my logged message.
When you change the file location to ../relative.log, I get a new file at the parent directory of Python27. So relative path does work for logging:
>>> import logging
>>> logging.basicConfig(filename='../relative.log')
>>> logging.info('test123')
C:\relative.log
And logging module also supports absolute path:
>>> logging.basicConfig(filename=r'c:\abs_path.log')
>>> logging.info('test')
C:\abs_path.log
It is always better to use absolute path, as explicit is better than implicit.
They are both valid. But relative paths (with ..) will select different files depending on the directory you are in when you run it.
So when you run logger.py in /home/user/projects/python and the filename is ../log.txt the file will be saved in /home/user/projects. On the other hand when you run the script in /home/user then log.txt will be saved in /home/.
Absolute paths always work and are more reliable. If you want a file in the current directory I recommend this approach:
basedir = os.path.abspath(os.path.dirname(__file__))
filename = os.path.join(basedir, 'file.txt')

How to set current working directory in python in a automatic way

How can I set the current path of my python file "myproject.py" to the file itself?
I do not want something like this:
path = "the path of myproject.py"
In mathematica I can set:
SetDirectory[NotebookDirectory[]]
The advantage with the code in Mathematica is that if I change the path of my Mathematica file, for example if I give it to someone else or I put it in another folder, I do not need to do anything extra. Each time Mathematica automatically set the directory to the current folder.
I want something similar to this in Python.
The right solution is not to change the current working directory, but to get the full path to the directory containing your script or module then use os.path.join to build your files path:
import os
ROOT_PATH = os.path.dirname(os.path.abspath(__file__))
# then:
myfile_path = os.path.join(ROOT_PATH, "myfile.txt")
This is safer than messing with current working directory (hint : what would happen if another module changes the current working directory after you did but before you access your files ?)
I want to set the directory in which the python file is, as working directory
There are two step:
Find out path to the python file
Set its parent directory as the working directory
The 2nd is simple:
import os
os.chdir(module_dir) # set working directory
The 1st might be complex if you want to support a general case (python file that is run as a script directly, python file that is imported in another module, python file that is symlinked, etc). Here's one possible solution:
import inspect
import os
module_path = inspect.getfile(inspect.currentframe())
module_dir = os.path.realpath(os.path.dirname(module_path))
Use the os.getcwd() function from the built in os module also there's os.getcwdu() which returns a unicode object of the current working directory
Example usage:
import os
path = os.getcwd()
print path
#C:\Users\KDawG\Desktop\Python

Categories