Forum Archive

Paths and saving files

benwiggy

I'm having trouble with the Path concept. I'm using the ObjC PDFDocument.writeToFile method, but it just crashes Pythonista.

The relevant bit of code is:

        outFilename = pathlib.Path(outFilename)
        pdfDoc.writeToFile_(outFilename)

pdfDoc is a valid PDFDocument object, and outFilename is a path as a string. The location is Pythonistas own iCloud folder, copied from a dialogs.pick_document thing.

cvp

@benwiggy Could you post the reason of the crash, of known and the content of outFilename

cvp

@benwiggy See doc of pick_document

The return value is a temporary file. 
You can read it directly, but to keep a permanent copy, you must move it somewhere else.

and a sample of returned value

/private/var/mobile/Containers/Data/Application/1E3F0CAE-F004-491D-B153-03AE8CEA73F2/tmp/com.omz-software.Pythonista3-Inbox/test3.py

See the word tmp , you can not write on it

benwiggy

Ah, I suspected that iOS's restrictions would be the cause. Yes, it's a tmp location path similar to yours.

I suppose I'll just have to save everything to:

/private/var/mobile/Library/Mobile Documents/iCloud~com~omz-software~Pythonista3/Documents

cvp

@benwiggy exactly

outFilename = '/private/var/mobile/Library/Mobile Documents/iCloud~com~omz-software~Pythonista3/Documents/xxx.xxx'  
benwiggy

Ah. It's still crashing the app, though.

cvp

@benwiggy thus, first question, reason of the crash...

benwiggy

I don't know what the cause is, but it only happens when I uncomment the writeToFile line.

Is there a log somewhere?

cvp

@benwiggy Install this script
as pythonista_startup.py in your site-packages directory of Pythonista, restart Pythonista and retry your code, you will get the log **after next restart **

cvp

@benwiggy This very little and ugly script works...
It picks a pdf and write it as PDFDocument to Pythonista iCloud

from objc_util import *
import dialogs

fil = dialogs.pick_document()
url = nsurl(fil)
PDFDocument = ObjCClass('PDFDocument').alloc().initWithURL_(url)
#print(dir(PDFDocument))

outFilename = '/private/var/mobile/Library/Mobile Documents/iCloud~com~omz-software~Pythonista3/Documents/xxx.pdf'  

PDFDocument.writeToFile_(outFilename)

benwiggy

Thanks.

It's complaining about NSURL not having a string parameter for initFileURLWithPath when it crashes, but it doesn't complain about when writeToFile is commented out, which is weird.

I'm trying to convert some MacOS PyObjC code into something that'll work here.

Thanks for the example: I'll give it a try.

cvp

@benwiggy is it possible to post your code?

benwiggy
import os

from objc_util import *
from pathlib import Path
import dialogs

PDFDocument = ObjCClass('PDFDocument')
NSURL = ObjCClass('NSURL')
home = "/private/var/mobile/Library/Mobile Documents/iCloud~com~omz-software~Pythonista3/Documents/"

def rotate(filename):
        shortName = Path(filename).stem
        outFilename = home + shortName + "+90.pdf"
        pdfURL = NSURL.fileURLWithPath_(filename)
        pdfDoc = PDFDocument.alloc().initWithURL_(pdfURL)
        if pdfDoc:
            pages = pdfDoc.pageCount()
            for p in range(0, pages):
                page = pdfDoc.pageAtIndex_(p)
                existingRotation = page.rotation()
                newRotation = existingRotation + 90
                page.setRotation_(newRotation)

            outFilename = Path(outFilename)
            print (outFilename)
            pdfDoc.writeToFile_(outFilename)


if __name__ == '__main__':
        filename = dialogs.pick_document(types=['public.data'])
        rotate(filename)
cvp

@benwiggy by commenting this line, it works

            #outFilename = Path(outFilename)
benwiggy

Brilliant! I told you I was confused about Path !!

Excellent. Hopefully I should now be able to modify all my MacOS python scripts for PDFs along the same lines.

Many thanks.

cvp

@benwiggy I didn't even know the existence of pathlib 😅

mikael

@benwiggy, did you look at using Python PDF manipulation library included in Pythonista? I think you might get a more robust solution with it.

Here’s an example combining all the PDFs in a directory into one file:

#coding: utf-8

from PyPDF2 import PdfFileMerger
import glob

pdfs = sorted(glob.glob("PDF/*"))

merger = PdfFileMerger()

for pdf in pdfs:
    merger.append(pdf)

merger.write("Combined result.pdf")
cvp

@benwiggy In this case, your script could become:

import os

from pathlib import Path
import dialogs
from PyPDF2 import PdfFileWriter, PdfFileReader

home = "/private/var/mobile/Library/Mobile Documents/iCloud~com~omz-software~Pythonista3/Documents/"

def rotate(filename):
        shortName = Path(filename).stem
        outFilename = home + shortName + "+90.pdf"
        pdfDoc = PdfFileReader(filename)
        if pdfDoc:
            output = PdfFileWriter()
            pages = pdfDoc.getNumPages()
            for p in range(0, pages):
                page = pdfDoc.getPage(p)
                page_out = page.rotateClockwise(90)
                output.addPage(page_out)

            outfil = open(outFilename, 'wb')
            output.write(outfil)
            outfil.close()
            print (outFilename)


if __name__ == '__main__':
        filename = dialogs.pick_document(types=['public.data'])
        rotate(filename)