I created this example app, it takes any list of forms, and if they can be rendered within the individual time limit of one call to anvil.pdf.PDFRenderer, aggregates them all using the new anvil data_files service and then combines them using PyPDF2 which is already available on the paid plan.
You would also need the paid plan to use the data_files service. (**see below)
It also takes a list of tuples in the format of ('form_name', args, kwargs) so you can do as @stefano.menci described in his FR, making sure all the data for each form is crunched and ready to be fed into the form to be rendered before making PDFRenderer create the form.
It should hopefully be mostly clear from reading the example code in the app.
(fixed it, when you create a new clone, there is no temp directory for the data_files service, I had to auto-create one.)
The clone link gives you all of the server module code you would need to just copy and paste it into your own app, as long as you install the data files service.
It uses background tasks to exceed the normal 30 second server call limit.
( so have the client periodically check the task object )
The rest of the app is an example of how to use it, the background tasks, how to retrieve the combined file from the data_files service, etc.
I tested it on over 135 pages of ‘random time to render’ test forms, creating an 11MB pdf with images and random text on each page, you can enable this extra long form of testing in the Form1.__init__() code on the startup form. There are code comments explaining how.
This 135 page PDF worked, despite taking over 890 seconds:
I had to hack together a part of the data files service that does not exist yet.
So, it turns out you can edit a file from the data_files but you can’t create one, and the code available on github is marked with a TODO, so I just built it myself, so my code should be replaced in the future if the Anvil team implements an official method.
I found out the limit for the PDFRenderer spinning off as tasks was about 5 at a time, so it chunks them at 5 at a time. This means it could be slower if you were somehow making very long quick to render forms that were more pages but never hit any timeouts.
This just for fun, (I’m sure ill use it later) but other than answering questions about it, I’m not really interested on working on it any further, so if you have something you’d like to add, feel free to post a new clone link below!
** If someone wanted to, nothing would stop them from modifying this to send each rendered pdf over uplink via media objects to some other machine and have PyPDF2 combine the files there and return them, but you would still have to watch out for a 30 second background task timeout, and any other unavailable standard library things I used that are unavailable on the free tier.
That’s exactly why the 30 second timeout limit ends up with wasting resources rather than saving them: it forces me to spin the renderer many times instead of just once.
The app can usually make an estimated guess about the time required to render each form. So the “5 at a time” chunking could be dynamically set.
Thank you for taking the time to play with it!
Right now I have other priorities and can’t spend time on that app. Last week a colleague needed to print a PDF that was hitting the limit. I started debugging the app, and after a few attempts, one “accidentally” completed the rendering on time. I sent that PDF to my colleague and put this problem in my todo list. I’m sure soon there will be another large truck carrying a lot of stuff, and printing its packing list will take too long, and I will have a look at your solution, and maybe add a clone link to show my version.
I am going to aggregate some forum links here because I have seen requests for how to do this from people before, and you have to know plenty of anvil concepts before you can get to the point of the app above: