Inserting/overwriting a table after a paragraph (specific location) in a word file with docx python? - python

Does anybody know how to create/update a table with the docx library in a word document at a specific location.
So e.g. after a paragraph with text 'test1'?
The idea is to check if paragraph exists in the document, overwrite the existsing table underneath if not create a new paragraph and underneath at a certain location (at certain header level).
I managed to add a paragraph after a specific paragraph but it does not seem to work with tables in the same way.
I can not seem to find a link between the paragraph objects and creating a table object underneath that paragraph object or identifying the existing table object based on the paragraph.
A bit of context on the code, the code is first reading xaml files and writing this data in a word document. The first time the code is run it will create all subheadings and text/tables. With a second run the code will be updating the text/table values as the subheadings already exist.
e.g.
template:
02_BusinessProcess
00_Dispatcher
01_Initialization
after first run:
02_BusinessProcess
1.1 Xamlfilename
Text
Table
00_Dispatcher
2.1 Xamlfilenam
Text
01_Initialization
after second run:
02_BusinessProcess
1.1 Xamlfilename
Updated Text
Updated Table
00_Dispatcher
2.1 Xamlfilenam
Updated Text
01_Initialization
I want to add in the tables between these lines(newly created paragraphs).
paragraph1 = insert_paragraph_after(paragraph, xaml_obt.xamlfilename, style=document.styles['Heading 3'])
paragraph_annseq = insert_paragraph_after(paragraph1, xaml_obt.ann_seq, style=document.styles['No Spacing'])
paragraph_var = insert_paragraph_after(paragraph_annseq, "Variables - " + xaml_obt.xamlfilename,style=document.styles['Heading 4'])
paragraph_in_arg = insert_paragraph_after(paragraph_var, "In_Agruments - " + xaml_obt.xamlfilename, style=document.styles['Heading 4'])
paragraph_io_arg = insert_paragraph_after(paragraph_in_arg, "In_Out_Agruments - " + xaml_obt.xamlfilename, style=document.styles['Heading 4'])
insert_paragraph_after(paragraph_io_arg, "Out_Agruments - " + xaml_obt.xamlfilename, style=document.styles['Heading 4'])
Or update the table in this spot if the paragraph exists in the document:
if paragraph.style.name.startswith('Heading'):
if paragraph.text == xaml_obt.xamlfilename:
new_para = document.paragraphs[i + 1]
new_para.text = xaml_obt.ann_seq + "\n\n"
style = document.styles['No Spacing']
new_para.style = style
new_para.alignment = WD_ALIGN_PARAGRAPH.LEFT
Here is the complete code:
from tkinter import Tk, filedialog
import os
import json
from xml.etree import ElementTree as ET
import docx
from docx.oxml.xmlchemy import OxmlElement
from docx.text.paragraph import Paragraph
from docx.enum.text import WD_ALIGN_PARAGRAPH
import time
import win32com.client
import pandas as pd
class xamlinfo(object):
def __init__(self, name: object) -> object:
self.aut_block = str
self.xamlfilepath = str
self.xamlfilename = str
self.xaml_read = None
self.toplevelnaming = str
self.ann_seq = str
self.in_arguments = pd.DataFrame(columns=['Name', 'Type', 'Annotation'])
self.out_arguments = pd.DataFrame(columns=['Name', 'Type', 'Annotation'])
self.io_agruments = pd.DataFrame(columns=['Name', 'Type', 'Annotation'])
self.variables = pd.DataFrame(columns=['Name', 'Annotation'])
def selectfolder():
root = Tk() # pointing root to Tk() to use it as Tk() in program.
root.withdraw()
root.attributes('-topmost', True)
open_file = filedialog.askdirectory()
open_file = os.path.normpath(open_file)
print("Following filepath selected: ",open_file)
return open_file
def assignxamlobjects(listxamls, path):
if os.path.exists(path):
for root,dirs,files in os.walk(path):
for file in files:
xaml_obt = xamlinfo(os.path.basename(file))
xaml_obt.aut_block = os.path.basename(path)
xaml_obt.xamlfilename = file
xaml_obt.xamlfilepath = os.path.join(root,file)
tree = ET.parse(xaml_obt.xamlfilepath)
treeroot = tree.getroot()
xaml_obt.xaml_read = treeroot
top_sequence = treeroot.find(".//{*}Sequence")
xaml_obt.toplevelnaming = top_sequence.attrib["DisplayName"]
annotation = ""
annotationelements = [x for x in top_sequence.attrib if "annotationtext" in x.lower()]
if (len(annotationelements) > 0):
annotation = top_sequence.attrib[annotationelements[0]]
xaml_obt.ann_seq = annotation
listofelements = treeroot.findall(".//{*}Property")
for element in listofelements:
if "InArgument" in element.attrib["Type"]:
annotation = ""
annotationelements = [x for x in element.attrib if "annotationtext" in x.lower()]
if (len(annotationelements) > 0):
annotation = element.attrib[annotationelements[0]]
xaml_obt.in_arguments = xaml_obt.in_arguments.append({0:str(element.attrib["Name"]), 1:str(element.attrib["Type"]).replace("InArgument",""),2: annotation})
if "InOutArgument" in element.attrib["Type"]:
annotation = ""
annotationelements = [x for x in element.attrib if "annotationtext" in x.lower()]
if (len(annotationelements) > 0):
annotation = element.attrib[annotationelements[0]]
xaml_obt.io_agruments = xaml_obt.io_agruments.append({0:str(element.attrib["Name"]), 1:str(element.attrib["Type"]).replace("InOutArgument",""),2: annotation})
if "OutArgument" in element.attrib["Type"]:
annotation = ""
annotationelements = [x for x in element.attrib if "annotationtext" in x.lower()]
if (len(annotationelements) > 0):
annotation = element.attrib[annotationelements[0]]
xaml_obt.out_arguments = xaml_obt.out_arguments.append({0:str(element.attrib["Name"]), 1:str(element.attrib["Type"]).replace("OutArgument",""),2: annotation})
listofelements = treeroot.findall(".//{*}Variable")
for element in listofelements:
annotation = ""
annotationelements = [x for x in element.attrib if "annotationtext" in x.lower()]
if (len(annotationelements) > 0):
annotation = element.attrib[annotationelements[0]]
xaml_obt.variables = xaml_obt.variables.append({0:str(element.attrib["Name"]),1:annotation})
listxamls.append(xaml_obt)
else:
print("The following path does not exists, please amend your project structure: "+path)
return listxamls
def getworkflowinfo(openfile):
jsonpath = os.path.join(openfile,"project.json")
procestrans_path = os.path.join(openfile,"process","02_BusinessProcess")
dispatcher_path = os.path.join(openfile,"process","00_Dispatcher")
init_path = os.path.join(openfile,"process","01_Initialization")
process_path = os.path.join(openfile,"Process")
listxamls = []
listxamls = assignxamlobjects(listxamls, path=procestrans_path)
listxamls = assignxamlobjects(listxamls, path=dispatcher_path)
listxamls = assignxamlobjects(listxamls, path=init_path)
listxamls = assignxamlobjects(listxamls, path=process_path)
with open(jsonpath) as f:
uipathjson = json.load(f)
return uipathjson, listxamls
def insert_paragraph_after(paragraph, text, style):
new_p = OxmlElement('w:p')
paragraph._p.addnext(new_p)
new_para = Paragraph(new_p, paragraph._parent)
if text:
new_para.add_run(text)
if style is not None:
new_para.style = style
paragraph1 = new_para
return paragraph1
def fillxamldata(document, listofxamls):
print("Starting to update workflow information.")
for xaml_obt in listofxamls:
paraexists = False
for paragraph in document.paragraphs:
if paragraph.text == xaml_obt.xamlfilename:
paraexists = True
if paraexists is True:
for i, paragraph in enumerate(document.paragraphs):
# Check if the paragraph is a heading
if paragraph.style.name.startswith('Heading'):
if paragraph.text == xaml_obt.xamlfilename:
new_para = document.paragraphs[i + 1]
new_para.text = xaml_obt.ann_seq + "\n\n"
style = document.styles['No Spacing']
new_para.style = style
new_para.alignment = WD_ALIGN_PARAGRAPH.LEFT
else:
for paragraph in document.paragraphs:
# Check if the paragraph is a heading
if paragraph.style.name.startswith('Heading'):
if paragraph.text == xaml_obt.aut_block:
paragraph1 = insert_paragraph_after(paragraph, xaml_obt.xamlfilename, style=document.styles['Heading 3'])
paragraph_annseq = insert_paragraph_after(paragraph1, xaml_obt.ann_seq, style=document.styles['No Spacing'])
paragraph_var = insert_paragraph_after(paragraph_annseq, "Variables - " + xaml_obt.xamlfilename,style=document.styles['Heading 4'])
paragraph_in_arg = insert_paragraph_after(paragraph_var, "In_Agruments - " + xaml_obt.xamlfilename, style=document.styles['Heading 4'])
paragraph_io_arg = insert_paragraph_after(paragraph_in_arg, "In_Out_Agruments - " + xaml_obt.xamlfilename, style=document.styles['Heading 4'])
insert_paragraph_after(paragraph_io_arg, "Out_Agruments - " + xaml_obt.xamlfilename, style=document.styles['Heading 4'])
print("Workflow information updated successfully.\n")
return
def filldependencies(document, jsonUI):
print("Starting to fill dependencies.")
dict_depend = jsonUI['dependencies']
text = ""
for i in dict_depend:
text = text + i+": "+ dict_depend[i]+"\n"
for i, paragraph in enumerate(document.paragraphs): # Loop through all the paragraphs in the Word file
if paragraph.style.name.startswith('Heading'): # Check if the paragraph is a heading
if 'dependencies' == paragraph.text.lower():
new_para = document.paragraphs[i+1]
new_para.text = text
style = document.styles['No Spacing']
new_para.style = style
new_para.alignment = WD_ALIGN_PARAGRAPH.LEFT
print("Dependencies updated successfully.\n")
return
def fillgeneralinfo(document, jsonUI):
print("Starting to fill process info.")
text = ("Process name: "+"\t\t\t"+ jsonUI['name'] + "\n" +
"Process description:"+"\t\t" + jsonUI['description'] +"\n" +
"UIpath Studio version:"+"\t\t"+ jsonUI['studioVersion'] + "\n" +
"Project version:"+"\t\t\t" + jsonUI['projectVersion'] + "\n")
for i, paragraph in enumerate(document.paragraphs): # Loop through all the paragraphs in the Word file
if paragraph.style.name.startswith('Heading'): # Check if the paragraph is a heading
if 'general info' == paragraph.text.lower():
new_para = document.paragraphs[i+1]
new_para.text = text
style = document.styles['No Spacing']
new_para.style = style
new_para.alignment = WD_ALIGN_PARAGRAPH.LEFT
print("Process info successfully updated.\n")
return
def fillworddata(path, listofxamls):
print("You seleceted the following SDD file: "+path+"\n")
document = docx.Document(path)
with open(path, "w") as doc:
fillxamldata(document, listofxamls)
filldependencies(document, jsonUI)
fillgeneralinfo(document, jsonUI)
document.save(path)
return
def startmessage():
print("###############################################################\n"+
" SDD_AUT \n"+
"###############################################################\n")
starttimer = time.time()
startmessage()
openfile = selectfolder()
jsonUI, listxamls = getworkflowinfo(openfile)
correct_proc = input("The information for process | " + jsonUI['name'] + " | has been read.\n"+
"Do you want to continue? (y/n)\n")
if correct_proc.lower() == 'y':
sdd_doc = filedialog.askopenfilename(title='Select a file')
fillworddata(path=sdd_doc, listofxamls=listxamls)
print("Process has been executed successfully!")
else:
print("The process has been terminated as the incorrect project was selected.")
endtimer = time.time()
duration = endtimer - starttimer
print("Process took: " + str(duration))

Related

FPDF Python Package to Write PDF Files - Inserting extra line breaks. Does this for Multi_cell and cell. Want to remove extra line breaks

I have a python application that traverses directories on the file path passed in as a parameter. As each file is found, the file is opened and data is inserted into multi_cells.
I have checked the TXT values provided to multi_cell and there are no extra line breaks. I have played around with different setting to no avail. When inspecting the PDF output, extra line breaks are inserted. Any help would be appreciated. Look at the end of the script --- the final multicell.
import os,sys
from fpdf import FPDF
for i in range(1, len(sys.argv)):
print('argument:', i, 'value:', sys.argv[i])
mypath = sys.argv[i];
mypath = "D:\\test\\test\\CrossingTrades\\DataDictionary\\testLib\\forms"
class TOC(FPDF):
def __init__(this, orientation='P',unit='mm',format='A4'):
this._toc=[]
this._numbering=0
this._numberingFooter=0
this._numPageNum=1
FPDF.__init__(this,orientation,unit,format)
def header(self):
self.set_font('Courier', 'B', 15);
self.cell(0, 5, "Tradeflow Format and Rule Documentation", 0, 0, 'C')
self.ln(20)
def footer(self):
self.set_y(-10)
self.set_font('Arial', 'I', 8)
# Add a page number
page = 'Page ' + str(self.page_no()) + '/{nb}'
self.cell(0, 10, page, 0, 0, 'C')
def startPageNums(this):
this._numbering=1
this._numberingFooter=1
def stopPageNums(this):
this._numbering=0
def numPageNo(this):
return this._numPageNum
def TOC_Entry(this,txt,level,pageNumber):
this._numPageNum=pageNumber
this._toc+=[{'t':txt,'l':level,'p':this.numPageNo()}]
#print("PAGE NO IS ",this.numPageNo())
def insertTOC(this,location=1,labelSize=20,entrySize=10,tocfont='Times',label='Table of Contents'):
#make toc at end
this.stopPageNums()
#this.AddPage()
this.add_page();
this._numPageNum+=1
tocstart=this.page
this.set_font(tocfont,'B',labelSize)
this.cell(0,5,label,0,1,'C')
this.ln(10)
for t in this._toc:
#Offset
level=t['l']
if(level>0):
this.cell(level*8)
weight=''
if(level==0):
weight='B'
Str=t['t']
this.set_font(tocfont,weight,entrySize)
strsize=this.get_string_width(Str)
this.cell(strsize+2,this.font_size+2,Str)
#Filling dots
this.set_font(tocfont,'',entrySize)
PageCellSize=this.get_string_width(str(t['p']))+2
w=this.w-this.l_margin-this.r_margin-PageCellSize-(level*8)-(strsize+2)
#nb=w/this.get_string_width('.')
dots = "........................................................................................................"
#dots.replace('.', '.'*60, 1)
this.cell(w,this.font_size+2,dots,0,0,'R')
#Page number
this.cell(PageCellSize,this.font_size+2,str(t['p']),0,1,'R')
#grab it and move to selected location
n=this.page
n_toc = n - tocstart + 1
last = []
#store toc pages
for i in range(tocstart,n+1):
last+=[this.pages[i]]
#move pages
for i in range(tocstart-1,location-1,-1):
#~ for(i=tocstart - 1;i>=location-1;i--)
this.pages[i+n_toc]=this.pages[i]
#Put toc pages at insert point
for i in range(0,n_toc):
this.pages[location + i]=last[i]
#def Footer(this):
# if(this._numberingFooter==0):
# return
# #Go to 1.5 cm from bottom
# this.SetY(-15)
# #Select Arial italic 8
# this.SetFont('Arial','I',8)
# this.Cell(0,7,str(this.numPageNo()),0,0,'C');
# if(this._numbering==0):
# this._numberingFooter=0
class DPLFormat:
def __init__(self, name,arguments,contentsList,callerList,callingList):
self.name = name
self.arguments = arguments
self.contentsList = contentsList
self.callerList = callerList
self.callingList = callingList
class DPLRule:
def __init__(self, name,arguments,contentsList,callerList,callingList):
self.name = name
self.arguments = arguments
self.contentsList = contentsList
self.callerList = callerList
self.callingList = callingList
def get_filepaths(directory):
"""
This function will generate the file names in a directory
tree by walking the tree either top-down or bottom-up. For each
directory in the tree rooted at directory top (including top itself),
it yields a 3-tuple (dirpath, dirnames, filenames).
"""
file_paths = [] # List which will store all of the full filepaths.
#print ("Opening:", directory)
# Walk the tree.
for root, directories, files in os.walk(directory):
for filename in files:
if ".cfformat" in filename and ".cfformatprop" not in filename:
# Join the two strings in order to form the full filepath.
filepath = os.path.join(root, filename)
file_paths.append(filepath) # Add it to the list.
#file_paths.append(filename) # Add it to the list.
return file_paths # Self-explanatory.
# PDF Handling
# save FPDF() class into a
# variable pdf
pdf = TOC('P', 'mm', 'A4')
pdf.alias_nb_pages()
# Run the above function and store its results in a variable.
full_file_paths = get_filepaths(mypath)
formatList = []
tocList = []
print ("Beginning Processing ",mypath)
for index, item in enumerate(full_file_paths):
formatName = item.replace(".cfformat","")
#print(index,"",formatName)
formatArgs = ""
ruleFlag = 1
contentsList = []
callerList = []
callingList = []
#Find format in files
full_file_paths2 = get_filepaths(mypath)
cnt = 0
for index2, item2 in enumerate(full_file_paths2):
formatName2 = item2.replace(".cfformat","")
#if cnt == 0:
# print("Searching ",os.path.basename(formatName)," IN ",os.path.basename(formatName2))
with open(item2,'r') as fp2:
line2 = fp2.readline()
#print ("Opening ",os.path.basename(formatName2))
while line2:
line2 = fp2.readline()
if cnt == 0 :
if os.path.basename(formatName)in line2 and os.path.basename(formatName) != os.path.basename(formatName2) :
callerList.append(os.path.basename(formatName2))
cnt += 1
#---------------------END SEARCH FOR FORMAT IN OTHER FILES------------------
with open(item,'r') as fp:
line = fp.readline()
if "[" in line and "SQL" or ";" not in line:
formatArgs = line
ruleFlag = 0
cnt = 1
while line:
line = fp.readline()
#print("Line {}: {}".format(cnt, line.strip()))
#if "!" in line:
line = line.replace("–", "-")
#res = bytes(line,'UTF-8')
contentsList.append(line)
if "#" in line:
callingList.append(line)
cnt += 1
if formatArgs != "":
formatList.append( DPLFormat(os.path.basename(formatName),formatArgs,contentsList,callerList,callingList) )
#Now go through format files
pdf.set_font("Courier", size = 8)
formatList.sort(key=lambda x: x.name)
pdf.startPageNums()
for obj in formatList:
#print( obj.name, obj.arguments,sep =' ' )
# Add a page
pdf.add_page()
pdf.TOC_Entry(obj.name,1,pdf.page_no())
# caller list
pdf.set_font('Courier', 'B', size=13);
pdf.cell(200, 10, txt = obj.name ,
ln = 1, align = 'C')
ii = 0
pdf.set_font('Courier', 'I', size=10);
pdf.cell(200, 10, txt = "Called By: " ,
ln = 1, align = 'L')
callerStr=""
#print ("Caller list length is ", len(obj.callerList))
while ii != len (obj.callerList):
callerStr=callerStr+obj.callerList[ii]
ii += 1
pdf.multi_cell(0, 8, callerStr, 1, 'J')
#calling list
pdf.set_font('Courier', 'I', size=10);
ii = 0
pdf.cell(200, 10, txt = "Calling: " ,
ln = 1, align = 'L')
callingStr=""
#print ("Caller list length is ", len(obj.callerList))
while ii != len (obj.callingList):
callingStr=callingStr+obj.callingList[ii]
ii += 1
pdf.set_font('Courier',size=8);
pdf.multi_cell(0, 8, callingStr, 1, 'J')
#contents
pdf.set_font('Courier',size=8);
i = 0
codeStr = ""
while i != len (obj.contentsList):
codeStr=codeStr+obj.contentsList[i]
i += 1
pdf.multi_cell(0, 8, codeStr, 1, 'J')
# save the pdf with name .pdf
print ("\nWriting PDF Documentation")
pdf.insertTOC()
pdf.output("D:\\DPLAutoDoc.pdf")
print ("\nFinished")
The width in multi cell call, the first parameter is cell size or width. In portrait set that to something like 190. The second value actually controls spacing between lines so set to a value like 1 or 2. Set justification to left.

Python flask web API XML findall no attribute

import requests
try:
import xml.etree.cElementTree as et
except ImportError:
import xml.etree.ElementTree as et
user_key = "CWB-22E1B400-6B6B-4E9E-8BBF-9D78666CF958"
doc_name = "F-C0032-001"
url = "https://opendata.cwb.gov.tw/api/v1/rest/datastore/%s?Authorization=%s&format=xml" % (doc_name,user_key)
report = requests.get(url).text
#print(report)
xml_namespace = "{urn:cwb:gov:tw:cwbcommon:0.1}"
root = et.fromstring(report)
dataset = root.find(xml_namespace + 'dataset')
locations_info = dataset.findall(xml_namespace + 'location')
location = '高雄市'
target_idx = -1
for idx,ele in enumerate(locations_info):
locationName = ele[0].text
if locationName == location:
target_idx = idx
break
if target_idx != -1:
show = ''
tlist = ['天氣狀況', '最高溫', '最低溫', '舒適度', '降雨機率']
for i in range(5):
element = locations_info[target_idx][i+1]
timeblock = element[1]
data = timeblock[2][0].text
show = show + tlist[i] + ':' + data + '\n'
print(show)
else:
print('無此縣市資料')
in the Console it show
File "D:\flask\weatherdata.py", line 16, in
locations_info = dataset.findall(xml_namespace + 'location')
AttributeError: 'NoneType' object has no attribute 'findall'

I can not iterate over Python-docx document in word file

LOOK AT THE PICTUREI have the following code that reads a word docx document and write a line on the top of the table in it. It iterates over the tables inside the document. This is the old version of the code. I want to iterate over all the elements (supposely paragraphs and tables together) and insert two pointer (one for paragraphs and one for tables) and iterate with pointers. I want to write something before the previous paragraph where the data came from every table. If we have 3 tables, I want to write a sentence for every table before the last seen paragraph while we traverse the all the word file.
import docx
import section as section
from docx import Document
from docx.section import _Header
from docx.text.paragraph import Paragraph
from docx.oxml.text.paragraph import CT_P
from docx.enum.style import WD_STYLE_TYPE
import re
# Insert a empty line before the tables in the document.
def insert_paragraph_before(item, text, style=None):
"""
Return a newly created paragraph, inserted directly before this
item (Table, etc.).
"""
# CT_P.add_p_before(item._element)
p = CT_P.add_p_before(item._element)
# CT_P.add_p_before(item._element)
p2 = Paragraph(p, item._parent)
p2.text = text
p2.style = styles["REQ"]
return p2
FileName = 'Test'
document = docx.Document(FileName + ".docx")
styles = document.styles
style = styles.add_style('REQ', WD_STYLE_TYPE.PARAGRAPH)
# for table in document.tables:
# # insert_paragraph_before(table, "" )
for table in document.tables:
req_name = ""
req_id = ""
req_id_found = False
counter = 0
for row in table.rows:
for cell in row.cells:
for paragraph in cell.paragraphs:
syntax = re.compile(r'(UNIT_S-REQ|UNIT_S-DC|UNIT_S-DD|Information|MRS-REQ|MRS-DC|MRS-DD)')
result = syntax.findall(paragraph.text)
if result and req_id_found == False:
req_id = table.cell(0, 1).text
# req_id = str(result[0])
req_id_found = True
txt = table.cell(2, 1).text
# print(txt)
if txt not in ["<name>"]:
req_name = table.cell(2, 1).text
for paragraph in document.paragraphs:
if req_id_found == True:
if counter != 0:
continue
if counter == 0:
if req_id and req_name:
document.add_heading(table, "ID-" + req_id + " - " + req_name)
print(table, "ID-" + req_id + " - " + req_name)
print(paragraph.text)
elif req_id and not req_name:
document.add_heading(table, "ID-" + req_id)
print(table, "ID-" + req_id)
print(paragraph.text)
counter += 1
if counter == 0:
continue
if counter != 0:
if req_id and req_name:
document.add_paragraph(table, "ID-" + req_id + " - " + req_name)
print(table, "ID-" + req_id + " - " + req_name)
print(paragraph.text)
elif req_id and not req_name:
document.add_paragraph(table, "ID-" + req_id)
print(table, "ID-" + req_id)
print(paragraph.text)
counter += 1
document.save(FileName + "_modified.docx")

python-docx how to merge row cells

I am creating a Word document from data using python-docx. I can create all the rows and cells with no problem but, in some cases, when the current record from the database has some content in field comment, I need to add a new line to display a long content.
I tried by appending a paragraph, but the result is that the comment is appended after the table, and I need it to be added bellow the current table row.
I think the solution is to append a table row with all cells merged, but I can't find documentation to do so.
This is the code where I generate the docx file:
class OperationDOCXView(viewsets.ViewSet):
exclude_from_schema = True
def list(self, request):
from ReportsManagerApp.controllers import Operations2Controller
self.profile_id = request.query_params['profile_id']
self.operation_date = request.query_params['operation_date']
self.operation_type = request.query_params['operation_type']
self.format = request.query_params['doc_format']
operation_report_controller = Operations2Controller(self.profile_id, self.operation_date, self.operation_type)
context = operation_report_controller.get_context()
if self.format == 'json':
return Response(context)
else:
word_doc = self.get_operation_word_file(request, context)
return Response("{}{}{}".format(request.get_host(), settings.MEDIA_URL, word_doc))
def get_operation_word_file(self, request, context):
import unicodedata
from django.core.files import File
from django.urls import reverse
from docx import Document
from docx.shared import Inches, Pt
operation_type = {
'arrival': 'Llegadas',
'departure': 'Salidas',
'hotel': 'Hotel-Hotel',
'tour': 'Tours',
}
weekdays = {
'0': 'LUNES',
'1': 'MARTES',
'2': 'MIÉRCOLES',
'3': 'JUEVES',
'4': 'VIERNES',
'5': 'SÁBADO',
'6': 'DOMINGO',
}
titles = ['Booking', 'Nombre', '#', 'Vuelo', 'Hr', 'P Up', 'Traslado', 'Circuito', 'Priv?', 'Agencia', '']
widths = [Inches(1), Inches(2), Inches(0.5), Inches(1), Inches(1), Inches(1), Inches(2), Inches(3), Inches(0.5), Inches(3), Inches(0.5)]
document = Document()
section = document.sections[-1]
section.top_margin = Inches(0.5)
section.bottom_margin = Inches(0.5)
section.left_margin = Inches(0.3)
section.right_margin = Inches(0.2)
style = document.styles['Normal']
font = style.font
font.name ='Arial'
font.size = Pt(10)
company_paragraph = document.add_heading("XXXX TTOO INC")
company_paragraph.alignment = WD_ALIGN_PARAGRAPH.CENTER
description_paragraph = document.add_paragraph("Operación de {} del día {}".format(operation_type[self.operation_type], self.operation_date))
description_paragraph.alignment = WD_ALIGN_PARAGRAPH.CENTER
operation_date = self.get_operation_date().date()
operation_week_day = operation_date.weekday()
day_paragraph = document.add_paragraph(weekdays[str(operation_week_day)])
day_paragraph.alignment = WD_ALIGN_PARAGRAPH.CENTER
for provider_unit, transfers in context.items():
provider_unit_paragraph = document.add_paragraph(provider_unit)
provider_unit_paragraph.style.font.size = Pt(10)
provider_unit_paragraph.style.font.bold = False
table = document.add_table(rows=1, cols=11)
hdr_cells = table.rows[0].cells
runs = []
for i in range(len(hdr_cells)):
runs.append(self.get_hdr_cells_run(hdr_cells[i], titles[i]))
for row in table.rows:
for idx, width in enumerate(widths):
row.cells[idx].width = width
adults = 0
minors = 0
for transfer in transfers:
# table = document.add_table(rows=1, cols=11)
row_cells = table.add_row().cells
row_cells[0].text = transfer['booking']
row_cells[1].text = transfer['people']
row_cells[2].text = transfer['pax']
flight = transfer.get("flight","") if transfer.get("flight","") is not None else ""
row_cells[3].text = flight
flight_time = self.get_flight_time(flight) if flight != '' else ''
row_cells[4].text = flight_time
row_cells[5].text = transfer['pickup_time'].strftime('%H:%M') if transfer['pickup_time'] is not None else ''
row_cells[6].text = transfer['place']
row_cells[7].text = transfer['roundtrip']
row_cells[8].text = transfer['is_private']
row_cells[9].text = transfer['agency']
people = transfer['pax'].split('.')
adults = adults + int(people[0])
minors = minors + int(people[1])
if transfer['comment'] is not None:
document.add_paragraph("Comentarios: {}".format(transfer['comment']))
for row in table.rows:
for idx, width in enumerate(widths):
row.cells[idx].width = width
for cell in row.cells:
paragraphs = cell.paragraphs
for paragraph in paragraphs:
for run in paragraph.runs:
font = run.font
font.size = Pt(8)
row_cells = table.add_row().cells
row_cells[10].text = "{}.{}".format(adults, minors)
current_directory = settings.MEDIA_DIR
file_name = "Operaciones {} {}.docx".format(self.operation_type, self.operation_date)
document.save("{}{}".format(current_directory, file_name))
return file_name
def get_flight_time(self, flight):
from OperationsManagerApp.models import Flight
operation_types = {
'arrival': 'ARRIVAL',
'departure': 'DEPARTURE'
}
operation_date = datetime.strptime(self.operation_date, '%Y-%m-%d')
try:
flight = Flight.objects.get(flight_type=operation_types[self.operation_type], number=flight)
except:
return ''
else:
weekday_times = {
'0': flight.time_monday,
'1': flight.time_tuesday,
'2': flight.time_wednesday,
'3': flight.time_thursday,
'4': flight.time_friday,
'5': flight.time_saturday,
'6': flight.time_sunday,
}
weekday_time = weekday_times[str(operation_date.weekday())]
return weekday_time.strftime('%H:%M') if weekday_time is not None else ''
def get_hdr_cells_run(self, hdr_cells, title):
from docx.shared import Pt
new_run = hdr_cells.paragraphs[0].add_run(title)
new_run.bold = True
new_run.font.size = Pt(8)
return new_run
def get_operation_date(self):
date_array = self.operation_date.split('-')
day = int(date_array[2])
month = int(date_array[1])
year = int(date_array[0])
operation_date = datetime(year, month, day)
return operation_date
One approach is to add a paragraph to one of the cells:
cell.add_paragraph(transfer['comment'])
This will place it in the right position with respect to the row it belongs to, rather than after the table.
If that would take too much room for a single cell that already has another data item in it and you want to add a row, you'll need to account for that when you allocate the table. But assuming you get that worked out, merging the cells is easy:
row.cells[0].merge(row.cells[-1])

Python find function selects one match per line

I am trying to make a simple text editor using python. I am now trying to make a find function. This is what I've got:
def Find():
text = textArea.get('1.0', END+'-1c').lower()
input = simpledialog.askstring("Find", "Enter text to find...").lower()
startindex = []
endindex = []
lines = 0
if input in text:
text = textArea.get('1.0', END+'-1c').lower().splitlines()
for var in text:
character = text[lines].index(input)
start = str(lines + 1) + '.' + str(character)
startindex.append(start)
end = str(lines + 1) + '.' + str(character + int(len(input)))
endindex.append(end)
textArea.tag_add('select', startindex[lines], endindex[lines])
lines += 1
textArea.tag_config('select', background = 'green')
This will succesfully highlight words that match the users input with a green background. But the problem is, that it only highlights the first match every line, as you can see here.
I want it to highlight all matches.
Full code here: https://pastebin.com/BkuXN5pk
Recommend using the text widget's built-in search capability. Shown using python3.
from tkinter import *
root = Tk()
textArea = Text(root)
textArea.grid()
textArea.tag_config('select', background = 'green')
f = open('mouse.py', 'r')
content = f.read()
f.close()
textArea.insert(END, content)
def Find(input):
start = 1.0
length = len(input)
while 1:
pos = textArea.search(input, start, END)
if not pos:
break
end_tag = pos + '+' + str(length) + 'c'
textArea.tag_add('select', pos, end_tag)
start = pos + '+1c'
Find('display')
root.mainloop()

Categories

Resources