Tkinter FileDialog.askopenfilename failing on already open files - python

I can not find a way using the the Tkinter tkFileDialog.askopenfilename / Open() method to get a file name of an already opened file. At least on Windows 7 anyway.
Simply need to return the filename selected, but when I select an 'opened' file I get the "This file is in use" popup. Any searches for getting filenames seems to always point back to using FileDialog.
There seems to be the same question but using c# here:
Open File Which is already open in window explorer
Are there any ways not listed that can be used to arrive at this? A file selection popup that doesn't fail on already opened files on Windows 7?
Python 2.7.11
Windows 7_64
Selection dialog:
opts = {}
opts['title'] = 'Select file.'
filename = tkFileDialog.Open(**opts).show()
or
filename = tkFileDialog.askopenfilename(**opts)
Which are the same as askopenfilename calls Open().show() which in turn is calling command = "tk_getOpenFile".
Searching tk_getOpenFile shows nothing to override this behavior.
Any pointers here would be much appreciated.
Update:
So as to not reiterate everything that's been gone over here's the break down of the Tkinter 8.5 FileDialog.
def askopenfile(mode = "r", **options):
"Ask for a filename to open, and returned the opened file"
filename = Open(**options).show()
if filename:
return open(filename, mode)
return None
def askopenfilename(**options):
"Ask for a filename to open"
return Open(**options).show()
Both call the Open class but askopenfile follows up with an open(file), here:
class Open(_Dialog):
"Ask for a filename to open"
command = "tk_getOpenFile"
def _fixresult(self, widget, result):
if isinstance(result, tuple):
# multiple results:
result = tuple([getattr(r, "string", r) for r in result])
if result:
import os
path, file = os.path.split(result[0])
self.options["initialdir"] = path
# don't set initialfile or filename, as we have multiple of these
return result
if not widget.tk.wantobjects() and "multiple" in self.options:
# Need to split result explicitly
return self._fixresult(widget, widget.tk.splitlist(result))
return _Dialog._fixresult(self, widget, result)
UPDATE2(answerish):
Seems the windows trc/tk tk_getOpenFile ultimately calls
OPENFILENAME ofn;
which apparently can not, at times, return a filename if the file is in use.
Yet to find the reason why but regardless.
In my case, needing to reference a running QuickBooks file, it will not work using askopenfilename().
Again the link above references someone having the same issue but using c# .

Related

How do I get the path selected by the user in Explorer?

I have a program that makes voice text using .txt ,but os.startfile doesn't let me select the file, hence get the path to it) I will be very grateful for your help!!
Как должно быть.
enter image description here
Как у меня)
enter image description here
import os
import pyttsx3 as pyt
from gtts import gTTS
class DICTOR:
def __init__(self, path):
self.engine = pyt.init()
#voices = self.engine.getProperty('voices')
self.engine.setProperty('voice', 0)
#rate = self.engine.getProperty('rate')
self.engine.setProperty('rate', 150)
with open(path, 'r') as file:
self.file = file.read()
# def speak(self):
# self.engine.say(self.file)
# self.engine.runAndWait()
def save(self, filename):
tss = gTTS(text = self.file, lang='en')
tss.save(filename)
#rate = self.engine.getProperty('rate')
path = os.startfile(filepath = 'D:\Python\Road_map\DICTOR')
DICTOR(path).save('.mp3')
I'm guessing your problem is with the formatting. You should add r to the start. It should be:
path = os.startfile(filepath = r"G:\EEGdatabase\6541455.docx")
the r is needed because \ is considered to be a special character by python. Another option is to escape \ with \\:
path = os.startfile(filepath = 'D:\\Python\\Road_map\\DICTOR')
More info in the docs.
Finally, since you haven't provided your error message, maybe this isn't your problem at all. If this doesn't fix it, add your error log so we know exactly what is going on.
Edit: It seems you have misunderstood the use of os.startfile. This function takes in something you need to "start", and starts it. So if you had said
os.startfile("something.pdf")
Then something.pdf will be opened in your default PDF software. If you instead passed in something like file.html, then this html file will be opened in your default web browser.
So you are now passing in D:\Python\Road_map\DICTOR, which is a folder, and the startfile function simply opens up that folder in Windows Explorer. A full reference for startfile can be found in the docs.
In any case, I don't think you need startfile at all. You need a file selector, which you can get using the Tkinter package. You can then say:
from Tkinter import Tk # from tkinter import Tk for Python 3.x
from tkinter.filedialog import askopenfilename
Tk().withdraw() # we don't want a full GUI, so keep the root window from appearing
filename = askopenfilename() # show an "Open" dialog box and return the path to the selected file
print(filename)
path = filename
(Taken from https://stackoverflow.com/a/3579625/3730626)

Canonical Method to get Long Filename from User

I am writing a Python module which will read and analyze an input file for a specialized software program. I want the user to be able to analyze whichever input file they choose. So far I've tried 2 methods to get the file name:
Method 1:
filename = input('File to be analyzed: ')
Pro: simplest method
Con: difficult for user to type long file path every time
Method 2:
Put a file called path.txt in the same directory as the Python module and the user can store the filename there.
import os
pathtxt_dir = os.path.dirname(os.path.realpath(__file__))
pathtxt_fullpath = os.path.join(pathtxt_dir, 'path.txt')
try:
fo = open(pathtxt_fullpath, 'r')
lines = fo.readlines()
fo.close()
except IOError:
raise Exception('path.txt cannot be opened')
filename = lines[0].rstrip().lstrip() # input file
Pro: Coworkers are familiar with this approach since it is similar to previous programs they have used.
Con: It seems like an unnecessarily complicated way to get user input
Question:
Is there a canonical Python method for getting long and repetitive user inputs, like this filename? Also, is there another useful method that I have not considered?
You can use tkinter to open a GUI for them to select the file. That way they don't have to type it out every time.
import tkinter as tk
from tkinter import filedialog as fd
import os
def getfile(title='Choose files', sformat='.*'):
root = tk.Tk()
root.lift()
# d and f are whatever default directory and filename
try:
f = fd.askopenfilename(parent=root, title=title, filetypes=[('', sformat)], initialdir=d, initialfile=f)
root.withdraw()
return f
except:
# print(title + ': error - no file exists')
return ''

Passing an open file from one function to another

I'm a python beginner so bear with me. I have written some code on a GUI that allows users to select a file using one button (browse_inputfile), it then displays the file path and then the user can click another button to run a conversion on that file (run_conversion).
However to do this I've had to define a global variable to enable the open file to be passed from one function to another. Is there a better way to do this? I tried passing the path and actually opening it in the second function but this produced "file not found" errors I think due to the "\" used in the string path.
This is the code I have:
def browse_inputfile(self):
global inputfile
inputfile = open(QtGui.QFileDialog.getOpenFileName(self, "Open Data File", "", "txt files (*.txt)"),'r+')`
Then there's some code to display the path using "inputfile.name".
The second function is like this:
def run_conversion(self):
global inputfile
if inputfile: # if user didn't pick a file don't continue
#do stuff
inputfile.close()
I know using global variables is not good practise, so how can I pass the open file from one function to another and have it so that the user clicks the second button before the "stuff" is run on the file?
I want them to be able to check it's the right file before doing the "stuff" on it.
Thanks
Use inputfile as field of the class, in this way there is no need to pass the file as a parameter or to use a global.
class MyClass:
def browse_inputfile(self):
self.inputfile = open(QtGui.QFileDialog.getOpenFileName(self, "Open Data File", "", "txt files (*.txt)"),'r+')`
# you code for display the path
def run_conversion(self):
if self.inputfile: # if user didn't pick a file don't continue
#do stuff
self.inputfile.close()
Your current method risks inputfile not being closed on exit. I would do something like this:
file_path = None
def browse_inputfile(self):
return QtGui.QFileDialog.getOpenFileName(self, 'Openfile', '/home')
def run_conversion(self, path):
if path: # if user didn't pick a file don't continue
with open(path) as f:
#do stuff
If you want to manipulate file names robustly, use the functions in the os.path module https://docs.python.org/2/library/os.path.html.

wxPython FileOutputStream error

I'm trying to learn wxPython/python and I want to save text in a file. I found this example
def OnSaveAs(self, e):
saveFileDialog = wx.FileDialog(self, "SAVE txt file", "", "", "Textdocument (*.txt)|*.txt", wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT)
if saveFileDialog.ShowModal() == wx.ID_CANCEL:
return # User canceled
# save the current contents in the file
# this can be done with e.g. wxPython output streams:
output_stream = wx.FileOutputStream(saveFileDialog.GetPath())
#My question: Insert what to write to output_stream here?
if not out_stream.IsOk():
wx.LogError("Cannot save current contents in file '%s'."%saveFileDialog.GetPath())
return
I get the error
in OnSaveAs output_stream = wx.FileOutputStream(saveFileDialog.GetPath()) AttributeError 'module' object has no attribute 'FileOutputStream'
Shouldnt output_stream contain the path to the file i want to save. And then I write to output_stream to save text in the file?
Thanks in advance!
Just use the Python functions to open and write content to the file. Something like this:
output = open(saveFileDialog.GetPath(), 'w')
ouput.write(stuff)
ouput.close()
In almost all cases wxPython only wraps the wxWidgets classes and functions which do not already have an equivallent in Python, and the AttributeError is telling you that there is no wx.FileOutputStream class available.

Lauch default editor (like 'webbrowser' module)

Is there a simple way to lauch the systems default editor from a Python command-line tool, like the webbrowser module?
Under windows you can simply "execute" the file and the default action will be taken:
os.system('c:/tmp/sample.txt')
For this example a default editor will spawn. Under UNIX there is an environment variable called EDITOR, so you need to use something like:
os.system('%s %s' % (os.getenv('EDITOR'), filename))
The modern Linux way to open a file is using xdg-open; however it does not guarantee that a text editor will open the file. Using $EDITOR is appropriate if your program is command-line oriented (and your users).
If you need to open a file for editing, you could be interested in this question.
You can actually use the webbrowser module to do this. All the answers given so far for both this and the linked question are just the same things the webbrowser module does behind the hood.
The ONLY difference is if they have $EDITOR set, which is rare. So perhaps a better flow would be:
editor = os.getenv('EDITOR')
if editor:
os.system(editor + ' ' + filename)
else:
webbrowser.open(filename)
OK, now that I’ve told you that, I should let you know that the webbrowser module does state that it does not support this case.
Note that on some platforms, trying to open a filename using this function, may work and start the operating system's associated program. However, this is neither supported nor portable.
So if it doesn't work, don’t submit a bug report. But for most uses, it should work.
As the committer of the python Y-Principle generator i had the need to check the generated files against the original and wanted to call a diff-capable editor from python.
My search pointed me to this questions and the most upvoted answer had some comments and follow-up issue that i'd also want to address:
make sure the EDITOR env variable is used if set
make sure things work on MacOS (defaulting to Atom in my case)
make sure a text can be opened in a temporary file
make sure that if an url is opened the html text is extracted by default
You'll find the solution at editory.py and the test case at test_editor.py in my project's repository.
Test Code
'''
Created on 2022-11-27
#author: wf
'''
from tests.basetest import Basetest
from yprinciple.editor import Editor
class TestEditor(Basetest):
"""
test opening an editor
"""
def test_Editor(self):
"""
test the editor
"""
if not self.inPublicCI():
# open this source file
Editor.open(__file__)
Editor.open("https://stackoverflow.com/questions/1442841/lauch-default-editor-like-webbrowser-module")
Editor.open_tmp_text("A sample text to be opened in a temporary file")
Screenshot
Source Code
'''
Created on 2022-11-27
#author: wf
'''
from sys import platform
import os
import tempfile
from urllib.request import urlopen
from bs4 import BeautifulSoup
class Editor:
"""
helper class to open the system defined editor
see https://stackoverflow.com/questions/1442841/lauch-default-editor-like-webbrowser-module
"""
#classmethod
def extract_text(cls,html_text:str)->str:
"""
extract the text from the given html_text
Args:
html_text(str): the input for the html text
Returns:
str: the plain text
"""
soup = BeautifulSoup(html_text, features="html.parser")
# kill all script and style elements
for script in soup(["script", "style"]):
script.extract() # rip it out
# get text
text = soup.get_text()
# break into lines and remove leading and trailing space on each
lines = (line.strip() for line in text.splitlines())
# break multi-headlines into a line each
chunks = (phrase.strip() for line in lines for phrase in line.split(" "))
# drop blank lines
text = '\n'.join(chunk for chunk in chunks if chunk)
return text
#classmethod
def open(cls,file_source:str,extract_text:bool=True)->str:
"""
open an editor for the given file_source
Args:
file_source(str): the path to the file
extract_text(bool): if True extract the text from html sources
Returns:
str: the path to the file e.g. a temporary file if the file_source points to an url
"""
# handle urls
# https://stackoverflow.com/a/45886824/1497139
if file_source.startswith("http"):
url_source = urlopen(file_source)
#https://stackoverflow.com/a/19156107/1497139
charset=url_source.headers.get_content_charset()
# if charset fails here you might want to set it to utf-8 as a default!
text = url_source.read().decode(charset)
if extract_text:
# https://stackoverflow.com/a/24618186/1497139
text=cls.extract_text(text)
return cls.open_tmp_text(text)
editor_cmd=None
editor_env=os.getenv('EDITOR')
if editor_env:
editor_cmd=editor_env
if platform == "darwin":
if not editor_env:
# https://stackoverflow.com/questions/22390709/how-can-i-open-the-atom-editor-from-the-command-line-in-os-x
editor_cmd="/usr/local/bin/atom"
os_cmd=f"{editor_cmd} {file_source}"
os.system(os_cmd)
return file_source
#classmethod
def open_tmp_text(cls,text:str)->str:
"""
open an editor for the given text in a newly created temporary file
Args:
text(str): the text to write to a temporary file and then open
Returns:
str: the path to the temp file
"""
# see https://stackoverflow.com/a/8577226/1497139
# https://stackoverflow.com/a/3924253/1497139
with tempfile.NamedTemporaryFile(delete=False) as tmp:
with open(tmp.name,"w") as tmp_file:
tmp_file.write(text)
tmp_file.close()
return cls.open(tmp.name)
Stackoverflow answers applied
https://stackoverflow.com/a/45886824/1497139
https://stackoverflow.com/a/19156107/1497139
https://stackoverflow.com/a/24618186/1497139
How can I open the Atom editor from the command line in OS X?
https://stackoverflow.com/a/8577226/1497139
https://stackoverflow.com/a/3924253/1497139

Categories

Resources