I tried to write a simple program for converting PDF files to JPG. The main idea is a simple .exe file that will find all PDF files in the same directory, and after converting them to JPG put them in the new folder.
And I did it! Using pdf2image, my program doing exactly as I want and as .py and as .exe. But, after running this program on another PC I got an error with popper >following Cmd screenshot
So, I understand, the program tries to find a popper. And sure on another PC program can't find it.
I tried --hidden-import, and --onedir, --onefile e.t.c.
Also saw some similar problem here, as:
PyInstaller and Poppler
Include poppler while generating an application using pyinstaller
But, or I do something wrong, or can't clearly understand how to do solutions in this questions.
What should I do?
#P.S. Maybe, there is a better library or module to create this kind of program?
Whole code:
import os
import pdf2image
from pdf2image import convert_from_path
from inspect import getsourcefile
from pdf2image.exceptions import (
PDFInfoNotInstalledError,
PDFPageCountError,
PDFSyntaxError
)
# Create output direction
# Direction of executable file
script_dir = os.path.abspath(getsourcefile(lambda:0))
# print(script_dir)
output_dir = 'JPG'
# List for files which wasn't converted
error_list = []
# If path don't exist - create
if not os.path.exists(output_dir):
os.makedirs(output_dir)
#print('Path has been created', "\n")
else:
pass
#print('Directory exist', "\n")
# Show all files in directory
file_list = os.listdir()
print(file_list, "List of files")
for file in file_list:
try:
# print(file)
pages = convert_from_path(file, dpi=300, fmt='jpg', output_folder=output_dir, output_file=file)
except Exception as e: print(e)
print("File wasn't converted:", "\n")
if len(error_list) == 0:
print(0, "\n")
else:
for f in error_list:
print(f)
input("Done! Press Enter")
Related
Hi everyone I have a problem with a simple app (at least the MRE is simple) packed with pyinstaller.
This desktop app should display a simple SVG file (I use tksvg).
My app first writes SVG into a temporary directory (writing is not as simple as in MRE), and then in the right moment displays it. It works nicely until I've packed it with pyinstaller.
My full app console throws me an error that the file can't be found. The path always ends with \tksvg. And such directory don't exist.
It looks as if tksvg would create such a subfolder but pyinstaller is missing such instructions?
Any ideas on what can I do?
Warning, total noob.
Thanks
from tkinter import *
import tempfile
import tksvg
root = Tk()
temp_dir = tempfile.TemporaryDirectory()
print(temp_dir.name)
with open(temp_dir.name + f'\\test.svg', 'w') as a_file:
a_file.write('<svg viewBox="0 0 400 400"><rect x="0" y="0" width="400" height="400" fill="red" /></svg>')
svg_image = tksvg.SvgImage(file=temp_dir.name + f'\\test.svg')
show_svg = Label(root, image=svg_image)
show_svg.pack()
mainloop()
Edit
After some fight with the subject, I'm certain that it must be an issue with how pyinstaller packs libraries, a specially tksvg.
Method proposed by #JRiggles in itself works, but not with tksvg objects, and it's not necessary in my case (I use a temporary directory to manage files).
To check if the temporary directory works also when packed (pyinstaller), I've created "jpeg viewer" script and it works perfectly, even using PIL libraries.
from tkinter import *
import tempfile
from tkinter import filedialog
from PIL import Image, ImageTk
root = Tk()
temp_dir = tempfile.TemporaryDirectory()
print(temp_dir.name) # just to check if temp. dir. was created
jpeg_file = filedialog.askopenfilename(filetypes=[("jpeg file", "*.jpeg")]) # opening file from disc
picture = Image.open(jpeg_file) # reading it with PIL library
picture.save(temp_dir.name+'\\test.jpeg') # saving image to temp. dir.
an_image = Image.open(temp_dir.name + '\\test.jpeg') # opening image from temp.dir.
the_image = ImageTk.PhotoImage(an_image) # reading image
show_image = Label(root, image=the_image) # setting label as "display"
show_image.pack() # showing the image
mainloop()
Does anyone has experience with SVG libraries, tksvg or any other, and how to make exe. with them?
Pyinstaller places your assets (images, icons, whatever) in a special directory that's created in your temp dir at runtime. I use this fetch_resource function to dynamically load assets when running a pyinstaller executable
import sys
from pathlib import Path
def fetch_resource(rsrc_path):
"""Loads resources from the temp dir used by pyinstaller executables"""
try:
base_path = Path(sys._MEIPASS)
except AttributeError:
return rsrc_path # not running as exe, just return the unaltered path
else:
return base_path.joinpath(rsrc_path)
In your case, you would use it like so:
svg_path = fetch_resource(r'path\to\test.svg')
with open(svg_path, 'w') as a_file:
...
svg_image = tksvg.SvgImage(file=svg_path)
You'll need to tell pyinstaller where to locate any files you want to 'fetch' by using the --add-data command-line or by adding the path to the datas list in your *.spec file
After some time it turn out that it was enough to add --collect-all="tksvg" to the pyinstaller. Maybe you could be more specific about what was missing in the compiled pack, but I have no competence to judge it, so I went for a safe collect-all.
THX
Error image
from pathlib import Path
import linecache
import pyperclip
print('Looking for a path...')
print('Found path!')
Path('C:/Users/Akush/Documents/Warcraft III/CustomMapData/YouTD/')
a = linecache.getline('savecode.txt',7)
pyperclip.copy(a)
print('{} copied to clipboard!'.format(a))
So everything works fine in pycharm, but when i made .exe from .py it gives "Module not found" error in CMD
Do you know what i did wrong here?
thanks for help!
Since you are using pycharm, make sure you are using the correct python interpreter in the project settings. If you are using the system interpreter, the modules won't be found in a virtual environment
I cleaned up your code a little:
import os
from pathlib import Path
import linecache
import pyperclip
# Specify the path
dir = Path('C:/Users/Akush/Documents/Warcraft III/CustomMapData/YouTD/')
# Specify the file
file = 'savecode.txt'
# Start Searching for Path
print('Looking for a path...')
# Check if Path exists
if dir.is_dir():
# Set the currect working directory to the found path
os.chdir(dir)
# Let the user know the path has been found
print('Found path!')
# Check to see if the file exists
if Path(file).is_file():
# Get lines from file
a = linecache.getline(file, 7)
if a == '':
print('Nothing found in file')
else:
# Copy line to clipboard
pyperclip.copy(a)
print(f'{a} copied to clipboard!')
else:
print("File not found")
else:
print('This directory does not exist')
I have two files, one bell.mp3 one main.py file, that plays back bell.mp3 via subprocess.
If I do:
pyinstaller main.py
the Dist file ends up correctly, and everything works fine, The program runs in a directory.
This is the code for my file which i call pyinst_tester.py
it creates a text file, and plays a bell.mp3 file
#
from con import * # this is just a configuration file that has g='play' in it.
import subprocess
f=open(r'/home/godzilla/Desktop/Pyinstaller testing/testfile1','w')
f.write('This has worked')
f.close()
file='/home/godzilla/Desktop/Pyinstaller testing/data/bell.mp3'
if 'play' == g:
subprocess.call(['/usr/bin/cvlc',file])
a single file is created, but if I delete the bell.mp3 file it doesn't work. In a single file isn't the bell.mp3 zipped inside the main.exe ? therefore, redundant as a separate file ?
What Is the point having a single file exe, if you need an adjacent file with all the mp3s inside?
Pyinstaller has many features and if you want to include non python files (for example mp3 files) you have to do so explicitly with the --add-binary switch.
In one file mode the executable will be unpacked into a temporary directory prior to execution of the python code.
So how to write your code to access these data files.
You might want to look at the pyinstaller documention at following sections:
https://pyinstaller.readthedocs.io/en/stable/runtime-information.html#run-time-information
https://pyinstaller.readthedocs.io/en/stable/runtime-information.html#using-sys-executable-and-sys-argv-0
I personally place all my files in a separate directory. e.g. data.
If you place the file bell.mp3 in the directory data, then you had to call pyinstaller with the option --add-binary data:data
in the one file mode the executable is extracted into a temporary directory
whose path you get get from the variable sys._MEIPASS
Your data directory will bi in the sub directory data of sys._MEIPASS
In my example I create a function, that will be able to locate the data files in normal python mode and in pyinstaller one file or one directory mode.
Just try it out it should be self explaining
simple example:
minitst.py
import os, sys
import time
is_frozen = getattr(sys, "frozen", False)
MYDIR = os.path.realpath(os.path.dirname(__file__))
def data_fname(fname):
if is_frozen:
return os.path.join(sys._MEIPASS, "data", fname)
else:
return os.path.join(MYDIR, "data", fname)
def main():
print("This application is %s frozen" %
("" if is_frozen else "not"))
print("executable =", sys.executable,
"File =", __file__,
"mydir =", MYDIR)
if is_frozen:
print("MEIPASS", sys._MEIPASS)
fname = data_fname("tst.txt")
print("will open", fname)
with open(fname) as fin:
print(fin.read())
time.sleep(5) # this shall allow to view the console e.g. on windows if clicking on the executable.
if __name__ == "__main__":
main()
now create a directory data and place a file "tst.txt"
data/tst.txt
Hello world
Now call
pyinstaller -F minitst.py --add-binary data:data -c
and call dist/minitst from a console.
The output should look like:
This application is frozen
executable = /home/gelonida/so/pyinst/dist/minitst File = minitst.py mydir = /home/gelonida/so/pyinst
MEIPASS /tmp/_MEIKGqah9
will open /tmp/_MEIKGqah9/data/tst.txt
Hello
Now concerning your code.
I compacted the code to determine the datadir a little, but it is the same logic as in the upper example
import os, sys
from con import * # this is just a configuration file that has g='play' in it.
import subprocess
basedir = getattr(sys, "_MEIPASS", os.path.realpath(os.path.dirname(__file__)))
f=open('testfile1','w')
f.write('This has worked')
f.close()
file=os.path.join(basedir, 'data/bell.mp3')
if 'play' == g:
subprocess.call(['/usr/bin/cvlc',file])
New to coding, reading some books and trying to practice. Wrote a program in python3.7 to search through a directory, find all the pdf files and move them to a new folder called 'Reading Materials'.
How could I improve on this code e.g a shorter, more concise and/or efficient script in python?
import os, re, shutil
os.chdir(r'C:\\Users\\Luke\\Documents\\coding\\python\\') #set cwd to the where I want program to run
#create regex to identify pdf files
PDFregex = re.compile(r'''^(.*?) # all text before the file extension
\.{1} #start of file extension
(pdf)$ #ending in pdf''', re.VERBOSE)
Newdir = os.mkdir('Reading Material') #make new directory for files
NewdirPath = os.path.abspath('Reading Material')
print('new directory made at : '+NewdirPath)
#search through directory for files that contain .pdf extension using regex object
for pdf in os.listdir('.'):
mo = PDFregex.search(pdf)
if mo == None: #no pdf's found by regex search
continue #bypass loop
else:
originalLoc = os.path.join(os.path.abspath('.'), pdf) #original file location
newLoc = shutil.move(originalLoc, os.path.join(NewdirPath, pdf)) #move pdf to new folder
print('Moving file "%s" moved to "%s"...' %(pdf, newLoc)) #say what's moving
os.listdir(NewdirPath)
Regexp is overkilled here. os module has various method to help you extract informations about files.
You can use splitext method in os module to find the extension.
Something like this should work :
import os
import shutil
old_dir = 'C:\\Users\\Luke\\Documents\\coding\\python\\'
new_dir = 'Reading Material'
# You should always use underscore_notations to name variables instead of CamelCase (use for ClassNames) see https://www.python.org/dev/peps/pep-0008/
os.makedirs(new_dir, exist_ok=True)
for file_path in os.listdir(old_dir):
if os.path.splitext(file_path)[1] == '.pdf':
shutil.move(file_path, '{0}\\{1}'.format(new_dir, os.path.basename(file_path)))
I know this is going to be frustratingly easy for many of you. I am just beginning to learn Python and need help with some basic file handling.
I take a lot of screenshots, which end up on my desktop (as this is the default setting). I am aware I can change the screenshot setting to save it somewhere else automatically. However, I think this program will be a good way to teach me how to sort files. I would like to use python to automatically sort through all the files on my desktop, identify those that end with .png (the default file type for screenshots), and simply move it to a folder I've named "Archive".
This is what I've got so far:
import os
import shutil
source = os.listdir('/Users/kevinconnell/Desktop/Test_Folder/')
destination = 'Archive'
for files in source:
if files.endswith('.png'):
shutil.move(source, destination)
I've played around with it plenty to no avail. In this latest version, I am encountering the following error when I run the program:
Traceback (most recent call last):
File "pngmove_2.0.py", line 23, in
shutil.move(source, destination)
File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/shutil.py", line 290, in move
TypeError: coercing to Unicode: need string or buffer, list found
I am under the impression I have a sort of issue with the proper convention/syntax necessary for the source and destination. However, I've thus far been unable to find much help on how to fix it. I used os.path.abspath() to determine the file path you see above.
Thanks in advance for any help in preserving my sanity.
LATEST UPDATE
I believe I am very close to getting to the bottom of this. I'm sure if I continue to play around with it I'll figure it out. Just so everyone that's been helping me is updated...
This is the current code I'm working with:
import os
import shutil
sourcepath ='/Users/kevinconnell/Desktop/'
source = os.listdir(sourcepath)
destinationpath = '/Users/kevinconnell/Desktop/'
for files in source:
if files.endswith('.png'):
shutil.move(os.path.join(sourcepath,'Test_Folder'), os.path.join(destinationpath,'Archive'))
This works for renaming my 'Test_Folder' folder to 'Archive'. However, it moves all the files in the folder, instead of moving the files that end with '.png'.
You're trying to move the whole source folder, you need to specify a file path
import os
import shutil
sourcepath='C:/Users/kevinconnell/Desktop/Test_Folder/'
sourcefiles = os.listdir(sourcepath)
destinationpath = 'C:/Users/kevinconnell/Desktop/Test_Folder/Archive'
for file in sourcefiles:
if file.endswith('.png'):
shutil.move(os.path.join(sourcepath,file), os.path.join(destinationpath,file))
Another option is using glob module, which let's you specify file mask and retrieve list of desired files.
It should be as simple as
import glob
import shutil
# I prefer to set path and mask as variables, but of course you can use values
# inside glob() and move()
source_files='/Users/kevinconnell/Desktop/Test_Folder/*.png'
target_folder='/Users/kevinconnell/Dekstop/Test_Folder/Archive'
# retrieve file list
filelist=glob.glob(source_files)
for single_file in filelist:
# move file with full paths as shutil.move() parameters
shutil.move(single_file,target_folder)
Nevertheless, if you're using glob or os.listdir, remember to set full paths for source file and target.
Based on #Gabriels answer.
I have put some effort into this as, I like to "Categorize" my file types into folders. I now use this.
I believe this is what you are looking for, this was fun to figure out
This Script:
Shows Example files to be moved until you uncomment shutil.move
Is in Python3
Was Designed On a MacOSX
Will not create folders for you, it will throw an error
Can find and move files with extension you desire
Can be used to Ignore folders
Including the destination folder, should it be nested in your search folder
Can be found in my Github Repo
Example from Terminal:
$ python organize_files.py
filetomove: /Users/jkirchoff/Desktop/Screen Shot 2018-05-15 at 12.16.21 AM.png
movingfileto: /Users/jkirchoff/Pictures/Archive/Screen Shot 2018-05-15 at 12.16.21 AM.png
Script:
I named organize_files.py
#!/usr/bin/env python3
# =============================================================================
# Created On : MAC OSX High Sierra 10.13.4 (17E199)
# Created By : Jeromie Kirchoff
# Created Date: Mon May 14 21:46:03 PDT 2018
# =============================================================================
# Answer for: https://stackoverflow.com/a/23561726/1896134 PNG Archive
# NOTE: THIS WILL NOT CREATE THE DESTINATION FOLDER(S)
# =============================================================================
import os
import shutil
file_extensn = '.png'
mac_username = 'jkirchoff'
search_dir = '/Users/' + mac_username + '/Desktop/'
target_foldr = '/Users/' + mac_username + '/Pictures/Archive/'
ignore_fldrs = [target_foldr,
'/Users/' + mac_username + '/Documents/',
'/Users/' + mac_username + '/AnotherFolder/'
]
for subdir, dirs, files in os.walk(search_dir):
for file in files:
if subdir not in ignore_fldrs and file.endswith(file_extensn):
# print('I would Move this file: ' + str(subdir) + str(file)
# # + "\n To this folder:" + str(target_foldr) + str(file)
# )
filetomove = (str(subdir) + str(file))
movingfileto = (str(target_foldr) + str(file))
print("filetomove: " + str(filetomove))
print("movingfileto: " + str(movingfileto))
# =================================================================
# IF YOU ARE HAPPY WITH THE RESULTS
# UNCOMMENT THE SHUTIL TO MOVE THE FILES
# =================================================================
# shutil.move(filetomove, movingfileto)
pass
elif file.endswith(file_extensn):
# print('Theres no need to move these files: '
# + str(subdir) + str(file))
pass
else:
# print('Theres no need to move these files either: '
# + str(subdir) + str(file))
pass
import os
import shutil
Folder_Target = input("Path Target which Contain The File Need To Move it: ")
File_Extension = input("What Is The File Extension ? [For Example >> pdf , txt , exe , ...etc] : ")
Folder_Path = input("Path To Move in it : ")
Transformes_Loges = input("Path To Send Logs Of Operation in : ")
x=0
file_logs=open(Transformes_Loges+"\\Logs.txt",mode="a+")
for folder, sub_folder, file in os.walk(Folder_Target):
for sub_folder in file:
if os.path.join(folder, sub_folder)[-3:]==File_Extension:
path= os.path.join(folder, sub_folder)
file_logs.write(path+" ===================== Was Moved to ========================>> "+Folder_Path )
file_logs.write("\n")
shutil.move(path, Folder_Path)
x+=1
file_logs.close()
print("["+str(x)+"]"+"File Transformed")