deanishe

Workflow Library for Python

80 posts in this topic

IMPORTANT NOTE ABOUT HANGING PROCESSES ON SIERRA (2017-04-03)

 

Versions of Alfred-Workflow older than 1.25 cannot launch background processes properly on Sierra. In fact, they regularly hang quite dramatically and consume 100% CPU :( 

 

Users (in particular) affected by this bug should install and run this workflow, which can find and fix any workflows with broken versions of Alfred-Workflow.

 

--

 

Alfred-Workflow (for Python)

 

GitHub | Documentation


A state-of-the-art Python library for Workflow developers.

Being about a year late to the party, I've taken the opportunity to steal all the best ideas from other libraries and circumnavigate the bad ones, combining a plentitude of goodness into a library for the best language for Workflows (Python, natch).

The library is simple to install, has no external dependencies, is very well-documented and maintained, and boasts an eye-wateringly high feature-to-size ratio at just 140 KB.

Main features

  • Catches, logs and notifies users (and developers) of errors in Workflows. No more confusing, silent failure.
  • Super-simple, yet powerful data caching (e.g. from a web service) and storage.
  • Easy-to-use storage of Workflow settings.
  • Keychain access for secure storage (and cross-machine syncing) of sensitive data, like passwords and API keys.
  • Tunable and understandable Alfred-like fuzzy search (e.g. got matches Game of Thrones as well as Baby Got Back. Or not: that's up to you.) Now with solid support for multi-word queries.
  • Extremely lightweight, but full-featured, HTTP library with Requests-like interface, but just 12 KB instead of > 2 MB.
  • Convenient access to standard OS X icons, for high-quality, familiar icons without adding size to the library. Also available via proper English.
  • Pre-configured, built-in logging to enable simpler Workflow debugging.
  • Painlessly run (update) scripts in the background without blocking your workflow, so you can still show "old" results while fetching new ones.
  • Supports Alfred's new (version 2.3) modifier-specific subtitles.
  • Simple support for 3rd-party libraries your Workflow relies on.
  • "Magic" arguments to make developing/debugging Workflows so much easier, especially when helping less technically-inclined users. With "magic" arguments, you and your Workflow's users can open the Workflow's log file in Console.app, its cache and data directories in Finder, and its root directory in Finder or Terminal from the comfort of Alfred's query box. You can also delete the cache/data/settings if something is corrupted.
  • Your workflow can update itself via GitHub releases.
  • Accent-folding, so you can search non-ASCII text (e.g. voilà will be matched by voila)
  • Functions to support migrating settings/data from older versions of your workflow.
  • Well supported and kept up-to-date with Alfred's features as they are added.

Alfred 3-only features

  • Workflow variables
  • Advanced modifiers
  • Alfred 3-only updates
  • Re-run Script Filters

 

And as you can see from the above links, there is extensive documentation, including a two-part tutorial on building a Workflow from scratch.

Examples

Here are a few examples of how you can do some pretty cools stuff in just a few lines of code.

Remember, each of these Workflows also has—for free—full error-catching and -logging support, and the ability to open its log file (which contains all errors) via Alfred's query box. No need to ask users to grub around in ~/Library or flounder in Terminal here. This is not the Workflow library 2014 deserves, but it's the one it needs  ;) 

Selected workflows based on Alfred-Workflow

And dozens more.

 

Testimonials
 

Quote

This is the best Workflow library ever!

 

— me
 

 

Quote

it is genius and I appreciate having it in ZotQuery*

 

Stephen

* = might be taken a wee bit out of context :)

Feedback

If you have any bug reports/feature requests, add them either here or on GitHub.

More info

The documentation is the definitive source of information on the Alfred-Workflow library. The User Manual and Tutorial provide fairly extensive information both on how to use Alfred-Workflow and write Workflows in general (if you're new to this lark).

 

Edited by deanishe
Emphasise scale of problem with AW<1.25 and Sierra
idea4IT, Summxt, dfay and 3 others like this

Share this post


Link to post
As Dean said, I've moved my ZotQuery workflow to this library. For the many workflow authors out there who have used the wonderful, but unfortunately abandonware alp Python library, you will want to move over. Not only is this an actively developed, but Dean isn't joking about the debugging/error handling functionality. It is extremely useful. As someone who's dealt with a good bit of user debugging, these features are exactly what workflow authors need to take care of issue quickly, even with user's who aren't knowledgable about the funky code stuff. 

 

I hope at some point soon(ish) to write something short comparing Alfred-Workflow to alp and describing some of the specific issues I encountered when moving from one to the other. But, it was pretty simple (and also offered me an opportunity to clean some code up). All that to say, I would recommend Python workflow authors to seriously check this out. I feel confident that at some point it will make your life easier. And isn't that what Alfred is all about :)

Edited by smarg19

Share this post


Link to post

Thanks for the endorsement :)

BTW, I've added a new "Open Workflow directory in Terminal" magic arg (workflow:openterm).

What do you think about automatically adding a lib or packages subdirectory to sys.path if one exists? I'm not sure if that's perhaps a bit too much "magic", but I don't think it'd break anything. Perhaps only if there's no __init__.py inside it.

Share this post


Link to post

Depends. Me personally, I'm a bit anal about only importing what I need when I need it. But if it were "invisible", then it wouldn't really affect that part of my brain. I do like the idea tho, insofar as it would help workflows move towards standardization, since that folder would need to named something fixed, for Alfred-Workflows to find it. 

Share this post


Link to post

To clarify: I'm not talking about importing anything. I'm just considering automatically adding certain subdirectories to sys.path, so you can import from them if and when needed.

The library is quite careful about paths, so it should still do its thing correctly if the workflow root isn't the working directory. To get that behaviour in your scripts while using the Workflow(libraries=...) argument, you need to do os.path.join(os.path.dirname(__file__), 'mysubdirectory') which is a bit more complex that I was aiming for.

Share this post


Link to post

A few new features:

  • Supports Alfred 2.3 modifier-specific subtitles
  • Multi-word queries
  • Running background scripts, so you can still show (cached) results while your workflow fetches new data.
  • Basic accent-folding to search non-ASCII text with ASCII queries (e.g. munchen will match München)
Edited by deanishe

Share this post


Link to post

Hey deanische!

Your workflow sounds awesome! I've been using an equivalent workflow fetching results from Wolfram Alpha live in Alfred, but it's pretty slow...

I tried your workflow, but I cannot get past "conv {input}". As soon as I type an input, I get an alert requiring me to install XCode... Any idea of what's going on?

Thanks for your help!

Share this post


Link to post

Do you mean this workflow?

 

If so, could you post in that thread? This one is for different software.

 

To actually answer your question, yes, I've figured out what the problem is. I'll post an update in the appropriate thread once I've fixed it (maybe an hour).

Share this post


Link to post

Hey,

Yes, my bad. I hadn't realised I was posting in the wrong tab. I'll look out for your fix. Thanks again!

Share this post


Link to post

Hi! I've got a problem with another workflow, based on this helper.

Can you help me?

 

I've moved (for test) workflow from /Users/pavel/Dropbox/Приложения/ to /Users/pavel/Dropbox

and the workflow started working.

 

There is the error log:

Starting debug for 'Homebrew for Alfred'

[ERROR: alfred.workflow.input.scriptfilter] Code 1: Traceback (most recent call last):

  File "brew.py", line 148, in <module>

    wf = Workflow()

  File "/Users/pavel/Dropbox/Приложения/Alfred/Alfred.alfredpreferences/workflows/user.workflow.08964E06-AFFB-45F2-AA38-CFEC96D9534C/workflow/workflow.py", line 825, in __init__

    self._info_plist = self.workflowfile('info.plist')

  File "/Users/pavel/Dropbox/Приложения/Alfred/Alfred.alfredpreferences/workflows/user.workflow.08964E06-AFFB-45F2-AA38-CFEC96D9534C/workflow/workflow.py", line 1125, in workflowfile

    return os.path.join(self.workflowdir, filename)

  File "/Users/pavel/Dropbox/Приложения/Alfred/Alfred.alfredpreferences/workflows/user.workflow.08964E06-AFFB-45F2-AA38-CFEC96D9534C/workflow/workflow.py", line 1081, in workflowdir

    if os.path.exists(os.path.join(dirpath, 'info.plist')):

  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/posixpath.py", line 80, in join

    path += '/' + b

UnicodeDecodeError: 'ascii' codec can't decode byte 0xd0 in position 21: ordinal not in range(128)

Edited by facetheheat

Share this post


Link to post

Confirmed as a bug in the library.

 

I'll try to get that fixed by tomorrow. The fix is simple enough; creating the tests to ensure it doesn't happen again is a different matter…

Share this post


Link to post

This library really helped me re-jump into trying to learn programming . I've written three workflows now based around using this, each one building on the other and it's been super helpful.

deanishe and smarg19 like this

Share this post


Link to post

Important Message

 

There is a pretty serious bug in all versions of the library previous to 1.8.6 (the current version). If a user has non-ASCII characters anywhere in the path to where his/her workflows are installed, the library will fail.

 

If you've released a workflow based on Alfred-Workflow, please update it to use at least version 1.8.6 of the library.

 

My sincere apologies to the users and developers this has affected.

Edited by deanishe

Share this post


Link to post

This library really helped me re-jump into trying to learn programming . I've written three workflows now based around using this, each one building on the other and it's been super helpful.

 

Much appreciated :)

 

They're some pretty cool workflows you've written there.

 

May I suggest you consider including the library (and info.plist, icon.png etc.) in your repos. That way, if someone downloads or forks the repo, they have a working workflow.

Edited by deanishe
frankspin likes this

Share this post


Link to post

Much appreciated :)

 

They're some pretty cool workflows you've written there.

 

May I suggest you consider including the library (and info.plist, icon.png etc.) in your repos. That way, if someone downloads or forks the repo, they have a working workflow.

 

I'm planning to redo my github repo for my Alfred workflows, so I'll note to make sure these are included.

Share this post


Link to post

Important Message

 

There is a pretty serious bug in all versions of the library previous to 1.8.6 (the current version). If a user has non-ASCII characters anywhere in the path to where his/her workflows are installed, the library will fail.

 

If you've released a workflow based on Alfred-Workflow, please update it to use at least version 1.8.6 of the library.

 

My sincere apologies to the users and developers this has affected.

 

Thanks for the heads up. I'll update as soon as poss.

Share this post


Link to post

If you haven't been getting bug reports, it's likely not super-urgent. It's not like it can expose your nudie pics or anything.

 

On that note, anyone else just added 2-factor authentication to iCloud?

Share this post


Link to post

Hi!

 

Thanks for all your work getting this together.

 

I'm rather new to the workflow scene. Little experience in python.. enough to be dangerous but lots to learn in terms of making more application based stuff.

 

I'm getting this error when trying to use the workflow library in my script:

_init__.py", line 18, in <module>
    __version__ = open(os.path.join(os.path.dirname(__file__), 'version')).read()
IOError: [Errno 2] No such file or directory: '/Users/carsonjones

Any idea on how to fix this?

 

Thanks!

Edited by carson

Share this post


Link to post

Do you have a version file in the workflow directory? And part of the error message is missing.

Share this post


Link to post

It was my mistake. I didn't update my distribution scripts to add the version file to the distribution archive.

 

Everything should be working again in 1.9.1.

 

The same goes for the version on PyPI.

Share this post


Link to post

I've used this library a bunch but this is the first time I've tried to cache data. I've looked through the documentation but I'm hitting a point where I can't troubleshoot further.

     boards = wf.cached_data('trello_boards', getBoards(api_key), max_age = 60)

     for board in boards:
        wf.add_item(title = board['name'])

When I run the workflow I get: TypeError: 'list' object is not callable

 

I doublechecked my function and it works so I'm at a bit of a loss.

Share this post


Link to post

The idea of cached_data() is to avoid generating/fetching data if the cache is up-to-date. So, instead of passing it the data it should cache, you pass it a function it can call to get fresh data if the cached data is too old/non-existent.
 
You're passing the results of a call to getBoards(). You need to pass the function itself, which cached_data() will then call if necessary.
 
Normally, that looks something like this:
 

def fetch_new_data():
    # grab data from a web service/app here
    # ...
    return new_data

data = wf.cached_data('cache-name', fetch_new_data, max_age=600)

 
 Note that I'm passing fetch_new_data not fetch_new_data() to cached_data(), i.e. the function itself, not the data returned from calling the function.
 
You can't just pass the function in this case, however, as getBoards() takes an argument.
 
Check out the example script here. Look at the wrapper function and the call to cached_data() (lines 82–89). Note that I pass wrapper to cached_data without calling it.
 
You could also pass lambda api_key: getBoards(api_key) or functools.partial(getBoards, api_key). I wrote a separate wrapper() function in the tutorial to make it clearer and more explicit (lambda is ugly).
 
Does that help?

Edited by deanishe
frankspin likes this

Share this post


Link to post

Thanks! That makes sense and I'll dig into when I'm not at work. Appreciate the help and hard work you do.

 

Edit: yep that did it. Thanks. I was working off of the stuff in usermanual so maybe that's where I was getting confused.

Edited by frankspin

Share this post


Link to post

Hmm. The User Manual and Tutorials say basically the same thing. Perhaps I should clarify that a function should be passed, not called. I guess passing functions around is not a super-common thing to do.

Share this post


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