Python Key Error filtering MySQL - python

So I have a little program which makes a DB call and then converts it into a PDF.
I have most of them working but this last one is returning a Key Error on me and I cannot figure out why.
Here is an example of the data being returned by the DB:
((None, 0, 0, 0, 0, 0, 0, 0), (0, 0, 0, 0, 0, 26, 0, 26), (1, 1, 0, 0, 0, 17, 0, 18), (2, 0, 0, 0, 0, 15, 0, 16))
The Traceback:
Traceback (most recent call last):
File "C:\Users\Ace\AppData\Local\Programs\Python\Python36\lib\tkinter\__init__.py", line 1699, in __call__
return self.func(*args)
File "C:/Users/Ace/Desktop/IPNV/KP_App/FML/firstapp.py", line 232, in hrday_in
hourday_filter(noodle, dest, drange)
File "C:\Users\Ace\Desktop\IPNV\KP_App\FML\dataIN.py", line 187, in hourday_filter
doc.export(pths, drange)
File "C:\Users\Ace\Desktop\IPNV\KP_App\FML\calazan.py", line 58, in export
reverse=reverse_order)
KeyError: 'h'
Im not even sure where the 'h' comes from.
Here is the function that I run the data through to prepare for the pdf generation:
def hourday_filter(tuna, pth, drange):
data = []
for hr, number, local, chicken, alligator, ace, lola, chunk in tuna:
data.append({'hour': hr,
'number': number,
'local': local,
'long': chicken,
'inter': alligator,
'income': ace,
'tandem': lola,
'total': chunk})
fields = (
('hour', 'Hour of Day'),
('number', 'Internal Calls '),
('local', 'Local Calls'),
('long', 'Long Distance Calls'),
('inter', 'International Calls '),
('income', 'Incoming Calls'),
('tandem', 'Tandem Calls'),
('total', 'Total Calls'),
)
pths = pth + '/HourofDay.pdf'
doc = DataToPdf(fields, data, sort_by='hr',
title='Hour of Day Report')
doc.export(pths, drange)
And From there the data is passed to this function to actually convert it too pdf.
class DataToPdf:
"""
Export a list of dictionaries to a table in a PDF file.
"""
def __init__(self, fields, data, sort_by=None, title=None):
"""
Arguments:
fields - A tuple of tuples ((fieldname/key, display_name))
specifying the fieldname/key and corresponding display
name for the table header.
data - The data to insert to the table formatted as a list of
dictionaries.
sort_by - A tuple (sort_key, sort_order) specifying which field
to sort by and the sort order ('ASC', 'DESC').
title - The title to display at the beginning of the document.
"""
self.fields = fields
self.data = data
self.title = title
self.sort_by = sort_by
def export(self, filename, drange, data_align='LEFT', table_halign='LEFT'):
doc = SimpleDocTemplate(filename, pagesize=letter)
styles = getSampleStyleSheet()
styleH = styles['Heading1']
styleD = styles['Heading4']
date = time.strftime("%m/%d/%Y")
date2 = 'Ran on: ' + date
date3 = ' For the period ' + str(drange[0]) + ' to ' + str(drange[1]) # Edit here to display report date range
story = []
if self.title:
story.append(Paragraph(self.title, styleH))
story.append(Spacer(1, 0.25 * inch))
story.append(Paragraph(date2, styleD))
story.append(Spacer(1, 0.015 * inch))
story.append(Paragraph(date3, styleD))
if self.sort_by:
reverse_order = False
if str(self.sort_by[1]).upper() == 'DESC':
reverse_order = False
self.data = sorted(self.data,
key=itemgetter(self.sort_by[0]),
reverse=reverse_order)
converted_data = self.__convert_data()
table = Table(converted_data, hAlign=table_halign)
table.setStyle(TableStyle([
('FONT', (0, 0), (-1, 0), 'Helvetica-Bold'),
('ALIGN', (0, 0), (-1, 0), 'CENTER'),
('ALIGN', (0, 0), (0, -1), data_align),
('INNERGRID', (0, 0), (-1, -1), 0.50, colors.black),
('BOX', (0, 0), (-1, -1), 0.25, colors.black),
]))
data_len = len(converted_data)
for each in range(data_len):
if each % 2 == 0:
bg_color = colors.whitesmoke
else:
bg_color = colors.lightgrey
table.setStyle(TableStyle([('BACKGROUND', (0, each), (-1, each), bg_color)]))
story.append(table)
doc.build(story)
def __convert_data(self):
"""
Convert the list of dictionaries to a list of list to create
the PDF table.
"""
# Create 2 separate lists in the same order: one for the
# list of keys and the other for the names to display in the
# table header.
keys, names = zip(*[[k, n] for k, n in self.fields])
new_data = [names]
for d in self.data:
new_data.append([d[k] for k in keys])
return new_data
Is it possible that first result of the db (the null one) is causing this? I've made about a dozen of these reports now with no problems, not sure where I am messing up here.

So thanks to FamousJameous I realized that it was indeed the first field killing my filter. The sort_by call did not know how to deal with the NULL value. I managed to fix it by removing that first field from the tuple.
The database returned the results into the variable result
From there:
new_result = result[1:]
This line removed the NULL line and stopped the error

Related

Python Reportlab - Wordwrap on Table is splitting words rather than at spaces

I created a PDF in reportlab using a canvas:
self.pdf = canvas.Canvas(f'{file_name}.pdf', pagesize=A4)
I create tables within tables to create my document but one of my tables is not wrapping the way I expect it to. Rather than linebreaking at spaces, it does so between words as seen below.
The code below is the code I used to create the table. It is a bit long as I did make sure that the cells I'm passing into the Table() are all Paragraph().
def _discount_table(self, width_list):
# Table Name
table_name = Paragraph('DISCOUNTS', self.header_style_grey)
# Create Header
header = [Paragraph('NAME', self.table_header_style_left)]
header += [Paragraph(x, self.table_header_style_right) for x in self.unique_discount_list]
header += [Paragraph('TOTAL', self.table_header_style_right)]
# Process Data
discount_data = [[Paragraph(cell, self.table_style2) for cell in row] for row in self.discount_data]
data = [[child_row[0]] + disc for child_row, disc in zip(self.fees_data, discount_data)]
# Create Footer
table_footer = [Paragraph('') for _ in range(len(header) - 2)]
table_footer += [Paragraph('TOTAL', self.table_header_style_right),
Paragraph(f'{self.discount_total:,.2f}', self.table_header_style_right)]
# Create Table
bg_color = self.header_style_grey.textColor
table = Table([header] + data + [table_footer], colWidths=width_list)
table.setStyle([
('GRID', (0, 0), (-1, -1), 1, 'black'),
('BACKGROUND', (0, 0), (-1, 0), bg_color),
('TEXTCOLOR', (0, 0), (-1, 0), 'white'),
('BACKGROUND', (-2, -1), (-1, -1), bg_color),
('TEXTCOLOR', (-2, -1), (-1, -1), 'white'),
('FONTNAME', (-2, -1), (-1, -1), 'Helvetica-Bold'),
('FONTNAME', (0, 0), (-1, 0), 'Helvetica-Bold'),
('ALIGN', (1, 0), (-1, -1), 'RIGHT'),
('ROWBACKGROUNDS', (0, 1), (-1, -2), ['lightgrey', 'white']),
])
return [table_name, table]
(To note that child_row[0] is already a Paragraph - this is found on the line 12 above)
The styling I used is imported from another python file as follows:
self.table_style2 = ParagraphStyle('table_style')
self.table_style2.wordWrap = 'CJK'
self.table_style2.alignment = TA_RIGHT
self.table_style = ParagraphStyle('table_style')
self.table_style.wordWrap = 'CJK'
self.table_header_style_right = ParagraphStyle('table_header_style', self.table_style)
self.table_header_style_right.textColor = colors.HexColor('#FFFFFF')
self.table_header_style_right.fontName = 'Helvetica-Bold'
self.table_header_style_right.alignment = TA_RIGHT
self.table_header_style_right.wordWrap = 'CJK'
self.table_header_style_left = ParagraphStyle('table_header_style', self.table_style)
self.table_header_style_left.textColor = colors.HexColor('#FFFFFF')
self.table_header_style_left.fontName = 'Helvetica-Bold'
self.table_header_style_left.wordWrap = 'CJK'
So I am really lost and need help. Why is the table not wrapping correctly?
I was able to fix the table wrap issue when I removed the wordWrap = 'CJK' portion of the code. I saw in a video that a Paragraph() will automatically wordWrap so I'm guessing there was some issue with how those two elements overlap
self.table_style2 = ParagraphStyle('table_style')
# self.table_style2.wordWrap = 'CJK'
self.table_style2.alignment = TA_RIGHT
self.table_style = ParagraphStyle('table_style')
# self.table_style.wordWrap = 'CJK'
self.table_header_style_right = ParagraphStyle('table_header_style', self.table_style)
self.table_header_style_right.textColor = colors.HexColor('#FFFFFF')
self.table_header_style_right.fontName = 'Helvetica-Bold'
self.table_header_style_right.alignment = TA_RIGHT
# self.table_header_style_right.wordWrap = 'CJK'
self.table_header_style_left = ParagraphStyle('table_header_style', self.table_style)
self.table_header_style_left.textColor = colors.HexColor('#FFFFFF')
self.table_header_style_left.fontName = 'Helvetica-Bold'
# self.table_header_style_left.wordWrap = 'CJK'

Trouble in manipulating the data for treeview in tkinter

everyone. Let me first paste the code.
c.execute("SELECT * FROM c20 WHERE Position = 'chain';")
data1 = c.fetchall()
c.execute("SELECT * FROM c20 WHERE Position = 'center';")
data2 = c.fetchall()
c.execute("SELECT * FROM c20 WHERE Position = 'Total';")
data3 = c.fetchall()
data1 = p_mod.list_multiply(data, copies_data)
data2 = p_mod.list_multiply(data2, copies_data)
data3 = p_mod.list_multiply(data3, copies_data)
meta_data = [data1, data2, data3]
n = 0
while n != 3:
for i in meta_data:
my_tree.insert(parent="", index="end", iid=n, text=f"{n + 1}", values=i)
n += 1
if n == 3:
my_tree.pack(pady=20)
root1.mainloop()
This is the code where I need to fetch queries regarding a requirement and the output required is as follows:
conn = sqlite3.connect("userdata.db")
>>> c = conn.cursor()
>>> c.execute("SELECT * FROM c20 WHERE Position = 'chain';")
<sqlite3.Cursor object at 0x00000221DA432F80>
>>> data1 = c.fetchall()
>>> data1
[('chain', 100, 350, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)]
I have also used a remote function named p_mod.list_multiply().
The function looks like this:
def list_multiply(list_input, number):
new_list = []
list_input = list(list_input)[0]
list_input1 = list_input[1 : -1]
for i in list_input1:
data = int(i) * number
new_list.append(data)
if list_input[0] == 'chain':
new_list.insert(0, 'chain')
elif list_input[0] == 'center':
new_list.insert(0, 'center')
elif list_input[0] == 'Total':
new_list.insert(0, 'Total')
new_list = tuple(new_list)
return new_list
Now the problem arises...
Whenever I try to run the code with same outputs(data1, data2,...) using the function remotely from the main code,
it runs successfully, but whenever I am trying to run the script inside the main program it gives me an error.
Error is as follows:
PS D:\RM INCORPORATION\RM Software DEV Company Pvt\Jewellery App> & C:/Users/ONE/AppData/Local/Programs/Python/Python39/python.exe "d:/RM INCORPORATION/RM Software DEV Company Pvt/Jewellery App/contact.py"
h
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Users\ONE\AppData\Local\Programs\Python\Python39\lib\tkinter\__init__.py", line 1884, in __call__
return self.func(*args)
File "d:\RM INCORPORATION\RM Software DEV Company Pvt\Jewellery App\contact.py", line 53, in select
data1 = p_mod.list_multiply(data, copies_data)
File "d:\RM INCORPORATION\RM Software DEV Company Pvt\Jewellery App\p_mod.py", line 15, in list_multiply
data = int(i) * number
ValueError: invalid literal for int() with base 10: 'h'
Let me show you the output used with the function remotely, from the main code...
PS D:\RM INCORPORATION\RM Software DEV Company Pvt\Jewellery App> & C:/Users/ONE/AppData/Local/Programs/Python/Python39/python.exe "d:/RM INCORPORATION/RM Software DEV Company Pvt/Jewellery App/p_mod.py"
('chain', 200, 700, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) ('center', 222, 826, 82, 124, 98, 70, 756, 2, 2, 6, 8, 24, 24, 16, 0, 0) ('Total', 422, 1526, 82, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1878, 70)
Then what is the problem dude?
Eagerly waiting someone's reply
You have overwritten list_input by the following line in list_multiply():
list_input = list(list_input)[0]
Therefore, list_input will be a string after that.
Just remove this line will solve the issue.
Also the following line:
list_input1 = list_input[1 : -1]
will not copy the last item of list_input into list_input1.
It should be
list_input1 = list_input[1:]
list_multiply() can be simplified as below:
def list_multiply(list_input, number):
new_list = tuple(int(x)*number for x in list_input[1:])
return (list_input[0],) + new_list

Appending new items to a Python list with logic operators (Time values)

I'm starting out on Python on a job (I'm used to R) where I have to get daily data from an API that returns the datetime and value (which is a certain number of listeners on a podcast) and then send that data to a bigquery database.
After I split up the date and time, I need to add a new column that indicates which program was playing in that moment. In other words:
if time is >= than 11:00 and <= 11:59 then add a 'program name' value to the row into the column 'program'.
I've ran into several problems, namely the fact that time has been split as strings (could be due to the fact that we use google data studio, which has extremely rigid datetime implementation).
How would you go about it?
if response.status_code == 200:
data = response.text
result = json.loads(data)
test = result
#Append Items
for k in test:
l = []
l.append(datetime.datetime.strptime(k["time"], "%Y-%m-%dT%H:%M:%S.%fZ").strftime("%Y-%m-%d"))
l.append(datetime.datetime.strptime(k["time"], "%Y-%m-%dT%H:%M:%S.%fZ").astimezone(pytz.timezone("America/Toronto")).strftime("%H:%M"))
l.append(k["value"])
You need to have a 'DB' of the programs timetable. See below.
Your loop will call the function below with the time value and you will have the program name.
import datetime
from collections import namedtuple
Program = namedtuple('Program', 'name start end')
PROGRAMS_DB = [Program('prog1', datetime.time(3, 0, 0), datetime.time(3, 59, 0)),
Program('prog2', datetime.time(18, 0, 0), datetime.time(18, 59, 0)),
Program('prog3', datetime.time(4, 0, 0), datetime.time(4, 59, 0))]
def get_program_name(time_val):
for program in PROGRAMS_DB:
if program.start <= time_val <= program.end:
return program.name
data_from_the_web = [{"time": "2019-02-19T18:10:00.000Z", "value": 413, "details": None},
{"time": "2019-02-19T15:12:00.000Z", "value": 213, "details": None}]
for entry in data_from_the_web:
t = datetime.datetime.strptime(entry["time"], "%Y-%m-%dT%H:%M:%S.%fZ").time()
entry['prog'] = get_program_name(t)
for entry in data_from_the_web:
print(entry)
Output
{'prog': 'prog2', 'details': None, 'value': 413, 'time': '2019-02-19T18:10:00.000Z'}
{'prog': None, 'details': None, 'value': 213, 'time': '2019-02-19T15:12:00.000Z'}

C structure to Python class or dict?

I heard and read that, defining large number of information is easy using class structure, which is defined in C language (see C Code below).
I want to defined similar way using Python. I need little favor on code, and I am in new learner group of Python.
Any suggestion about which way make it easy to define? Going dict is fine, but class is best.
Example in C code below (and I have additional similar structures and information):
typedef struct
{
U16 ID;
S8 Name[32];
S8 Description[96];
S8 Units[16];
enum eType Type;
F32 Scaling;
F32 Offset;
BOOL Writeable;
} sDataInfo;
/* ID, Name, Description, Unit, Type, Scaling, Offset, Writable */
sDataInfo data_items[] =
{
0x0202, "dtc_num_of_faults_", "Number of DTCs", "", u8, 1, 0, FALSE,
0x2007, "FlBodyVertLocSel_A_Meas_", "FL Vertical Acceleration", "m/s^2", s16, 0.05, 0, FALSE,
0x2008, "FrBodyVertLocSel_A_Meas_", "FR Vertical Acceleration", "m/s^2", s16, 0.05, 0, FALSE,
0x2022, "RlBodyVertLocSel_A_Meas_", "RL Vertical Acceleration", "m/s^2", s16, 0.05, 0, FALSE
}
It is important to know every one the above code can be changed in Python. None of question answered for above in any online chain.
And expecting some examples as well.
As I said in a comment, I'm not sure exactly what you want...but here's one guess:
from pprint import pprint
import sys
def sprintf(format, *args):
return format % args
def _attributes_from_dict(d):
self = d.pop('self')
for n, v in d.items():
setattr(self, n, v)
class DataInfo(object):
fieldnames = 'id, name, description, units, type, scaling, offset, writeable'.split(', ')
def __init__(self, id, name, description, units, type, scaling, offset, writeable):
_attributes_from_dict(locals())
def __repr__(self): # optional
values = tuple(getattr(self, fieldname) for fieldname in self.fieldnames)
id = values[0]
remainder = ', '.join(map(repr, values[1:]))
return sprintf('%s(0x%04x, %s)', self.__class__.__name__, id, remainder)
u8, s16 = 0, 1 # enum eType names and values
data_items = [
DataInfo(*args) for args in [
(0x0202, "dtc_num_of_faults_", "Number of DTCs", "", u8, 1, 0, False),
(0x2007, "FlBodyVertLocSel_A_Meas_", "FL Vertical Acceleration", "m/s^2", s16, 0.05, 0, False),
(0x2008, "FrBodyVertLocSel_A_Meas_", "FR Vertical Acceleration", "m/s^2", s16, 0.05, 0, False),
(0x2022, "RlBodyVertLocSel_A_Meas_", "RL Vertical Acceleration", "m/s^2", s16, 0.05, 0, False),
]
]
pprint(data_items)
Output:
[DataInfo(0x0202, 'dtc_num_of_faults_', 'Number of DTCs', '', 0, 1, 0, False),
DataInfo(0x2007, 'FlBodyVertLocSel_A_Meas_', 'FL Vertical Acceleration', 'm/s^2', 1, 0.05, 0, False),
DataInfo(0x2008, 'FrBodyVertLocSel_A_Meas_', 'FR Vertical Acceleration', 'm/s^2', 1, 0.05, 0, False),
DataInfo(0x2022, 'RlBodyVertLocSel_A_Meas_', 'RL Vertical Acceleration', 'm/s^2', 1, 0.05, 0, False)]

Unable to write image in PDF File

def logo_para(self):
exp = Paragraph(
'<b>Express</b>', self.styles['CenterHeading'])
csheet = Paragraph(
'<b>PDF SHEET</b>', self.styles['CenterHeading'])
img_location = "https://www.google.co.in/logos/doodles/2016/icc-australia-v-bangladesh-5759441086447616-res.png"
img_data = '''
<para><img src="%s" width="300" height="90"/><br/>
</para>''' % img_location
img = Paragraph(img_data, self.styles['CenterHeading'])
data = [[exp], [csheet], [''], [img] ]
main_header_table = Table([['', img, '']], colWidths=(100, 300, 100))
main_header_table.setStyle(TableStyle([
('ALIGN', (0, 0), (-1, -1), 'CENTER'),
('BOX', (0, 0), (-1, -1), 0.25, colors.black)
]))
self.elements.append(main_header_table)
When ever I am calling
docket.logo_para()
I am getting error cannot concatenate 'str' and 'int' objects
at self.doc.build(self.elements)
When the line is commenteddocket.logo_para(), the code works superbly.
I am trying to add an image on the PDF File using SimpleDocTemplate
EDIT 1
creating new pdf
class PDFDocketGenerator(object):
def __init__(self, file_name):
self.filename = file_name
self.filepath = STATIC_URL + 'uploads/billing/' + file_name
self.path_to_save = FILE_UPLOAD_TEMP_DIR + '/billing/' + file_name
# define the pdf object
self.doc = SimpleDocTemplate(
self.path_to_save, pagesize=landscape(A4), topMargin=50, bottomMargin=30,
leftMargin=60, rightMargin=60)
self.elements = []
writing to pdf
def write_pdf(self):
self.doc.build(self.elements)
Is it possible that some values in self.elements are integers? I would suggest to try this in this case :
def write_pdf(self):
self.doc.build([str(e) for e in self.elements])

Categories