Here's my code:
import easygui
f = easygui.fileopenbox()
print f
Seems simple, but when I run it, I can't select any of the files, see figure in link. Sorry if this is dumb, but I am at my wit's end!
http://imgur.com/c20TvQ5
EasyGui isn't supported anymore. On OS X I don't have this problem with fileopenbox (it looks like what happens with diropenbox actually.) I'd recommend you try something like wxPython. Here's how to get a file open box in that (from https://stackoverflow.com/a/9319832/866271)
import wx
def get_path(wildcard):
app = wx.App(None)
style = wx.FD_OPEN | wx.FD_FILE_MUST_EXIST
dialog = wx.FileDialog(None, 'Open', wildcard=wildcard, style=style)
if dialog.ShowModal() == wx.ID_OK:
path = dialog.GetPath()
else:
path = None
dialog.Destroy()
return path
print get_path('*.txt')
Tested on OS X with no problem. It's also cross-platform. If you're going to be doing GUI development, there's a lot of options to look at but wxPython is a good one because it uses the native widgets of whatever OS you're running. So everything looks pretty :)
For your case, you could instead call get_path('*.csv') if that's the type of file you're opening. Or just call get_path('*') to get all of them.
Related
I have a simple script which parses a file and loads it's contents to a database. I don't need a UI, but right now I'm prompting the user for the file to parse using raw_input which is most unfriendly, especially because the user can't copy/paste the path. I would like a quick and easy way to present a file selection dialog to the user, they can select the file, and then it's loaded to the database. (In my use case, if they happened to chose the wrong file, it would fail parsing, and wouldn't be a problem even if it was loaded to the database.)
import tkFileDialog
file_path_string = tkFileDialog.askopenfilename()
This code is close to what I want, but it leaves an annoying empty frame open (which isn't able to be closed, probably because I haven't registered a close event handler).
I don't have to use tkInter, but since it's in the Python standard library it's a good candidate for quickest and easiest solution.
Whats a quick and easy way to prompt for a file or filename in a script without any other UI?
Tkinter is the easiest way if you don't want to have any other dependencies.
To show only the dialog without any other GUI elements, you have to hide the root window using the withdraw method:
import tkinter as tk
from tkinter import filedialog
root = tk.Tk()
root.withdraw()
file_path = filedialog.askopenfilename()
Python 2 variant:
import Tkinter, tkFileDialog
root = Tkinter.Tk()
root.withdraw()
file_path = tkFileDialog.askopenfilename()
You can use easygui:
import easygui
path = easygui.fileopenbox()
To install easygui, you can use pip:
pip3 install easygui
It is a single pure Python module (easygui.py) that uses tkinter.
Try with wxPython:
import wx
def get_path(wildcard):
app = wx.App(None)
style = wx.FD_OPEN | wx.FD_FILE_MUST_EXIST
dialog = wx.FileDialog(None, 'Open', wildcard=wildcard, style=style)
if dialog.ShowModal() == wx.ID_OK:
path = dialog.GetPath()
else:
path = None
dialog.Destroy()
return path
print get_path('*.txt')
pywin32 provides access to the GetOpenFileName win32 function. From the example
import win32gui, win32con, os
filter='Python Scripts\0*.py;*.pyw;*.pys\0Text files\0*.txt\0'
customfilter='Other file types\0*.*\0'
fname, customfilter, flags=win32gui.GetOpenFileNameW(
InitialDir=os.environ['temp'],
Flags=win32con.OFN_ALLOWMULTISELECT|win32con.OFN_EXPLORER,
File='somefilename', DefExt='py',
Title='GetOpenFileNameW',
Filter=filter,
CustomFilter=customfilter,
FilterIndex=0)
print 'open file names:', repr(fname)
print 'filter used:', repr(customfilter)
print 'Flags:', flags
for k,v in win32con.__dict__.items():
if k.startswith('OFN_') and flags & v:
print '\t'+k
Using tkinter (python 2) or Tkinter (python 3) it's indeed possible to display file open dialog (See other answers here). Please notice however that user interface of that dialog is outdated and does not corresponds to newer file open dialogs available in Windows 10.
Moreover - if you're looking on way to embedd python support into your own application - you will find out soon that tkinter library is not open source code and even more - it is commercial library.
(For example search for "activetcl pricing" will lead you to this web page: https://reviews.financesonline.com/p/activetcl/)
So tkinter library will cost money for any application wanting to embedd python.
I by myself managed to find pythonnet library:
Overview here: http://pythonnet.github.io/
Source code here: https://github.com/pythonnet/pythonnet
(MIT License)
Using following command it's possible to install pythonnet:
pip3 install pythonnet
And here you can find out working example for using open file dialog:
https://stackoverflow.com/a/50446803/2338477
Let me copy an example also here:
import sys
import ctypes
co_initialize = ctypes.windll.ole32.CoInitialize
# Force STA mode
co_initialize(None)
import clr
clr.AddReference('System.Windows.Forms')
from System.Windows.Forms import OpenFileDialog
file_dialog = OpenFileDialog()
ret = file_dialog.ShowDialog()
if ret != 1:
print("Cancelled")
sys.exit()
print(file_dialog.FileName)
If you also miss more complex user interface - see Demo folder
in pythonnet git.
I'm not sure about portability to other OS's, haven't tried, but .net 5 is planned to be ported to multiple OS's (Search ".net 5 platforms", https://devblogs.microsoft.com/dotnet/introducing-net-5/ ) - so this technology is also future proof.
If you don't need the UI or expect the program to run in a CLI, you could parse the filepath as an argument. This would allow you to use the autocomplete feature of your CLI to quickly find the file you need.
This would probably only be handy if the script is non-interactive besides the filepath input.
Another os-agnostic option, use pywebview:
import webview
def webview_file_dialog():
file = None
def open_file_dialog(w):
nonlocal file
try:
file = w.create_file_dialog(webview.OPEN_DIALOG)[0]
except TypeError:
pass # user exited file dialog without picking
finally:
w.destroy()
window = webview.create_window("", hidden=True)
webview.start(open_file_dialog, window)
# file will either be a string or None
return file
print(webview_file_dialog())
Environment: python3.8.6 on Mac - though I've used pywebview on windows 10 before.
I just stumbled on this little trick for Windows only: run powershell.exe from subprocess.
import subprocess
sys_const = ssfDESKTOP # Starts at the top level
# sys_const = 0x2a # Correct value for "Program Files (0x86)" folder
powershell_browse = "(new-object -COM 'Shell.Application')."
powershell_browse += "BrowseForFolder(0,'window title here',0,sys_const).self.path"
ret = subprocess.run(["powershell.exe",powershell_browse], stdout=subprocess.PIPE)
print(ret.stdout.decode())
Note the optional use of system folder constants. (There's an obscure typo in shldisp.h that the "Program Files (0x86)" constant was assigned wrong. I added a comment with the correct value. Took me a bit to figure that one out.)
More info below:
System folder constants
I have created shortcuts for executables and it works, but when I try to create one for a folder it does not work.
It does create a shortcut, it is just not the right 'Target Type'. Please take a look at the image below.
Instead of 'File', the target type should be 'File folder'. The problem is that when I open the shortcut it asks me which program do I want to open the File with and it does not open the folder.
The function I'm using to create the shortcuts is the following
from win32com.client import Dispatch
import winshell
import os
def create_shortcuts(self, tool_name, exe_path, startin, icon_path):
shell = Dispatch('WScript.Shell')
shortcut_file = os.path.join(winshell.desktop(), tool_name + '.lnk')
shortcut = shell.CreateShortCut(shortcut_file)
shortcut.Targetpath = exe_path
shortcut.WorkingDirectory = startin
shortcut.IconLocation = icon_path
shortcut.save()
I don't know if it's possible to set the 'Target Type'. I couldn't find a way to do it, but I do know there must be a way.
If you want to use .Net "clr" (especially if you already require it):
First run this... you will have to ship the output of this command with your application:
"c:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.6.1 Tools\TlbImp.exe" %SystemRoot%\system32\wshom.ocx /out:Interop.IWshRuntimeLibrary.dll
tlbimp.exe might even be in the path if you installed the Windows SDK in a fairly standard way. But if not, it's OK, you'll just ship the "assembly" (fancy word for interface-providing dll in .Net land) with your application.
Then this code will work in python:
import clr
sys.path.append(DIRECTORY_WHERE_YOU_PUT_THE_DLL)
clr.AddReference('Interop.IWshRuntimeLibrary')
import Interop.IWshRuntimeLibrary
sc = Interop.IWshRuntimeLibrary.WshShell().CreateShortcut("c:\\test\\sc.lnk")
isc = Interop.IWshRuntimeLibrary.IWshShortcut(sc)
isc.set_TargetPath("C:\\")
isc.Save()
.... the above code, with far too much modification and preamble, might even work with Mono.
For future reference: I observed the described behavior in python 3.9.6 when creating a shortcut to a non-existing directory, which was easily fixed by incorporating os.makedirs() into the method.
I've added a method parameter to the version I'm using, so it can handle shortcuts to files and directories:
def create_shortcuts(self, tool_name, exe_path, startin, icon_path, is_directory=False):
if is_directory:
os.makedirs(exe_path, exist_ok=True)
shell = Dispatch('WScript.Shell')
shortcut_file = os.path.join(winshell.desktop(), tool_name + '.lnk')
shortcut = shell.CreateShortCut(shortcut_file)
shortcut.Targetpath = exe_path
shortcut.WorkingDirectory = startin
shortcut.IconLocation = icon_path
shortcut.save()
So I have a Python script which I make into an exe with py2exe and I want it to do certain tasks only when the exe version is running. Is there a way to write the code so I don't have to manually save a separate version before I create the exe?
I'm picturing something like this:
if self.filename[-4:] == ".exe":
do this code
So it would somehow be able to find its own file name. Can it be done?
Try
import sys
...
if sys.argv[0].endswith('.exe'):
...
if ".exe" in self.fileName:
print "it's an exe file!"
Given that self.filename = "someprogram.exe"
The py2exe docs give a way to do this:
http://www.py2exe.org/index.cgi/HowToDetermineIfRunningFromExe
import imp, os, sys
def main_is_frozen():
return (hasattr(sys, "frozen") or # new py2exe
hasattr(sys, "importers") # old py2exe
or imp.is_frozen("__main__")) # tools/freeze
(I edited the whole question to be more clear)
Hello,
I have never had any affairs with Python GUI libraries. I know there are plenty and well documented, but as I need only one single snippet, I would dislike to dive deep into documentations to seek for a way how to do it. If I am going to write a GUI program, I surely would do that, but this is needed only as a few lines for my ad hoc script.
What would be the easiest and the most straightforward way for me (GUI noob) to write in Python following piece of code? Less lines = more happiness.
Grab a JPEG picture by filename.
Display it's thumbnail.
Below the thumbnail display a textfield so the user can type in a caption.
Wait until user hits ENTER key on his/her keyboard. In that case, close and return the input.
...or wait until user hits DELETE key. In that case, close and return an information about the decision (to delete the picture).
Dependencies or Linux-only solutions are okay. I need to run this on Xubuntu machine. Any code snippets, please? I believe this is a matter of 5 minutes for someone skilled in Python GUI field. I would need to study loads of library docs. Thank you!
Below is a minimal python script that more or less fits the spec.
It requires python2 and pyqt4 packages to be installed, and it won't work with python3 (although it could quite easily be adapted to do so if necessary).
If the user types in a valid caption and presses enter, the script will return with status code 0 and print the caption to stdout; otherwise, if the user enters an invalid caption (empty or whitespace only), or simply closes the dialog without doing anything, the script will return with status code 1 and print nothing.
example bash usage:
$ CAPTION=$(python imgviewer.py image.jpg)
$ [ $? -eq 0 ] && echo $CAPTION
imgviewer.py:
import sys, os
from PyQt4 import QtGui, QtCore
class Dialog(QtGui.QDialog):
def __init__(self, path):
QtGui.QDialog.__init__(self)
self.viewer = QtGui.QLabel(self)
self.viewer.setMinimumSize(QtCore.QSize(400, 400))
self.viewer.setScaledContents(True)
self.viewer.setPixmap(QtGui.QPixmap(path))
self.editor = QtGui.QLineEdit(self)
self.editor.returnPressed.connect(self.handleReturnPressed)
layout = QtGui.QVBoxLayout(self)
layout.addWidget(self.viewer)
layout.addWidget(self.editor)
def handleReturnPressed(self):
if self.editor.text().simplified().isEmpty():
self.reject()
else:
self.accept()
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
args = app.arguments()[1:]
if len(args) == 1:
dialog = Dialog(args[0])
if dialog.exec_() == QtGui.QDialog.Accepted:
print dialog.editor.text().simplified().toLocal8Bit().data()
sys.exit(0)
else:
print 'ERROR: wrong number of arguments'
sys.exit(1)
There are several good GUI libraries for Python. The "standard" library that comes built-in with python is tkinter:http://wiki.python.org/moin/TkInter. Some says that wxPython is much more powerful and straightforward: http://www.wxpython.org/.
I think that you can start with wxPython, they have many many tutorials and examples you can dig into (just run the DEMO).
They have an example called "ImageBrowser" which might be a very good starting point.
Regarding the communication between the different apps, you can use "pipes" and "redirections" to communicate. But if everything is written in python, I think this is the wrong way to go, you can show the image form within your python script and get the result internally.
I have a python desktop application that needs to store user data. On Windows, this is usually in %USERPROFILE%\Application Data\AppName\, on OSX it's usually ~/Library/Application Support/AppName/, and on other *nixes it's usually ~/.appname/.
There exists a function in the standard library, os.path.expanduser that will get me a user's home directory, but I know that on Windows, at least, "Application Data" is localized into the user's language. That might be true for OSX as well.
What is the correct way to get this location?
UPDATE:
Some further research indicates that the correct way to get this on OSX is by using the function NSSearchPathDirectory, but that's Cocoa, so it means calling the PyObjC bridge...
Well, I hate to have been the one to answer my own question, but no one else seems to know. I'm leaving the answer for posterity.
APPNAME = "MyApp"
import sys
from os import path, environ
if sys.platform == 'darwin':
from AppKit import NSSearchPathForDirectoriesInDomains
# http://developer.apple.com/DOCUMENTATION/Cocoa/Reference/Foundation/Miscellaneous/Foundation_Functions/Reference/reference.html#//apple_ref/c/func/NSSearchPathForDirectoriesInDomains
# NSApplicationSupportDirectory = 14
# NSUserDomainMask = 1
# True for expanding the tilde into a fully qualified path
appdata = path.join(NSSearchPathForDirectoriesInDomains(14, 1, True)[0], APPNAME)
elif sys.platform == 'win32':
appdata = path.join(environ['APPDATA'], APPNAME)
else:
appdata = path.expanduser(path.join("~", "." + APPNAME))
There's a small module available that does exactly that:
https://pypi.org/project/appdirs/
You can try to use QSettings from Qt. You can obtain the path to your MyCompany/MyApp.ini file this way:
from PySide.QtCore import QSettings, QCoreApplication
QSettings.setDefaultFormat(QSettings.IniFormat)
QCoreApplication.setOrganizationName("MyCompany")
QCoreApplication.setApplicationName("MyApp")
settings = QSettings()
print(settings.fileName())
Alternatively, without changing any global state:
QSettings(
QSettings.IniFormat, QSettings.UserScope,
"MyCompany", "MyApp"
).fileName()
On Win7 you get something like:
C:\Users\MyUser\AppData\Roaming\MyCompany\MyApp.ini
On Linux (may vary):
/home/myuser/.config/MyCompany/MyApp.ini
I don't know the possible results for OSX (but I'd like to).
QSettings functionallity seem to be nice until you want to use registerFormat, which is not available in PySide, so there is no easy way to use YAML or JSON writers for settings.
Well, for Windows APPDATA (environmental variable) points to a user's "Application Data" folder. Not sure about OSX, though.
The correct way, in my opinion, is to do it on a per-platform basis.