elapouya / python-docx-template

Use a docx as a jinja2 template
GNU Lesser General Public License v2.1
1.91k stars 378 forks source link

AttributeError: 'NoneType' object has no attribute 'tables' #498

Closed kunci115 closed 11 months ago

kunci115 commented 1 year ago

Describe the bug

bug to load a table in python3.11 for the latest docxtpl

To Reproduce

doc = DocxTemplate(template_path)
doc.tables

Expected behavior

<docx.table.Table object at 0x0000027A3FABD190>

leafarilongamor commented 11 months ago

I was banging my head against the keyboard for two days on it, not knowing what was wrong (I'm noob). Thanks for reporting. Hopefully it will get fixed it soon. I wonder if older versions are free from this bug, I think I'm gonna give it a try.

elapouya commented 11 months ago

you are in the wrong project

leafarilongamor commented 11 months ago

Oh, so this issue is related only to docxtpl? I guess I'll report it there then. Sorry for the noobness.

elapouya commented 11 months ago

I think you are speaking about python-docx project

elapouya commented 11 months ago

...or may be more verbose about what you want to do it is not easy to guess...

leafarilongamor commented 11 months ago

I am trying to build and run a docxtpl script to fill a docx template with data from other sources like csv and images on a local folder. I am consistently bumping into an "AttributeError: 'NoneType' object has no attribute" error despite loading the docx correctly. I was searching for answers when I found this bug report. I am also using the latest version of both the package (docxtpl 0.16.7) and python (3.11).

elapouya commented 11 months ago

your initial problem is that you was trying to get an attribute that does not exist into docxtpl suggesting to me you was not in the right project

if you want to generate a table with docxtpl, have a look at tests/order.py

elapouya commented 11 months ago

… and do not use «doc.tables » in your script it is not in the manual.

elapouya commented 11 months ago

Now for the expected behavior, but I really don’t know why you want to access tables attribute you can try doc.docx.tables

leafarilongamor commented 11 months ago

Sorry for the late reply.

I ended up starting my script from scratch and I'm not seeing the same issue now.

The problematic script was this one (already "anonymized"):

from docxtpl import DocxTemplate import csv import os import datetime import sys

--# Load the template doc = DocxTemplate('/path/to/TEMPLATE_TEST.docx')

--# Load the simple text values from the CSV file simple_text_values = {} with open('simple_text_values.csv', 'r') as f: reader = csv.DictReader(f, delimiter=';') for row in reader: print(row) simple_text_values[row['Generic Text Content Control']] = row['Value']

--# Load the service orders from the CSV file service_orders = [] with open('Service_Orders.csv', 'r') as f: reader = csv.DictReader(f) for row in reader: service_orders.append({ 'Service_Order_Number': row['Service_Order_Number'], 'Contact_Name': row['Contact_Name'], 'Subject': row['Subject'], 'Delivery_Date': row['Delivery_Date'] })

--# Render the document with the context context = { 'simple_text_values': simple_text_values, 'service_orders': service_orders, } print(context)

doc.render(context)

--# Redirect the get_xml() output to a log file now = datetime.datetime.now() datestr = now.strftime("%Y-%m-%d%H-%M-%S") log_filename = f"get_xml-log-{date_str}.txt" with open(log_filename, 'w') as log_file: sys.stdout = log_file print(doc.get_xml()) sys.stdout = sys.stdout # Restore standard output

--# Get the current date and time now = datetime.datetime.now() datestr = now.strftime("%Y-%m-%d%H-%M-%S")

--# Save the generated document with the date and time appended to the file name outputfilename = f"Client{date_str}.docx" doc.save(output_filename)

This is the one I'm using now:

from docxtpl import DocxTemplate import csv import os import datetime import sys

--# Load the template doc = DocxTemplate('/path/to/TEMPLATE_TEST.docx')

--# Load the simple text values from the CSV file simple_text_values = {} with open('simple_text_values.csv', 'r') as f: reader = csv.DictReader(f, delimiter=';') for row in reader: print(row) simple_text_values[row['Generic Text Content Control']] = row['Value']

--# Load the service orders from the CSV file service_orders = [] with open('Service_Orders.csv', 'r') as f: reader = csv.DictReader(f) for row in reader: service_orders.append({ 'Service_Order_Number': row['Service_Order_Number'], 'Contact_Name': row['Contact_Name'], 'Subject': row['Subject'], 'Delivery_Date': row['Delivery_Date'] })

--# Render the document with the context context = { 'simple_text_values': simple_text_values, 'service_orders': service_orders, } print(context)

doc.render(context)

--# Redirect the get_xml() output to a log file now = datetime.datetime.now() datestr = now.strftime("%Y-%m-%d%H-%M-%S") log_filename = f"get_xml-log-{date_str}.txt" with open(log_filename, 'w') as log_file: sys.stdout = log_file print(doc.get_xml()) sys.stdout = sys.stdout # Restore standard output

--# Get the current date and time now = datetime.datetime.now() datestr = now.strftime("%Y-%m-%d%H-%M-%S")

--# Use the same output filename as before outputfilename = f"generated{date_str}.docx"

--# Save the generated document with the date and time appended to the file name doc.save(output_filename)

This one here manages to create the file, however it creates the docx empty. It replaces all the placeholders with nothing. I'm still trying to figure out what is happening. I don't even know what I was doing wrong on that other one (because I'm only a curious person trying to solve a particular issue, I'm no developer), I think you will easily see the issue @elapouya.

Thanks anyway for your amazing work on this tool.

elapouya commented 11 months ago

Give me your template.docx please

leafarilongamor commented 11 months ago

Alright, I found out that data in csv cannot be treated like simple text (#readthedamndocs 😬).

My docx template was like: image

The simple_text_values.csv was like: image

The Service_Orders.csv was like: image

Then I changed my docx template to this and it began to work at least to the contents in the table: image

Results: image

Now I just need to adjust the rest. Thank you!