masaccio / numbers-parser

Python module for parsing Apple Numbers .numbers files
MIT License
201 stars 14 forks source link

Wish: Please let me set a table caption #86

Closed GerdHoeren closed 17 minutes ago

GerdHoeren commented 2 weeks ago

Describe the bug There is no way to add a caption at the bottom of a table.

Expected behavior Please provide a way to add text to the table caption.

Additional information python -m pip list [ ... ] numbers-parser 4.10.5

masaccio commented 2 weeks ago

See https://masaccio.github.io/numbers-parser/api/table.html#numbers_parser.Table.caption

GerdHoeren commented 2 weeks ago

Setting a caption throws an exception after creating a table with: table1 = spreadsheet.sheets[tab].add_table("Virtual " + tab, 0, y, 2, 4) [ ... ] table1.caption = str(numRows) + " " + tab

Traceback (most recent call last): File "/Users/gerd/Documents/Arduino/Scripts/Python Scripts/ParseGlobals/ParseGlobals.py", line 100, in WriteSpreadsheetTab(GetTrainInputs(), "Train Inputs") File "/Users/gerd/Documents/Arduino/Scripts/Python Scripts/ParseGlobals/Spreadsheet.py", line 163, in WriteSpreadsheetTab table1.caption = str(numRows) + " " + tab File "/Users/gerd/Documents/Arduino/Scripts/Python Scripts/ParseGlobals/.venv/lib/python3.9/site-packages/numbers_parser/document.py", line 502, in caption self._model.caption_text(self._table_id, caption) File "/Users/gerd/Documents/Arduino/Scripts/Python Scripts/ParseGlobals/.venv/lib/python3.9/site-packages/numbers_parser/model.py", line 335, in caption_text caption_storage_id = self.objects[caption_info_id].super.owned_storage.identifier File "/Users/gerd/Documents/Arduino/Scripts/Python Scripts/ParseGlobals/.venv/lib/python3.9/site-packages/numbers_parser/containers.py", line 119, in getitem return self._objects[key] KeyError: 0

= = =

Interestingly, I can set/get the caption as expected if I create the table in MacOs Numbers, set the caption and then open the Numbers file from Python:

table0.caption = str(numRows) + " " + tab
print("Updated caption:", table0.caption)

Output is: Updated caption: 112 Train Inputs

masaccio commented 2 weeks ago

I plan to implement captions for new tables, but this will take some time. When a new table is added, I don't delete most of the table's attributes to force Numbers to create them when the document is first loaded. Captions are one of those and they're surprisingly complicated compared to the table title. It's also why #84 happens.

GerdHoeren commented 2 weeks ago

No rush on fixing this and #84. They are icing on the cake.

I'm extracting documentation from 35K lines of C++ and creating a spreadsheet with six sheets, where each sheet contains two tables. This is already above and beyond what I had hoped for when I found the numbers-parser package.

masaccio commented 2 weeks ago

This now supported in v4.11.5. How captions are stored changed somewhere in the past few versions and I am relying upon recent data structures in Numbers files to set captions. It should be fine for new documents as the empty doc reference is generated with 14.1.

GerdHoeren commented 2 weeks ago

Thanks for working on this, Jon. I found two issues during my testing:

Recall that my Python program reads a template that I create with MacOS numbers. It contains the tabs and the heading for the first table (table0). The program adds lines to table0, then creates table1 with the Numbers-parser API and adds lines to table1.

First, Setting the caption for table1 after adding rows to table1 with: table1.caption = str(numRows) + " " + tab

Displays the caption over the table header like this: Caption-on-title

Secondly, trying to set the caption on table0 (the one created by MacOS Numbers) crashes if the table already contains a caption. I tried a template saved with both Numbers 13.1 and 14.1. Sheets whose table0 doesn't have a caption don't crash.

table0.caption = str(numRows) + " " + tab

Traceback (most recent call last): File "/Users/gerd/Documents/Arduino/Scripts/Python Scripts/ParseGlobals/ParseGlobals.py", line 103, in WriteSpreadsheetTab(GetCarInputs(), "Car System Inputs") File "/Users/gerd/Documents/Arduino/Scripts/Python Scripts/ParseGlobals/Spreadsheet.py", line 119, in WriteSpreadsheetTab table0.caption = str(numRows) + " " + tab File "/Users/gerd/Documents/Arduino/Scripts/Python Scripts/ParseGlobals/.venv/lib/python3.9/site-packages/numbers_parser/document.py", line 502, in caption self._model.caption_text(self._table_id, caption) File "/Users/gerd/Documents/Arduino/Scripts/Python Scripts/ParseGlobals/.venv/lib/python3.9/site-packages/numbers_parser/model.py", line 340, in caption_text caption_text[0] = caption IndexError: list index out of range

Interestingly, if I don't set the caption for table0 -- to avoid the crash -- the table0 caption is appended to the new caption I set for table1. Table0:1 issue

The string "14 Train Inputs" was set by Python. "Caption 14.1" is the caption I entered from Numbers in table0.

I wanted to add my Globals.numbers template (input) file. But I don't see how to attach it to this issue.

GerdHoeren commented 2 weeks ago

One more observation. I removed my code to set the caption on table1. I reran the Python script and the caption from table0 still showed up! This makes sense from your previous comments about sharing attributes between tables. — Gerd —On Jun 19, 2024, at 1:46 AM, Jon Connell @.***> wrote: This now supported in v4.11.5. How captions are stored changed somewhere in the past few versions and I am relying upon recent data structures in Numbers files to set captions. It should be fine for new documents as the empty doc reference is generated with 14.1.

—Reply to this email directly, view it on GitHub, or unsubscribe.You are receiving this because you authored the thread.Message ID: @.***>

masaccio commented 1 week ago

You can add Numbers files zipped or just rename the .numbers to .zip (Numbers files are zipped at the top level anyway). It looks like from what you are saying I need to support the various caption storage types after all. If you have an example doc you can share, either attaching or emailing me if you don't want to make it public on GitHub that will help.

GerdHoeren commented 1 week ago

Globals.numbers.zip

Hi Jon, here's my template Numbers input file with .zip extension. It's created with Numbers 13.1 -- that's where the MacBook Air I use tops out. As I mentioned above I tried a template created with Number 14.1, but the result was the same.

Using this "Template" pattern makes it much easier to crate the sheets, table columns, headings, colors, column widths, etc. I could create them all from code, but it's less convenient to change fonts/colors, etc. then.

masaccio commented 4 days ago

It wasn't so much version dependent as Numbers stores a dummy caption when one has yet to be created for a table so I needed to create the caption storage from scratch rather than patch it. Can you give 4.12.0 a try and see how well it works for you for new captions.

GerdHoeren commented 3 days ago

Hi Jon, I tried version 4.12, but it doesn't work much better than your previous release.

I've created a small Python program that demonstrates the issues -- I should have done that before. The program reads Template.numbers, which contains two sheets and one table in each sheet (Table0). The program creates a second table and adds one row to each table. The result is saved in Output.numbers. Caption Issues.zip

If you run it unmodified, it will set the caption of both tables in the first tab ("Train Inputs"). The top table caption works as expected. But the programmatically created table concatenates the captions of both tables and the caption is written over the table title:

CaptionIssues

= = =

Secondly, uncomment line 123 of main.py: WriteSpreadsheetTab("Car System Inputs")

The script now crashes. I believe the difference between the two sheets is that I've never set its caption from MacOS Numbers.

Updated caption: Table0 Caption Traceback (most recent call last): File "/Users/gerd/Documents/Arduino/Scripts/Python Scripts/Caption Issues/main.py", line 123, in WriteSpreadsheetTab("Car System Inputs") File "/Users/gerd/Documents/Arduino/Scripts/Python Scripts/Caption Issues/main.py", line 72, in WriteSpreadsheetTab table0.caption = "Table0 Caption" File "/Users/gerd/Documents/Arduino/Scripts/Python Scripts/Caption Issues/.venv/lib/python3.9/site-packages/numbers_parser/document.py", line 502, in caption self._model.caption_text(self._table_id, caption) File "/Users/gerd/Documents/Arduino/Scripts/Python Scripts/Caption Issues/.venv/lib/python3.9/site-packages/numbers_parser/model.py", line 470, in caption_text caption_text[0] = caption IndexError: list index out of range table1 - Caption enabled: True Updated caption: Table1 Caption table0 Caption enabled: False

Process finished with exit code 1

= = =

In case you are interested: I'm a retired C++ software developer. I've got a model railroad/automobile layout that's run by 15 Arduino processors. This Python script parses the C++ header files (from 35K lines of C+) and extract electrical input and output documentation. The documentation is written to the numbers spreadsheet.

Thanks again for working on this issue.

masaccio commented 2 days ago

That's a very helpful reproducer, thank you. The debug is very much appreciated.

If fixed the exception but not I need to figure out why the second caption is being placed on top of the table:

Screenshot 2024-07-01 at 10 20 32

Sounds like your railroad setup is very impressive if it's got 15 controllers!

masaccio commented 1 day ago

Spotted another missing attribute in new tables. Your script works for me now in v4.12.1.

GerdHoeren commented 1 day ago

Thanks, Jon. v4.12.1 works in my full Python script as well.

One remaining issue is that a new table is created with captions enabled. Seems like captions should be off by default. I thought perhaps that the enable/disable was being inherited from the previous table. Try commenting out line 71 in my sample script: table0.caption_enabled = True;

The output from the script is: table0 Caption enabled: False Updated caption: Table0 Caption table1 - Caption enabled: True Updated caption: Table1 Caption

= = =

Arduino's and Trains&Car System: I've got over 500 electrical inputs/outputs. Each Arduino can reasonably handle 40-60 I/O's from an electrical standpoint. I don't need the processing power of 15 processors. (But my friends tell me I'm crazy -- rightly so :-) )

= = =

One more thing, possibly related to the table height issue... When I look at the created spreadsheet in MacOS Numbers, the second table gets created in the expected position:

Correct Table Spacing

But, on longer tables (117 rows) File->Print overlaps the second table on the end of the first. This image is from the Print Preview (the actual print looks the same as the preview):

Long Table

A shorter first table does not have this issue:

Short Table

Would you like me to open a separate issue, or is this part of the previous Table Height issue?

masaccio commented 21 hours ago

Worth a separate issue as not accounting for captions is a known limitation. But new tables are now created without captions enabled (v4.12.2).

GerdHoeren commented 11 hours ago

Thanks for fixing the captions default. Captions now work as expected. You may close this issue.

I will characterize the printing overlap issue on tables without captions and create a separate issue.

Thanks again for all your work on this. I thought a simple API accessor was needed to implement captions. But, nothing is ever simple in software!

masaccio commented 17 minutes ago

Yes captions are significantly more complex than titles and a lot of what could be done with them isn’t even available in the Numbers UI.