I’m writing a small pywin32 program that converts text files to docx/pdf and that’s all chill and working. BUT… I haven’t figured out a way to unittest the coverter that would not require creating tempfiles. The proccess is really slow.
Is there a commonly accepted good practice on unittesting operations on files?
The converter + unittests below.
# file converter.py
import win32com.client as win32
class Converter:
def __init__(self):
self.word = win32.Dispatch('Word.Application')
self.word.Visible = False
self._word_format = {
'docx': 12,
'pdf': 17
}
#property
def word_format(self):
return self._word_format
def open_and_close(func):
def wrapper(self, fpath):
doc = self.word.Documents.Open(str(fpath))
doc.Activate()
func(self, fpath)
doc.Close()
return wrapper
#open_and_close
def to_docx(self, fpath):
new_fpath = str(fpath).replace('.doc', '.docx')
self.word.ActiveDocument.SaveAs(new_fpath, FileFormat=self.word_format['docx'])
#open_and_close
def to_pdf(self, fpath):
new_fpath = str(fpath).replace('.doc', '.pdf')
self.word.ActiveDocument.SaveAs(new_fpath, FileFormat=self.word_format['pdf'])
def __del__(self):
self.word.Quit()
# file test_converter.py
import unittest
import tempfile
import os
from pathlib import Path
from converter import Converter
class TestConverterToDocx(unittest.TestCase):
#classmethod
def setUpClass(cls):
cls.converter = Converter()
def setUp(self):
self.tempdir = tempfile.TemporaryDirectory()
for _ in range(5):
tempfile.NamedTemporaryFile(dir=self.tempdir.name,
suffix='.doc', delete=False)
def tearDown(self):
self.tempdir.cleanup()
def test_to_docx(self):
for root, dirs, files in os.walk(self.tempdir.name):
for file in files:
self.converter.to_docx(str(Path(root) / file))
files = [file for file in os.listdir(self.tempdir.name)
if file.endswith('.docx')]
self.assertEqual(len(files), 5)
def test_to_pdf(self):
for root, dirs, files in os.walk(self.tempdir.name):
for file in files:
self.converter.to_pdf(str(Path(root) / file))
files = [file for file in os.listdir(self.tempdir.name)
if file.endswith('.pdf')]
self.assertEqual(len(files), 5)
Related
I would like to select files in a QTreeView and in the end I would like to get the path of the selected files, what should I do?
Here is a small example that I partly found on stackoverflow that I transformed a bit:
from PyQt5.QtCore import QDir, Qt
from PyQt5.QtWidgets import QFileSystemModel, QTreeView, QAbstractItemView, QApplication, QFileIconProvider
from PyQt5.QtGui import QIcon
import sys, os
from chemin_data_ressources import chemin_ressources
class ArbreArborescence(QTreeView):
def __init__(self, parent=None):
super(ArbreArborescence, self).__init__(parent)
self.setDragEnabled(True)
self.setDragDropMode(QAbstractItemView.DragOnly)
self.setDefaultDropAction(Qt.CopyAction)
self.setAlternatingRowColors(True)
self.setSelectionMode(QAbstractItemView.SingleSelection)
self.setStyleSheet("background-color: rgb(180, 180, 180);alternate-background-color: rgb(180, 180, 180);")
def set_source(self, folder):
""" """
self.up_folder = os.path.dirname(folder)
self.dirModel = QFileSystemModel()
self.dirModel.setRootPath(QDir.homePath()) # Sous windows QDir.Drives() éventuellement
self.setModel(self.dirModel)
self.setRootIndex(self.dirModel.index(self.up_folder)) #
self.setWordWrap(True)
self.hideColumn(1)
self.hideColumn(2)
self.hideColumn(3)
idx = self.dirModel.index(folder)
self.expand(idx)
self.scrollTo(idx, QAbstractItemView.EnsureVisible)
self.dirModel.setNameFilters(["*.jpg", "*.jpeg", "*.png", "*.gif"])
self.dirModel.setNameFilterDisables(False)
self.dirModel.setIconProvider(IconProvider())
class IconProvider(QFileIconProvider):
def icon(self, fileInfo):
if fileInfo.isDir():
return QIcon(chemin_ressources(os.path.join('ressources_murexpo', 'icone_png_dossier_apsc_256x256.png')))
return QFileIconProvider.icon(self, fileInfo)
if __name__=='__main__':
app = QApplication(sys.argv)
w = ArbreArborescence()
w.set_source(os.path.expanduser('~')) # Fonctionne ! (ou '/home')
w.show()
app.exec_()
Help me please.
Use QFileSystemModel.filePath to get the path of an item at a given QModelIndex.
class ArbreArborescence(QTreeView):
...
def currentChanged(self, current, previous):
print(self.model().filePath(current))
super().currentChanged(current, previous)
I am having sample program with file name myAutocomplete.py and want to return instance of class
import cloudpickle
class Autocomplete(object):
def __init__(self):
self.test = " Test String "
def assign_value(self):
self.test = "Hello"
return self.test
def get_value(self):
return self.test
#staticmethod
def save(path):
with open(path, "wb") as f:
cloudpickle.dump(Autocomplete, f)
#staticmethod
def load(path):
with open(path, "rb") as f:
test = cloudpickle.load(f)
return test
and another file with name main.py
from myAutocomplete import Autocomplete
if __name__ == '__main__':
testobj = Autocomplete()
testobj.assign_value()
testobj.save("test.pkl")
test = testobj.load("test.pkl")
print(test().get_value())
i expecting output as
"Hello"
but i am getting output as
"Test String"
plz help
I have a simple luigi pipeline.
import luigi
import subprocess
import row_count_test
class TaskOne(luigi.Task):
def requires(self):
return None
def run(self):
output = row_count_test()
if output:
with self.output().open('w') as open_file:
open_file.write('{}'.format(output))
def output(self):
return luigi.LocalTarget('TaskOne.txt')
class TaskTwo(luigi.Task):
def requires(self):
return TaskOne()
def run(self):
subprocess.call('rm *.txt', shell = True)
if __name__ == "__main__":
luigi.run()
I run the following code through command line:
python luigi_demo.py --scheduler-host localhost TaskTwo
I want to be able to save the terminal output to a log file. I also want to be able to add a time stamp to the log file name. I know there's a way to do it through bash commands. Is there a way to do this using luigi? I looked at the luigi.cfg documentation and it wasn't too helpful. A simple example would be greatly appreciated.
You just have to changes the following to your TaskTwo.
import datetime as dt
class TaskTwo(luigi.Task):
date= luigi.DateSecondParameter(default=dt.datetime.now())
def output(self):
# Here you create a file with your date in it.
return luigi.LocalTarget('path/to/your/log/file%s.txt' % self.date)
def requires(self):
return TaskOne()
def run(self):
self.output().open('w') as f:
subprocess.call('rm *.txt', shell = True,stdout=f)
Also, on a side note if you want to delete the file created in the Taskone then you can remove all the code in the run() then just add self.input().remove()
class TaskTwo(luigi.Task):
date= luigi.DateSecondParameter(default=dt.datetime.now())
def output():
return luigi.LocalTarget('path/to/your/log/file%s.txt' % self.date)
def requires(self):
return TaskOne()
def run(self):
# this should remove the file created in the Task one.
self.input().remove()
I have a list of items in a QTreeView. Each item holds a QImage object. If I try to drag and drop the item, the program freezes. But when I comment out the line objMod._Image = QImage(flags = Qt.AutoColor), the program runs fine.
How can I drag and drop the items with the QImage object? The QImage holds an image which is rendered. The rendering process takes a while, so it would be nice to keep the QImage object.
import sys
import os
from PySide.QtCore import *
from PySide.QtGui import *
from PySide.QtUiTools import *
from PIL import Image, ImageCms, ImageQt
class ObjModel:
def __init__(self):
self._Image = None
class DragMoveTest(QMainWindow):
def __init__(self):
super(DragMoveTest,self).__init__()
self.initGUI()
self.show()
def initGUI(self):
self.treeView = QTreeView()
modelTreeView = QStandardItemModel()
self.treeView.setModel(modelTreeView)
for i in range(0, 4):
objMod = ObjModel()
objMod._Image = None
objMod._Image = QImage(flags = Qt.AutoColor)
item = QStandardItem('Test: %s' % str(i))
item.setData(objMod, Qt.UserRole + 1)
modelTreeView.invisibleRootItem().appendRow(item)
self.treeView.setDragDropMode(QAbstractItemView.InternalMove)
self.setCentralWidget(self.treeView)
def main(args):
app = QApplication(sys.argv)
qt_main_wnd = DragMoveTest()
ret = app.exec_()
sys.exit(ret)
if __name__ == "__main__":
main(sys.argv)
This is caused by a bug in PySide. During a drag and drop operation, the data in the dragged item must be serialized. This will be handled by Qt for most data-types, but for types that are specific to Python, special handling is required. This special handling seems to be broken in PySide. If your example is converted to PyQt, a TypeError is raised when trying to drag items, but the program does not freeze.
The source of the problem is that you are storing data using a custom Python class. PyQt uses pickle to serialize custom data-types, but it is not possible to also pickle the QImage that is stored in its __dict__, so the operation fails. I assume PySide must attempt something similar, but for some reason it does not raise an error when it fails. Qt grabs the mouse whilst dragging, so if the operation fails abnormally, it won't be released again, and the program will appear to freeze.
The simplest way to fix this is to avoid using a custom class to hold the QImage, and instead store the image directly in the item:
image = QImage()
item = QStandardItem('Test: %s' % i)
item.setData(image, Qt.UserRole + 1)
To store more data items, you can either use a different data-role for each one, or use a dict to hold them all:
data = {'image': QImage(), 'title': 'foo', 'timestamp': 1756790}
item.setData(data, Qt.UserRole + 1)
However, if you do this, you must always use string keys in the dict, otherwise you will face the same problems as before. (Using string keys means the dict can be converted into a QMap, which Qt knows how to serialize).
(NB: if you want to know whether a Qt class can be serialized, check the docs to see whether it defines the datastream operators).
I come up with a different solution. It is easier to have a object that holds a io.BytesIO. Your store the ImageData into the bytesIO variable. Upon on your image library you can open the image from the bytesIO variable.
In the demo the class ObjModel can handle QImage and Image from Pillow/PIL. If you use the set methods the image object will be converted into a bytesIO.
In short here a working example:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import sys
import os
import io
from PySide.QtCore import *
from PySide.QtGui import *
from PySide.QtUiTools import *
from PIL import Image, ImageCms, ImageQt
########################################################################
class ObjModel:
""""""
#----------------------------------------------------------------------
def __init__(self):
"""Constructor"""
self._ImageByteIO = None
#----------------------------------------------------------------------
def getObjByte(self):
""""""
return self._ImageByteIO
#----------------------------------------------------------------------
def getQImage(self):
""""""
try:
self._ImageByteIO.seek(0)
qImg = QImage.fromData(self._ImageByteIO.getvalue())
return qImg
except:
return None
#----------------------------------------------------------------------
def getPILImage(self):
""""""
try:
self._ImageByteIO.seek(0)
img = Image.open(tBytesIO)
return img
except:
return None
#----------------------------------------------------------------------
def setObjByte(self, fileName):
""""""
try:
tBytesIO = io.BytesIO()
f = open (fileName, 'rb')
tBytesIO.write(f.read())
f.close()
self._ImageByteIO = tBytesIO
except:
self._ImageByteIO = None
#----------------------------------------------------------------------
def setQImage(self, qImg):
""""""
try:
tBytesIO = io.BytesIO()
qByteArray = QByteArray()
qBuf = QBuffer(qByteArray)
qBuf.open(QIODevice.ReadWrite)
qImg.save(qBuf, 'PNG')
tBytesIO = io.BytesIO()
tBytesIO.write(qByteArray.data())
self._ImageByteIO = tBytesIO
except:
self._ImageByteIO = None
#----------------------------------------------------------------------
def setPILImage(self, pImg):
""""""
tBytesIO = io.BytesIO()
pImg.save(tBytesIO, 'png')
self._ImageByteIO = tBytesIO
#----------------------------------------------------------------------
class DragMoveTest(QMainWindow):
def __init__(self):
""""""
super(DragMoveTest,self).__init__()
self.initGUI()
self.show()
#----------------------------------------------------------------------
def initGUI(self):
""""""
self.treeView = QTreeView()
modelTreeView = QStandardItemModel()
self.treeView.setModel(modelTreeView)
for i in range(0, 4):
objMod = ObjModel()
objMod.setQImage(QImage(flags = Qt.AutoColor))
item = QStandardItem('Test: %s' % str(i))
item.setData(objMod, Qt.UserRole + 1)
modelTreeView.invisibleRootItem().appendRow(item)
self.treeView.setDragDropMode(QAbstractItemView.InternalMove)
self.setCentralWidget(self.treeView)
#----------------------------------------------------------------------
def main(args):
app = QApplication(sys.argv)
qt_main_wnd = DragMoveTest()
ret = app.exec_()
sys.exit(ret)
#----------------------------------------------------------------------
if __name__ == "__main__":
main(sys.argv)
I have the following code. It works to serve the index.html or any file located in the home/ directory, but will not serve any files that are located in nested directories, such as home/image/xyz.png.
import os
import sys
import ctypes
import pprint
import bottle
import socket
from bottle import *
#global functions
def ReadStringFromFile( file ):
f = open(file, 'r')
data = f.read()
f.close()
return data
def getBits():
#get the system bits
sysBit = (ctypes.sizeof(ctypes.c_voidp) * 8)
if((not(sysBit == 32)) and (not (sysBit == 64))):
sysBit = 0
return sysBit
class DevelServer( object ):
addr = ''
def __init__( self ):
self.addr = socket.gethostbyname( socket.gethostname() )
pass
def index( self ):
return ReadStringFromFile('home/index.html')
#these are not the URLs you are looking for
def error404( self, error):
return '<br><br><br><center><h1>Go home, You\'re drunk.'
def send_static( self, filename):
print (static_file(filename, root=os.path.join(os.getcwd(), 'home')))
return static_file(filename, root=os.path.join(os.getcwd(), 'home'))
#start hosting the application
def startThis( self ):
bottle.run(host=self.addr, port=80, debug=True)
#instatiate the main application class an initalize all of the app routes
def Main():
ThisApp = DevelServer()
bottle.route('/')(ThisApp.index)
bottle.route('/home/<filename>')(ThisApp.send_static)
bottle.error(404)(ThisApp.error404)
ThisApp.startThis()
Main()
Change this line:
bottle.route('/home/<filename>')(ThisApp.send_static)
to this:
bottle.route('/home/<filename:path>')(ThisApp.send_static)
(Add ":path".)
The Bottle docs explain why:
The static_file() function is a helper to serve files in a safe and
convenient way (see Static Files). This example is limited to files
directly within the /path/to/your/static/files directory because the
wildcard won’t match a path with a slash in it. To serve
files in subdirectories, change the wildcard to use the path filter...
I ran your code with my modification and it worked for me--does it work for you, too?