PyDT3 - The Missing Python API for DEVONthink

TBH, I’ve always been hating the AppleScript. The weird syntax, limitted ability and poor scalability. The list goes on. I don’t need to prove it, Apple itself is trying to replace it. Granted it has its usage, I do not enjoy writing it ever.

That’s why I wrote PyDT3, the Python API for DEVONthink. Underlying it uses PyObjC to communicate with AppleScript.

Unlike many other API wrapper projects, PyDT3 is well documented thanks to the detailed AppleScript dictionary by DEVONthink team and the code generation ability of ChatGTP.

Simple example:

from pydt3 import DEVONthink3
dt3 = DEVONthink3()
for db in dt3.databases:
    print(db.name)
tell application "DEVONthink 3"
    repeat with db in databases
        log name of db as string
    end repeat
end tell

More details can be found at the GitHub Page.

It’s still in early stage but I’ve integrated the OpenAI’s ChatGPT ability into DEVONthink using the Python API easily (see examples section in GitHub).

That being said, it is probably still pretty buggy. Do issue any bugs you find.

14 Likes

While i dislike and disagree with your expression of disrespect for AppleScript, I welcome this for using Python as a programming resource. Python has been and is my preference also for many reasons and I look forward to experimenting with your contribution. Many possibilities are now enabled. Thanks.

I say it just for dramatic. AppleScript is not that bad but it’s hard to maintain when the codes grows.

1 Like

Fascinating… many thanks - definitely worth a look

What development environment do you recommend for your Python-DT3 projects?

PyCharm?

Anvil?

Something else?

Yes, Python is much preferable to a lot of things and with its broad functionality with so many other resources (NumPY, SciPy, Pandas, statistics, networking, web, …) has stood the test of time for me and millions more for a very long time and a long time yet. Thanks for contributing an API for DEVONthink. I knew it only a matter of time till it was done.

1 Like

Personally I use VS Code but you can use any as you like. The documents are written into the source code so any mainstream python editors should have code suggestions and auto completions out of box.

1 Like

Can you clarify please how the API function works

Anvil as you probably know hosts Python in the cloud and thus can be used to build and host web apps

Can I use Anvil and still access your API and thus be able to write a Python Web App which has access to my DT3 data?

Or does your API have to run local on my Mac in order to access the DT3 data?

The Python API uses the AppleScript API. It just maps the AppleScript API to Python. So you have to run it locally. If you want to run it remotely, you can run a web server on your local machine listening incoming messages. But that’s off the topic I think.

2 Likes

Thanks for doing this – this is nice to see.

I’ve developed a number of utilities that interact with DEVONthink, and though my day job these days is developing software mostly in Python, so far I’ve always resorted to using either AppleScript or a now-deprecated Python framework called py-appscript when it came to writing stuff to interact with DEVONthink. I really look forward to using an actual Python API library instead!

3 Likes

Good day,
for the past few weeks, I’ve been facing some challenges while trying to get into Applescript. Coming from a Python background and being a former Windows user, it’s been a bit of a struggle. My main objective is to analyze and enhance my database, recently by prioritizing email senders based on their occurrence frequency from highest to lowest and sorting stuff out.
However, working with Applescript’s unique structure has proven to be quite cumbersome. To cut a long story short, if the Python API is as powerful as I believe it to be, it will be a complete gamechanger for me. Thank you so much!

1 Like

Alternatively, you could try JavaScript. That works ok with DT except for some border cases. Definitely closer to Python than AppleScript.

Totally agree there - I think Applescript seem more intuitive to those with no coding background. JXA is more of a quick learn for those with some other programming background.

That aside- there are tons of other reasons to learn Javascript besides Mac scripting.

1 Like

I like Python also. It’s infrastructure is massively larger than AppleScript and probably JavaScript–somewill disagree, of course.

Have you tried the API mentioned at top?

I haven’t but at some point I will.

Yes, I was able to accomplish my priorly mentioned goal with help of the PyDT3 API within a few minutes while I had already invested 15+ Minutes with Applescript without the result. Anyways: Will keep trying it out.

I do use JS with GSuite Appscript a fair bit but why learn another language in depth if you already know one that can do the job :smile:

3 Likes

Good to know. I also can also get results things relatively quickly with Python. And I do exploit tools like Pandas, database access, and such.

I will dig in to this API but I do not yet do much automation with DEVONthink. And from a post a few days ago I got intrigued about importing Apple Messages into DEVONthink markdown files and CSV summary files. All in Python.

I tried to get GPT to write me a script to search one of my Devonthink databases for a particular phase and then export the results. After a lot of back and forth, error messages and clarifications, it has finally written me a script that does not generate error messages and it says ‘will effectively search for documents containing the phrase “have not nations” in the DEVONthink Pro database named “1940” and save the names and locations of these documents to a text file on the desktop.’ The only thing is so far, while it should be finding 23 instances of the phrase, it finds none and exports an empty txt document. This is probably not a fruitful activity as I have no knowledge of Apple Script. I have found though teaching myself Python that GPT 4 is very effective at correcting coding errors and so on, at least at a beginners level. I’ll paste the code here and interested if anyone more knowledgeable can tell me if this is worth pursuing any further.

set searchPhrase to "have not nations"
set dbName to "1940"
set outputFile to "/Users/davidgoodman/Desktop/Havenot/have_not.txt"

tell application id "DNtp"
	-- We'll start with a broad search without specifying the database.
	set allSearchResults to search searchPhrase
	
	set foundItems to {}
	
	-- Iterate through the search results.
	repeat with anItem in allSearchResults
		-- Check if the item is from the desired database and is a document.
		if (database of anItem is (get database named dbName)) and (type of anItem is rtf or type of anItem is text or type of anItem is PDF document) then
			set textRetrievedSuccessfully to true
			
			try
				set itemText to get text of anItem
			on error
				set textRetrievedSuccessfully to false
			end try
			
			if textRetrievedSuccessfully and itemText contains searchPhrase then
				set end of foundItems to (name of anItem & " - " & (get location of anItem))
			end if
		end if
	end repeat
end tell

-- Write results to the file
my writeToFile(outputFile, foundItems)

on writeToFile(fileLocation, dataList)
	-- Ensure the file exists using the touch command
	do shell script "touch " & quoted form of fileLocation
	
	-- Clear the contents of the file
	do shell script "echo '' > " & quoted form of fileLocation
	
	-- Write each line to the file
	repeat with aLine in dataList
		do shell script "echo " & quoted form of aLine & " >> " & quoted form of fileLocation
	end repeat
end writeToFile

Apart from the fact that most human scripters wouldn’t write scripts that way :slight_smile:, there’s also an issue with the search term. The script searches for have not nations which is identical to have NOT nations and therefore most likely not what you had in mind. Meaning that the script first searches for items containing have but not nations and then checks whether the results contain the string have not nations. This can’t work.

1 Like

Oh OK! Is there a way to correct that?

I’d suggest to spend your time learning to write scripts in either AppleScript or JavaScript then teaching ChatGPT to get its act together.

It is notoriously bad with AppleScript as there’s little content on the internet it can copy, so trying JavaScript might lead to better results. But also in that case, the machine has probably only little knowledge of DT’s scripting dictionary.

2 Likes

I persisted a bit longer and this script did work - it exported the names of the files with the target phrase:

set searchPhrase to "\"have not nations\""
set dbName to "1940"
set outputFile to "/Users/davidgoodman/Desktop/Havenot/have_not.txt"

tell application id "DNtp"
    set allSearchResults to search searchPhrase
    set foundItems to {}
    
    -- Iterate through the search results.
    repeat with anItem in allSearchResults
        -- Check if the item is from the desired database.
        if name of (database of anItem) is dbName then
            set end of foundItems to (name of anItem & " - " & (get location of anItem))
        end if
    end repeat
end tell

-- Write results to the file
my writeToFile(outputFile, foundItems)

on writeToFile(fileLocation, dataList)
    -- Ensure the file exists using the touch command
    do shell script "touch " & quoted form of fileLocation
    
    -- Clear the contents of the file
    do shell script "echo '' > " & quoted form of fileLocation
    
    -- Write each line to the file
    repeat with aLine in dataList
        do shell script "echo " & quoted form of aLine & " >> " & quoted form of fileLocation
    end repeat
end writeToFile

What I would like now is to have it export say 20 words either side of the target phrase, but that is proving trickier.