Jump to content

An error I don´t understand using Script Filter


Recommended Posts

I have a bug in my workflow, and I don´t understand the cause - so I thought maybe some of you have experienced the same problem.

 

My workflow is a script filter getting a wifi-scan terminal output and populates the workflow with available networks to connect. Most of the time, it is working fine. However, sometimes Alfred shows no items. It seems to me that this happens when the workflow hasn´t been used for a while, but I haven´t tested that hypothesis extensively.

I use the Python Library in my script filter.

 

Anyone experienced something similar?  It takes a few seconds to scan and import to the script, can that be the issue?

 

PS: Is there a spoiler-function here?

# -*- coding: utf-8 -*-

"""This populates the workflow with networks available for connection
using the tool "m-cli" or "Swiss Army Knife" command line tools.
"""

import sys
import subprocess
from workflow import Workflow


def getNetwork():
    """This fetches a network scan using m-cli"""
    subprocess.call("./get_network.sh", shell=True)
    networkScan = []
    with open('networkScan.txt') as inputfile:
        for line in inputfile:
            networkScan.append(line.strip().split(','))

    scanNames = []
    scanRS = []

    for i in xrange(len(networkScan) - 1):
        results_line = networkScan[i + 1][0].split(":", 1)
        scanRS.append(results_line[1][15:18])
        scanNames.append(results_line[0][0:-3])

    return scanNames, scanRS


def search_key(key):
    """This function is a search key for the wf filter.
    It means that the Title of the item is the only relevance for the
    search filter"""
    elements = []
    elements.append(key['title'])
    return u' '.join(elements)


def main(wf):
    """This function generates actionable items in Workflow"""

    if len(wf.args):
        query = wf.args[0]
    else:
        query = None

    networks = wf.cached_data('networks', getNetwork, max_age=30)
    items = []

    for i in xrange(len(networks[0])):
        if int(networks[1][i]) > -55:
            newItem = dict(title=networks[0][i],
                           subtitle="Signal strength " + networks[1][i],
                           autocomplete=networks[0][i],
                           arg=networks[0][i],
                           icon="wifi_100.png")
        elif int(networks[1][i]) > -75:
            newItem = dict(title=networks[0][i],
                           subtitle="Signal strength " + networks[1][i],
                           autocomplete=networks[0][i],
                           arg=networks[0][i],
                           icon="wifi_66.png")
        else:
            newItem = dict(title=networks[0][i],
                           subtitle="Signal strength" + networks[1][i],
                           autocomplete=networks[0][i],
                           arg=networks[0][i],
                           icon="wifi_33.png")
        items.append(newItem)

    if query:
        items = wf.filter(query, items, key=search_key)


    # if not items:  # This is when there are no items, no data
    #     wf.add_item('no WiFi connections found',
    #                 icon=u"bummer_fax.jpeg")
    #     wf.send_feedback()
    #     return 0

    for item in items:
        wf.add_item(title=item["title"],
                    subtitle=item["subtitle"],
                    autocomplete=item['autocomplete'],
                    arg=item["arg"],
                    valid=True,
                    icon=item["icon"])

    wf.send_feedback()

if __name__ == u'__main__':
    wf = Workflow()
    sys.exit(wf.run(main))

 

Edited by TheDonk
Link to comment

What does Alfred's debugger/the log file say?

 

Could you upload the workflow somewhere? There aren't any obvious errors, and it's impossible to run the workflow, as you haven't provided the get_network.sh script.

 

FWIW, you're probably slowing down the script a lot by passing shell=True to subprocess.call().

Link to comment
Starting debug for 'Network Tool'

[2016-10-03 01:31:56][STDERR: input.scriptfilter] 01:31:56 workflow.py:2152 DEBUG    Workflow version : 1.0.0
01:31:56 workflow.py:1830 DEBUG    Cached data saved at : /Users/donk/Library/Caches/com.runningwithcrayons.Alfred-3/Workflow Data/com.alfredapp.donk.networktool/networks.cpickle
01:31:56 workflow.py:1564 DEBUG    Reading settings from `/Users/donk/Library/Application Support/Alfred 3/Workflow Data/com.alfredapp.donk.networktool/settings.json` ...
01:31:56 workflow.py:2346 DEBUG    Set last run version : 1.0.0
01:31:56 workflow.py:2190 DEBUG    Workflow finished in 0.036 seconds.
[2016-10-03 01:31:56][input.scriptfilter] <?xml version="1.0" encoding="utf-8"?>
<items><item valid="no"><title>no WiFi connections found</title><subtitle /><icon>bummer_fax.jpeg</icon></item></items>

This is the debugger from Alfred. It doesn´t run long enough - which means that the bash-script is not called for some reason. I got an export error as well trying to export it, which makes me think I made a mistake putting files where they shouldn´t be. However, that would be a more likely cause if it never ran.

 

I can upload the entire thing in a sec, after I sort out this export error

Link to comment

That isn't the same code you posted. You've commented out the bit that sends the bummer_fax.jpeg item in the code you posted.

 

Please be sure to post the actual code you're running.

 

EDIT: I'd also start looking at your get_network.sh script, or at least use subprocess.check_call() instead of subprocess.call(), so you get an error if it fails. The problem would probably be easier to track down if your code checked for errors.

Edited by deanishe
Link to comment

Right, good point sorry. It was the only difference though, and I have produced the problem either way.

 

https://www.dropbox.com/s/z8dovkdbpy6m8hp/WiFi_tool.alfredworkflow?dl=0

 

I had to copy-paste it into another workflow since I kept getting a "working directory doesn´t exist" error when I tried to export it. It still shows the same behaviour though, working most of the time - occasionally not

Link to comment
14 minutes ago, TheDonk said:

I kept getting a "working directory doesn´t exist" error

 

Is the workflow symlinked? Alfred 3 doesn't like that. It's a bug in the export function that should probably be reported.

 

I'll see if I can figure out what's going wrong in the morning. I don't have m-cli or WiFi on this machine.

Link to comment

I haven't been able to provoke any errors. I've rewritten the code a bit to include a bit of logging and throw errors (in your script, if the m-cli call fails, the error is ignored and networkScan.txt is empty).

 

What I did:

  1. Removed need for get_network.sh and networkScan.txt by calling /usr/local/bin/m directly
  2. Used subprocess.check_output(), which raises an exception if m-cli call fails
  3. Sorted networks by signal strength by default (unless there's a query)
  4. Made the loops a bit clearer (you can iterate directly over a list in Python without needing indices)
  5. Changed the parser to a regex (I was having a hard time following all the list and string slicing)
  6. Changed the script to use Unicode. I don't know if non-ASCII is allowed in SSIDs, but your code would throw an error if there were one

 

# -*- coding: utf-8 -*-

"""This populates the workflow with networks available for connection
using the tool "m-cli" or "Swiss Army Knife" command line tools.
"""

from __future__ import unicode_literals

from collections import namedtuple
from operator import attrgetter
import re
import sys
import subprocess
from workflow import Workflow

# Data model. WiFi network name and signal strength
Network = namedtuple('Network', ['ssid', 'rssi'])


find_network = re.compile(
    r"""\s*(.+)\s+               # SSID
    ([0-9A-F]{2}:?){6}\s+        # BSSID
    ([0-9-]+)\s+                 # RSSI
    ([0-9,+-]+)\s+               # Channel
    .+""",                       # Rest
    re.VERBOSE|re.I).match


def getNetwork():
    """This fetches a network scan using m-cli."""
    cmd = ['/usr/local/bin/m', 'wifi', 'scan']
    output = subprocess.check_output(cmd).decode('utf-8')
    log.debug('\n%s', output)

    networks = []
    for line in output.split('\n'):
        m = find_network(line)
        if m:
            net = Network(m.group(1), int(m.group(3)))
            log.info(net)
            networks.append(net)

    log.info('%d WiFi networks found', len(networks))
    # Sort by signal strength
    networks.sort(key=attrgetter('rssi'), reverse=True)
    return networks


def main(wf):
    """This function generates actionable items in Workflow."""
    query = None
    if len(wf.args):
        query = wf.args[0]

    networks = wf.cached_data('networks', getNetwork, max_age=30)

    if query:
        networks = wf.filter(query, networks, key=attrgetter('ssid'))

    if not networks:
        wf.add_item('No WiFi connections found',
                    icon='bummer_fax.jpeg')
        wf.send_feedback()
        return

    for net in networks:
        icon = 'wifi_33.png'
        if net.rssi > -55:
            icon = 'wifi_100.png'
        elif net.rssi > -75:
            icon = 'wifi_66.png'

        wf.add_item(net.ssid,
                    'Signal strength {:d}'.format(net.rssi),
                    arg=net.ssid, autocomplete=net.ssid,
                    icon=icon, valid=True)

    wf.send_feedback()


if __name__ == '__main__':
    wf = Workflow()
    log = wf.logger
    sys.exit(wf.run(main))

 

Edited by deanishe
Add code the stupid forum software removed
Link to comment
  • 2 weeks later...

After playing around with this for a while, I think I wrongly assumed this to be an Alfred problem.

 

The same bug is present from the command line directly, sometimes it just won't scan. Not sure why, could be just on my machine. The same persists when using the "airport" command as well.

 

So this one is closed I guess, sorry for the time wasting. It just didn't cross my mind that might be the error (since I didn't write it)

 

Anyways, thanks for the help!

Link to comment
11 hours ago, TheDonk said:

The same bug is present from the command line directly, sometimes it just won't scan. Not sure why, could be just on my machine. The same persists when using the "airport" command as well.

 

FWIW, m wifi is just a very thin wrapper around the airport command. If you plan to distribute the workflow, I'd advise dropping m-cli and using the OS X commands directly.

Link to comment
3 hours ago, deanishe said:

 

FWIW, m wifi is just a very thin wrapper around the airport command. If you plan to distribute the workflow, I'd advise dropping m-cli and using the OS X commands directly.

 

Thanks, I actually discovered this the other day when someone else published another workflow doing the same thing. This "m" was just the first google-result.

 

Anyways, I sadly think I wasted your time here. The bug is not in the Workflow, the same problem persist from the command line. Both with m and with airport. Sometimes it just won't scan. It could be my machine, not sure. It just didn't cross my mind that I didn't write the error, lesson learned.

 

On the upside, it is easy to work-around I think - by making the WF re-scan if the result and cache are empty.

 

I'll probably publish it, but I want to make it work with KeyChain first.

 

 

Link to comment

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...