I'm creating a simple Python CLI tool, which lets the user add and delete tasks (the classic Todo app). This is just for my own use, but I want to get into the best practices of creating such applications. The data will be stored in a simple text file.
Main question: Where should I store the data file? After doing some reading, I'm inclined to create a new folder in /var/lib and keep the data.txt file in that directory. Are there any drawbacks to that option?
Follow up question: Since, by default, only root has access to /var, do I need to change the permissions for the whole /var directory in order to read and write to the data file?
User data should be store in the user's home directory. You could use..
Mac OS X
/Users/joe/.myclitool/data.txt
GNU/Linux
/home/joe/.myclitool/data.txt
In Python this can be done with:
import os
import os.path
p = os.path.join(os.getenv("HOME"), ".myclitool", "data.txt")
Related
I'm writing a software in python for windows which should be connected to a database. Using py2exe i want to make an executable file so that I don't have to install python in the machines the software is running. The problem is that I want the user to define where the database is located the very first time the software starts, but I don't know how to store this information so that the user doesn't have to tell everytime where is the database. I have no idea how to deal with it. (the code cannot be changed because it's just a .exe file). How would you do that?
I can think of some solutions:
You can assume the DB is in a fixed location - bad idea, might move or change name and then your program stop working
You can assume the DB is in the same folder as the .exe file and guide the user to run it in the same folder - better but still not perfect
Ask the user for the DB location and save the path in a configuration file. If the file doesn't exist or path doesn't lead to the file, the user should tell the program where is the DB, otherwise, read it from the config file - I think this is the best option.
import os
default_db_path = os.environ['LOCALAPPDATA'] + '/stuff.db'
setting_path = os.environ['LOCALAPPDATA'] + '/.stuff_db_path.txt'
try:
open(setting_path)
except:
with open(setting_path, 'wt') as f:
f.write(default_db_path)
db_path = open(setting_path).read().strip()
This way, the user is able to configure via the text file, and you're able to have a sensible default for the first time.
Edit: added a Windows friendly config path, which should work in most private and corporate environments. There are innumerous ways to improve this example, but my suggestion is you start out simple stupid and take it from there.
My Revit Add-in reads at some point a text file, that could be located anywhere. In my current implementation, the path to the text file is hardcoded. I'd like to avoid that, so that when I distribute the Add-in to other people, it doesn't simply crash.
Ideally I'd like to give them the ability of specifying their own location for that file on their computer, and that they don't need to re-specify it every time they re-launch the Add-in!
In other words, I'd like to store once and for all this information. And if you close and re-open Revit, the location is still stored somewhere when you re-use the Addin.
This question is actually similar to this one, except that I'd need a solution when developing in Python (pyRevit). Any help?
if you're developing you addon in pyRevit, then you can use the pyrevit.script module to get the configuration for that script.
Ask user for the file location (pyrevit.forms.save_file helps) and then save the file path in the script configuration. pyRevit handles this automatically and saves the information inside its master configuration file at %appdata%/pyRevit
from pyrevit import script
config = script.get_config()
config.filelocation = 'path/to/your/file'
script.save_config()
And then later, read the configuration like this:
from pyrevit import script
config = script.get_config()
print(config.filelocation)
# or to get the config safely
print(config.get_option('filelocation', None)
I implemented two other ways to store Revit add-in settings in the HoloLens Escape Path Waypoint JSON Exporter:
Store add-in option settings in XML using the .NET System.Configuration.ApplicationSettingsBase class
Store add-in option settings in JSON using custom solution and JavaScriptSerializer class
Both solutions are well suited for what you need.
Check them out in the ExportWaypointsJson GitHub repository.
I am trying to list (let's say) PDF files in a directory (to a GUI). I know I can manage that with in different ways (like below) but I also want the list is to be current and dynamic. For instance, if someone deletes a PDF file from or adds a PDF file to the directory, I want the application to delete or add the file name to the list instantly, without any refresh.
Do you know any ways to manage that?
Here is some of my code:
import os
pdffiles = [name for name in os.listdir('somedir')
if name.endswith('.pdf')]
for file in pdffiles:
print(file)
I am in a learning progress.
Your code looks good so far. If you want to do this programmatically (avoiding pynotify or signal handling), the simplest way to maintain a directory listing in your application is via polling the directory.
So, your code might look like:
import os
import time
## run indefinitely
while True:
## get the directory listing
pdffiles = [name for name in os.listdir('somedir')
if name.endswith('.pdf')]
## print the most recent listing
for file in pdffiles:
print(file)
## wait a little bit before getting the next listing
## if you want near instantaneous updates, make the sleep value small.
time.sleep(1)
You need to get notified by the OS that the directory and/or some files changed.
On Linux you can use pyinotify
On OSX you can do that with MACFSEvents
On Windows (.Net) you can try to interface with FileSystemWatcher, but I am not aware of any specific libraries for that.
And a platform independent solutions is watchdog
Hooking that into your program is non-trivial, but the examples of watchdog are clear and that means there is no need for polling.
I have a simple web-server written using Python Twisted. Users can log in and use it to generate certain reports (pdf-format), specific to that user. The report is made by having a .tex template file where I replace certain content depending on user, including embedding user-specific graphs (.png or similar), then use the command line program pdflatex to generate the pdf.
Currently the graphs are saved in a tmp folder, and that path is then put into the .tex template before calling pdflatex. But this probably opens up a whole pile of problems when the number of users increases, so I want to use temporary files (tempfile module) instead of a real tmp folder. Is there any way I can make pdflatex see these temporary files? Or am I doing this the wrong way?
without any code it's hard to tell you how, but
Is there any way I can make pdflatex see these temporary files?
yes you can print the path to the temporary file by using a named temporary file:
>>> with tempfile.NamedTemporaryFile() as temp:
... print temp.name
...
/tmp/tmp7gjBHU
As commented you can use tempfile.NamedTemporaryFile. The problem is that this will be deleted once it is closed. That means you have to run pdflatex while the file is still referenced within python.
As an alternative way you could just save the picture with a randomly generated name. The tempfile is designed to allow you to create temporary files on various platforms in a consistent way. This is not what you need, since you'll always run the script on the same webserver I guess.
You could generate random file names using the uuid module:
import uuid
for i in xrange(3):
print(str(uuid.uuid4()))
The you save the pictures explictly using the random name and pass insert it into the tex-file.
After running pdflatex you explicitly have to delete the file, which is the drawback of that approach.
This might be a general programming question but since I am doing it from within an Add-In therefore asking here at GIS forum. I have a project folder with sub-folders containing several files on my hard disk which I read from within my Python Add-In, its hard coded e.g.:
dem = r'C:/project/raster/dem'
and Add-In is in
r'C:/project/Add-In'
folder. I tried doing '../raster/dem' to define path of input raster layer but it failed to read. Please suggest how can I make it generic so that if I move project folder to D drive then Add-In would still be able to read data.
You can reference materials that are located within the add-in, everything that's included within the 'Install' directory will be copied into the appropriate location within AssemblyCache. You can then reference this by doing something like:
local_path = os.path.abspath(os.path.basename(__file__))
raster_path = os.path.join(local_path, 'rasters')
And from there, treat raster_path as a nomral path.
You could read in a configuration file stored under the user's profile. Because ArcGIS add-ins overwrite themselves every time the host application is opened, you don't want to store user-specific configuration information inside the add-in itself.
The configuration file can be in any format you want (e.g. XML, plain text), but the ConfigParser class makes reading and writing to an INI-like file format easy.