Jump to content

Filtering JSON Output: A Very Basic Python Question


Recommended Posts

I have a very basic python question that I was hoping to get a little help with that involves filtering out list items in a script filter. At the moment, the script filter works great except that it includes a few items I'd prefer not to see in Alfred's output. Is there any easy way to remove items whose titles can be found in another list?

 

Admittedly, I normally do these sorts of things in AppleScript - which is pretty easy to do in this case - except that I’ve been trying to learn a little python, given all of the limitations with AppleScript (which @deanishe and @vitor have rightly reminded me of on numerous occasions, so hopefully this will make them proud 😃).

 

For example, let’s say that I have the following list:

 

titles_remove = {"Title A", "Title B", "Title C"}

 

And, before outputting my results in Alfred, I’d like to remove all items whose titles can be found in titles_remove.

 

At the moment, my script filter ends with the following line:

 

print(json.dumps(result))

 

And, it’s JSON output follows the usual format where each item has a title, subtitle, uid, and arg. Now, if I modify that last line so that it’s output is:

 

unfiltered_output = json.dumps(result)

 

What should I do next to remove items whose titles can be found in the titles_remove list?

 

I tried following several different python tutorials, but I kept receiving errors. I suspect that some of the methods weren't intended for dealing with strings. But I'm a complete newbie here. 

 

Thanks for any help you can lend! I really appreciate it. And, if anyone has any advice for python newbies that might want to do things with Alfred, I'd greatly appreciate any recommendations on potential resources to check out, etc. Thanks!!

Link to post
1 hour ago, Jasondm007 said:

For example, let’s say that I have the following list

 

That syntax defines a set, not a list. It doesn’t matter here, but it’s important to know the difference. A set usually isn’t what you want.

 

1 hour ago, Jasondm007 said:

And, before outputting my results in Alfred, I’d like to remove all items whose titles can be found in titles_remove

 

You use a for loop or a list comprehension to remove the items you don’t want:

# assuming results is a list of Alfred feedback dicts:
# [
#   {
#       'title': '...',
#   },
# ]
results = [d for d in results if d['title'] not in titles_remove]

 

1 hour ago, Jasondm007 said:

print(json.dumps(result))

 

This is rather inefficient. It’s better to use json.dump(result, sys.stdout)

Link to post

@deanishe Thanks a ton for getting back to me. This is super helpful!

 

Although I've run into this issue on several occasions, this post was prompted by my frustration trying to modify a portion of Charles Ma's workflow (which I had originally changed to read a different plist file in DEVONthink). I tried implementing your suggestions in a couple of different ways, but am running into similar errors as before.

 

I've included one such iteration below. The line that is commented out is essentially where the script used to stop. I assume I'm implementing the "for" loop incorrectly?

 

#!/usr/bin/python
# -*- coding: UTF-8 -*-
import plistlib
import os
import json
titles_remove = {"Title A", "Title B", "Title C"}
filePath = os.path.expanduser("~/Library/Application Support/DEVONthink 3/SmartGroups.plist")
if os.path.exists(filePath):
    result = {"items": []}
    plObjList = plistlib.readPlist(filePath)
    for plobj in plObjList:
        result["items"].append({
            "title": plobj["name"],
            "subtitle": "Open Smart Group",
            "uid": plobj["name"],
            "arg": plobj["sync"]["UUID"]})
    #print(json.dumps(result))
    unfiltered_output = json.dumps(result)
    filtered_output = [d for d in unfiltered_output if d["title"] not in titles_remove]
    print(json.dumps(filtered_output))
else:
    print('{"items": [{"title": "Error","subtitle": "No Smart Groups Found"}]}')


Thanks again for all of your help!

 

Relatedly, do you have a favorite editor for testing python scripts? I've always liked the simplicity of Apple's Script Editor and was hoping to find something equally as easy to work with. At the moment, I've usually just tinkered around in Alfred with python scripts or Atom & BBEdit but I find their outputs difficult to see. Thanks again!

Link to post
5 hours ago, Jasondm007 said:

unfiltered_output = json.dumps(result)

filtered_output = [d for d in unfiltered_output if d["title"] not in titles_remove]

 

Get rid of unfiltered_output. That line converts result to a string. Second line should be result = [d for d in result if d['title'] not in titles_remove]

 

And if you have any more questions, please upload your workflow somewhere.

 

5 hours ago, Jasondm007 said:

Relatedly, do you have a favorite editor for testing python scripts?

 

What do you mean "testing"? I mostly use Sublime or neovim as an editor, in any case.

 

Link to post

@deanishe Thanks again for all of your help. And, for the editor suggestions, too! I haven't tried either of those editors yet, so I'll check them out. Much appreciated!

 

As for script itself, I'm afraid that I keep getting the same string indices error. I've included the script below, and uploaded a test workflow at the link provided. My apologies  for not uploading the workflow earlier. I didn't think there'd be enough people with DEVONthink to have any interest (or people to test, for that matter). In any case, thanks again for any help you can lend!

 

#!/usr/bin/python
# -*- coding: UTF-8 -*-
import plistlib
import os
import json
titles_remove = {"Title A", "Title B", "Title C"}
filePath = os.path.expanduser("~/Library/Application Support/DEVONthink 3/SmartGroups.plist")
if os.path.exists(filePath):
    result = {"items": []}
    plObjList = plistlib.readPlist(filePath)
    for plobj in plObjList:
        result["items"].append({
            "title": plobj["name"],
            "subtitle": "Open Smart Group",
            "uid": plobj["name"],
            "arg": plobj["sync"]["UUID"]})
    #print(json.dumps(result))
    #unfiltered_output = json.dumps(result)
    #filtered_output = [d for d in unfiltered_output if d["title"] not in titles_remove]
    result = [d for d in result if d['title'] not in titles_remove]
    print(json.dumps(filtered_output))
else:
    print('{"items": [{"title": "Error","subtitle": "No Smart Groups Found"}]}')

 

Link to post
5 hours ago, Jasondm007 said:

result = [d for d in result if d['title'] not in titles_remove]

print(json.dumps(filtered_output))

 

Sorry, this bit was wrong (wrong data structure).

 

result['items'] = [d for d in result['items'] if d['title'] not in titles_remove]
json.dump(result, sys.stdout)

 

Link to post
9 hours ago, Jasondm007 said:

I haven't tried either of those editors yet, so I'll check them out.

 

As a user of Neovim myself, I doubt @deanishe is recommending you use it. Vim’s a hard editor to grasp and you’ll be fighting to set it up and use it for a while, which is definitely not what you need right now.

 

Sublime Text is good, but it is paid (or it nags you). Consider Visual Studio Code. It’s simple, capable, free and open-source, actively developed by a major company (Microsoft), and insanely popular (which translates to a vast plugin system). Yes, it’s build on Electron, but it’s far from the worst use of it.

Link to post

@deanishe Thanks for taking a look at it again. As usual, your suggestion worked perfectly! I'm looking forward to going back and updating some of my other scripts. Thanks a ton!!

 

@vitor Thanks for the editor suggestion, too. I just installed Visual Studio Code, and it's output is definitely a lot easier to see than working directly in Alfred or using Atom or BBEdit. Thanks!!

 

By chance, do either of you guys have any suggestions for resources or tutorials for python newbies who would like to do a little tinkering in Alfred, etc.?

Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...