Chris Messina Posted May 28, 2021 Share Posted May 28, 2021 (edited) I probably spent far too much time not knowing what I was doing to produce this workflow but now that it will prettify a single obfuscated .json file, I could use some help with improvements: Support prettifying multiple selected files at a time (I've been able to do this with other languages, but haven't figured out how to work with an array of files in python in a Script Filter) Ignore any non-JSON files that might be passed in (currently if you run this against a TXT file, it'll replace the file contents with {query}! (whoops)) Improve the notifications based on whether a single or multiple files were processed I did take a look at @deanishe's Workflow Library or Python but it seemed like overkill for what I wanted to do. Also, I did find several other workflows that will prettify the clipboard's contents, but I specifically want to just handle files in Finder (for now). I found this technique which looked promising, but I kept getting syntax errors in the Script Filter when I would run it: import json import os # Read JSON data from file and pretty print it with open("{query}", "r") as jsonfile: # Convert JSON file to Python Types obj = json.load(jsonfile) # Pretty print JSON data pretty_json = json.dumps(obj, indent=4) print(pretty_json) Edited May 28, 2021 by Chris Messina added code sample Link to comment
deanishe Posted May 28, 2021 Share Posted May 28, 2021 (edited) 6 hours ago, Chris Messina said: Support prettifying multiple selected files at a time Your workflow's set up the wrong way for that. A File Action can output an array, and a script can accept multiple arguments (provided you use argv), but most other elements can't handle multiple inputs and will squash them into a single string. Write Text File can only write one file, so if you need to handle multiple files, you have to do it in code. Like this. Edited May 28, 2021 by deanishe Chris Messina 1 Link to comment
Chris Messina Posted May 28, 2021 Author Share Posted May 28, 2021 10 hours ago, deanishe said: Write Text File can only write one file, so if you need to handle multiple files, you have to do it in code. Like this. Amazing, thank you! I've updated my workflow and given you credit. Appreciate it! How might I add a check to make sure the selected files are actually JSON files before processing them? Link to comment
deanishe Posted May 28, 2021 Share Posted May 28, 2021 (edited) 1 hour ago, Chris Messina said: How might I add a check to make sure the selected files are actually JSON files before processing them? Your File Filter doesn't accept anything else. EDIT: More generally, a separate validity check is pointless in a situation like this because decoding the file to process it is a validity check. You should just go ahead and try to process all the files, but handle each one in a try … except clause in your main loop, so one invalid file doesn’t prevent others from being processed. Edited May 28, 2021 by deanishe Link to comment
Chris Messina Posted May 28, 2021 Author Share Posted May 28, 2021 1 hour ago, deanishe said: Your File Filter doesn't accept anything else. Right, but the keyboard shortcut bypasses that check — which is how I accidentally replaced the contents of an XML file with the path of the file... however, I just tried this again with your method and it does seem like the function won't run if it doesn't find a suitable JSON object ("No JSON object could be decoded") so I see your point! I will work on the try … except clause in my main loop though! Link to comment
deanishe Posted May 28, 2021 Share Posted May 28, 2021 45 minutes ago, Chris Messina said: which is how I accidentally replaced the contents of an XML file with the path of the file... Right yeah, good point: workflows keep running when a Run Script action fails, so your original version also needs some kind of hand-rolled error check before the Write Text File. But the script is inherently fail safe because it will error out decoding the file and never run the code that overwrites it. Chris Messina 1 Link to comment
Chris Messina Posted May 28, 2021 Author Share Posted May 28, 2021 10 minutes ago, deanishe said: But the script is inherently fail safe because it will error out decoding the file and never run the code that overwrites it. Here's what I came up with — seems to work: import json import sys for path in sys.argv[1:]: with open(path) as fp: data = json.load(fp) with open(path, 'w') as fp: try: json.dump(data, fp, indent=4, separators=(',', ': ')) except TypeError: pass How might I add a file count which gets passed to a notification? I can probably figure out the count, but I always struggle with how to pass a variable from a Script Filter to another block. Link to comment
deanishe Posted May 28, 2021 Share Posted May 28, 2021 (edited) Your try ... except is in the wrong place: the script will fail on read 99.9% of the time, not write. But in any case, you generally just put it around the entire per-item code: from __future__ import print_function import json import sys n = 0 # number of files processed for path in sys.argv[1:]: try: with open(path) as fp: data = json.load(fp) with open(path, 'w') as fp: json.dump(data, fp, indent=4, separators=(',', ': ')) n += 1 except Exception as err: # anything written to STDERR goes to Alfred's debugger print('[error] file %s: %s' % (path, err), file=sys.stderr) plural = ('s', '')[n==1] # anything written to STDOUT goes to the next action (i.e. arg/{query}) print('Prettified %d file%s' % (n, plural), end='') 40 minutes ago, Chris Messina said: I always struggle with how to pass a variable from a Script Filter to another block. Variables and arg/{query} are two different matters, and Script Filters and regular Run Script actions are two different things again. In this case, you don’t really need to use variables, because you only need one output: the notification. So you can just print the notification text because anything you print becomes the next element’s arg/{query}. Important: If you’re going to get into writing Python, you should stop using /usr/bin/python and use /usr/bin/python3 instead. (You’ll have to use Alfred's External File option for Language and the shebang #!/usr/bin/python3 to do that.) Python 2 is dead and will be gone soon, and Python 3 is easier to use, anyway. Edited May 28, 2021 by deanishe giovanni and Chris Messina 2 Link to comment
giovanni Posted May 29, 2021 Share Posted May 29, 2021 Quote you should stop using /usr/bin/python and use /usr/bin/python3 instead. @deanisheI am trying to migrate my scripts to Python3 and I get this error below from your Workflow, what am I doing wrong? my python3 version should be 3.9.4. thanks! File "[...].py", line 12, in <module> from workflow import Workflow3, ICON_WEB, web File "[...]/src/workflow/__init__.py", line 16, in <module> from .workflow import Workflow, manager File "[...]/src/workflow/workflow.py", line 25, in <module> import cPickle ModuleNotFoundError: No module named 'cPickle' Link to comment
deanishe Posted May 29, 2021 Share Posted May 29, 2021 The library isn't compatible with Python 3. giovanni 1 Link to comment
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now