Forums

unhandled exception, cant find similarly detailed issue.

I have my app uploaded to PA thru dropbox, and seem to have editted the wsgi file correctly, wherein it locates and recognizes the file, but when i try to open the app thru my webapp webpage it says unhandled exception. In my errorlog, this is what im told:

2012-09-09 19:16:45,569 :Traceback (most recent call last): 2012-09-09 19:16:45,572 : File "/var/www/wsgi.py", line 16 2012-09-09 19:16:45,572 : from KoC AR.py import app as application 2012-09-09 19:16:45,572 : ^ 2012-09-09 19:16:45,572 :SyntaxError: invalid syntax As this is the direct reason i got a PA subscription, does me no good if it wont work lol. anyone possibly help me resolve this issue, or at least weather or not it can be resolved? thx much

Syntax error? Sounds unusual. There are lots of Pythonistas on this board willing to help, so why don't you post the code and I (plus a2j and any of the developers who are watching) can have a look at it.

If you open a bash console you'll find a tool called pyflakes installed, which is quite helpful in tracking down syntax errors. If you just run pyflakes source.py on a Python file it'll generally give you a good hint where the problem lies.

If you're having trouble seeing why the syntax it finds is invalid, I'm sure someone here can help you.

Actually, I probably should have just read that stack trace more carefully. I just spotted what appears to be the following line of code:

from KoC AR.py import app as application

Python isn't going to like that. Firstly, you don't need to (and should not) add the .py extension when importing modules, it's implicitly added by Python. Secondly, it appears your module name has a space in it. Could you check this line of code and fix it? It's located on line 16 of your wsgi.py file.

For future reference, when you paste in a backtrace or log file then go and insert 4 spaces at the start of each line and it'll appear nicely formatted like this:

2012-09-09 19:16:45,569 :Traceback (most recent call last):
2012-09-09 19:16:45,572 : File "/var/www/wsgi.py", line 16
2012-09-09 19:16:45,572 : from KoC AR.py import app as application
2012-09-09 19:16:45,572 : ^
2012-09-09 19:16:45,572 :SyntaxError: invalid syntax

As you can see, the issue is much clearer when presented in this manner.

Thanks Cartroo,

havok, has that sorted out the problem? Remember also that PythonAnywhere is running on Linux so is case sensitive. Watch this when adding the correct directory to your sys.path.

@havok: Welcome to PA. Hey, do the letters SGW mean anything to you? If so, you probably recognize a2j as well...☺

@all: A wife asks her husband, a software engineer: "Could you please go shopping for me and buy one carton of milk, and if they have eggs, get 6!" A short time later the husband comes back with 6 cartons of milk. The wife asks him, "Why the hell did you buy 6 cartons of milk?" He replied, "They had eggs."

sorry about the delayed response, have been busy. @ first response, im not sure how to use pyflakes, bash gives me command window, but im not sure how to run pyflakes on the .py file. @ #2, ive changed the name of the module to one with no spaces. As, I'm not very knowledgeable in coding in general, I'm still unsure what web framework i should use, but when i use Flask it tells me the file needs the .py, but either way, i still havent gotten it to run on the personal webpage, only in console. Here is the script im trying to run, hopefully it copies and pastes better than my errorlog did.

import time
import datetime
import urllib2
import cookielib
import os
import sys
import socket
import threading
socket.setdefaulttimeout(10.0)

cj = cookielib.CookieJar()
opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cj))
opener.addheaders = [('User-agent', 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:13.0) Gecko/20100101 Firefox/13.0.1  ID:20120614114901')]


GOD_CHECK_TIME = 1 # The speed at which it rechecks for a raid in the room

FORMER_ID = "141528" #jafo    
CAST_SIN = False   # True or False to cast a SiN
SIN_ID = "79472"        # Optional if you set CAST_SIN to True

chars = ([ "128722", "5806", "19231", "16720" ])


LOGIN_WITH_SESSION = False # Change to True to log in with session
                          # or False to use the stored user/pass

rg_sess_id = ""
server = "quiver"
username = ""
password = ""


#global editables, dont touch these
if server.lower() == "sigil":
    SERVER_ID = "1"
elif server.lower() == "torax":
    SERVER_ID = "2"
elif server.lower() == "fabar":
    SERVER_ID = "3"
elif server.lower() == "zimbob":
    SERVER_ID = "4"
elif server.lower() == "rancid":
    SERVER_ID = "5"
elif server.lower() == "quiver":
    SERVER_ID = "6"
else:
    SERVER_ID = "1"

RAID_ID = ""
RAID_NAME = ""
_startTime = datetime.datetime.now()
_finishTime = datetime.datetime.now()

#anti-lag-opener
def alo(url):
    lagsafe = 1
    while lagsafe == 1:
        try:
            site = opener.open(url)
            lagsafe = 0
        except IOError:
            print "URLError: Site not loading. Retrying..."
        except Exception:
            print "Unknown error, retrying..."
    return site

def alo2(url, pData):
    lagsafe = 1
    while lagsafe == 1:
        try:
            site = opener.open(url, pData)
            lagsafe = 0
        except IOError:
            print "URLError: Site not loading. Retrying..."
        except Exception:
            print "Unknown error, retrying..."
    return site


# Print a message with timestamp
def msg(out):
    thetime = time.strftime("[%H:%M:%S]", time.localtime(time.time()))
    message = thetime + " " + out
    print message
    return message


def getCharName(src):
    charName = "Unknown"
    try:
        charName = src.split('" selected>')[1].split('</option>')[0]
    except:
        msg("Could not retrieve character name.")

    return charName

def iB(src, start, end):
    try:
        return src.split(start)[1].split(end)[0]
    except IndexError:
        msg("Could not retrieve the inbetween value.")
        return

def formRaid(formerID):
    one = 1
    while one == 1:
        try:
            global _startTime
            _startTime = datetime.datetime.now()
            srcworld = alo("http://"+server+".outwar.com/ajax_changeroomb.php?suid=" + formerID + '&serverid='+SERVER_ID).read()

            if "raidicondead.png" in srcworld:
                #print "***God not Spawned."
                time.sleep(GOD_CHECK_TIME)

            else:

                raidLink = srcworld.split("formraid.php?target=")[1].split('\\">')[0]
                print ""
                msg("***Raid spotted, forming raid.")
                formpage = alo("http://"+server+".outwar.com/formraid.php?target=" + raidLink).read()
                codeID = formpage.split('codeid" value="')[1].split('">')[0]
                Form = alo2("http://"+server+".outwar.com/formraid.php?target=" + raidLink, "target=" + raidLink + "&codeid=" + codeID + "&formtime=3&submit=Launch!").read()
                global RAID_ID, RAID_NAME
                RAID_ID = getRaidID(Form)
                RAID_NAME = getRaidName(Form)
                msg("***" + RAID_NAME + " Formed.")
                one = 0
                return True
        except IndexError:
            #msg("God not spawned.")
            time.sleep(GOD_CHECK_TIME)


def getRaidID(src):
    #raids = alo("http://quiver.outwar.com/crew_raidsforming.php")
    #srcraids = raids.read()
    try:
        return iB(src, "joinraid.php?raidid=", "&")
    except IndexError:
        msg("Couldn't retrieve raid ID")
        return False

def getRaidName(src):
    try:
        return iB(src, "<div ONMOUSEOVER=\"statspopup(event,'<b>", "</b>')\" ONMOUSEOUT=\"kill()\">")
    except IndexError:
        msg("Couldn't retrieve raid name")
        return False

def launchRaid(launchURL):
    x = 1
    while x == 1:
        try:
            launch = alo(launchURL).read()
            if "Your raid will launch shortly" in launch:
                msg("RAID LAUNCHED!")
                global _finishTime
                _finishTime = datetime.datetime.now()
                x = 1
                return True
        except IndexError:
            x = 0
            time.sleep(1)

def createReport(raidTime):
    r = open("numero.txt", "a")
    r.write("Raid launched at " + time.strftime("[%H:%M:%S]", time.localtime(time.time())) + " \nThe raid took "+str(raidTime.seconds)+" seconds.")
    r.close()
    return True


if LOGIN_WITH_SESSION:
    loginrpg = alo("http://"+server+".outwar.com/myaccount.php?rg_sess_id=" + rg_sess_id + "&serverid="+SERVER_ID+"&suid=" + FORMER_ID)
    print "Logged in with Session ID Quiver Main\n"
else:
    loginrpg = alo2("http://"+server+".outwar.com/myaccount.php", "login_username="+username+"&login_password="+password)
    loginchar = alo("http://"+server+".outwar.com/world.php?suid="+FORMER_ID+"&serverid="+SERVER_ID)
    print "Logged in with Log in\n"


# God name was found on the page, so form and join the raid.
formRaid(FORMER_ID)

# Start to join
#for i in range(len(chars)):
#    join = alo2('http://quiver.outwar.com/joinraid.php?raidid=' + RAID_ID + '&suid=' + chars[i] + '&serverid=6', "join=1").read()
#    msg("Joined character: " + getCharName(join))

class ThreadClass(threading.Thread):
    def __init__(self, char):
        self.char = char
        threading.Thread.__init__(self)

    def run(self):
        join = alo2('http://quiver.outwar.com/joinraid.php?raidid='+RAID_ID+'&suid='+self.char+'&serverid=6', "join=1").read()
        if "error" in join:
            x = 1
            while x == 1:
               join = alo2('http://quiver.outwar.com/joinraid.php?raidid='+RAID_ID+'&suid='+self.char+'&serverid=6', "join=1").read()
               if "Please click" in join:
                   x = 0

        time.sleep(0.2)
        msg("Joined character: " + getCharName(join))


for i in range(len(chars)):
  t = ThreadClass(chars[i])
  t.start()

# Cast SiN
if CAST_SIN == True:
    cast = alo2("http://quiver.outwar.com/cast_skills.php?C=5", "suid="+SIN_ID+"&castskillid=3015&cast=Cast+Skill")
    msg("Casted Strength in Numbers on " + getCharName(cast))


launchURL = 'http://quiver.outwar.com/joinraid.php?raidid=' + RAID_ID + '&suid=' + FORMER_ID + '&serverid=6&launchraid=yes&x=141&y=36'
launchRaid(launchURL)
tTime = _finishTime - _startTime
msg("TOTAL RAID TIME: " + str(tTime.seconds) + " seconds.\n")
keepChecking = 0

OK, finally got it posted in such a way as it can be easily read, thanks in advance for the help

So, I'm not quite sure what you're trying to do here, I'm afraid, but this doesn't look like a WSGI app to me. Are you trying to run this as a webserver and access it in your browser? If so, I'm afraid this code just isn't written like that.

From a very cursory (literally 60 seconds) glance, it appears that this script is designed to connect to some sort of online game and perform some actions on it. When run it creates four threads, one for each of those random looking numbers in the "chars" list (perhaps they're some sort of user IDs?). Each of these threads performs a GET on some URLs, and then terminates. The script itself will terminate once all the threads have done so (and the main thread performs some sort of request itself).

From what I can tell this is just an on-demand script, it's not designed to run in the background or be a web-facing application. Perhaps if you can give us more details of what you're trying to do, and what you're expecting to happen, we could help.

However, you do want to be careful that whatever this script is doing it's not making too many requests on this quiver.outwar.com server, because otherwise it may irritate their admins no end.

you basically summed up the objective of it, they are character IDs, and lol if the admins were going to do something about it they wouldve done something, as there arent many who play that dont use this or some variation of it. It runs thru python fine off my desktop, idles while it watches for a trigger, i was attempting to run it through a host, can i not do that with this script here?

That looks much more like something that's supposed to be run off a command line. Also, it seems to be accessing outwar.com. I had a quick look at their TOS and using a script is forbidden, so you may want to be careful - they even threaten criminal liability, but I don't think that's a very credible threat.

yeah, unfortantely the admins dont enforce it. Actually, it was the admins who opted to remove captchas when u join a character, the one thing still holding them at bay. but oh well. I do run it on the py command line. So it wont work on here?

If it works for you from the command line why don't you adapt it to run from the Schedule tab?

what exactly would i need to adapt to make it work, and will it idle as a schedule?

You shouldn't need to adapt it at all, although I'm not sure what happens to standard output (i.e. the printed output) when you run it on a schedule.

Basically you just go to the Dashboard, then to the Schedule tab and add the path to the script you want to run and the time at which you want to run it.

I can't think of any reason why it wouldn't idle from the schedule tab, but as written you'll end up forking off endless copies because it never seems to terminate on its own. To prevent that, you need some sort of lock which other invocations of the script can use to decide to terminate immediately (instead of running multiple instances endlessly). Because of the distributed nature of PA this is slightly tricky - you can use simple file locking (with some caveats I'll discuss below). This is a quick and dirty example (the use of atexit is particularly ugly, but this is just off the top of my head):

import atexit
lock_file_path = os.path.expanduser("~/my_lock_file")
try:
    fd = os.open(lock_file_path, os.O_WRONLY | os.O_CREAT | os.O_EXCL)
    os.close(fd)
except OSError:
    # The script is already running (or some other error)
    sys.exit()
atexit.register(os.remove, lock_file_path)

This should ensure only a single copy ever runs at a time, but has the issue that if the script is terminated by a signal (i.e. ungracefully) then the lock file will remain and you'll need to manually remove it via your bash shell or the Files tab in the dashboard.

You should also probably at least limit the time for which this script can run - I haven't got time to show you how to do this right now, but it's quite simple. I'm sure that the PA staff might not be keen on scheduled scripts which run forever, but obviously that's for them to say and not me (I'm just saying bear it in mind).

I'm also not sure if they'll be keen on running a script which breaks the ToS of another site, but having said it's not running any faster than it could on a home desktop machine, so I guess they've got a pretty solid safe harbour defence.

Hi havok,

We're probably not going to be able to help you to write scripts that violate other sites' terms of service. Especially when it is brought to our attention. It's not like we could now credibly claim ignorance. These are public forums after all.

This is the reason that we were forced to restrict free users to a whitelist of internet sites.

To clarify our position. If a user was to engage in criminal behaviour, i.e a denial of service attack against another site, then we would immediately disable that account.

If a user is violating the TOS of another site, and we became aware of it, then we would have to monitor the situation and have a discussion with them. If the admins of the site affected contact us to complain then we would immediately disable the account responsible.

This doesn't mean we want to get involved in making case by case decisions on what is and is not a violation of another sites TOS. It isn't up to us to morally police the internet. But complaints from other sites will be taken seriously.

@hansel: On the more general issue of background-running scripts, though, it might be worth having a think whether that's something to encourage / discourage / don't care on the site. I'm not sure if it's worth implementing a generic wrapper around all scheduled tasks for a specific user to ensure that only one can be executing at a time or something.

Anyway, either way, I'm guessing in an environment like this which makes it really convenient to execute scripts without being a proper sys admin, this sort of thing is going to come up from time to time.

Absolutely, we do have clean up procedures for badly behaved scheduled tasks. Ultimately we want the platform to be easy to use and as open ended as possible.

Please correct any of this that is misunderstood (or just plain wrong):

  • PA staff won't assist in writing a script that knowingly violates a sites TOS.
  • Other users are welcome to assist in writing said script.
  • PA staff won't prevent a script that violates another sites TOS unless the site in question complains.
  • Scheduled tasks shouldn't be configured to run forever, but if a user configures a way to keep it controlled then they are welcomed to keep it running permanently.

TIA for any corrections/feedback.

@havok: I'd just read the current time into a variable at the start of the script and then periodically check for the time difference then quit when you get to the time for the next schedule to spawn.

PA staff won't assist in writing a script that knowingly violates a sites TOS.

That's right. If we know it's a script to do something naughty, we won't help.

Other users are welcome to assist in writing said script.

Well, we don't want to police the forums and restrict what people can discuss, at least beyond obvious nasty stuff (spam, threats of violence, "hate speech", etc). So if people want to help each other with coding problems then we won't be judgmental or try to shut the conversation down.

PA staff won't prevent a script that violates another sites TOS unless the site in question complains.

We're still discussing that internally, so no definitive answer on that yet. Generally, if we're not aware of the script (so, for example, it hasn't been discussed on the forums cough cough and isn't doing something on our servers that our monitoring picks up -- for example, burning bandwidth by running a DoS) then what we don't know about we can't block. We're not going to put in place stuff to specifically actively look for people using our service to do Bad Things, not least because there are lots of Perfectly OK Things that people could do that might look like Bad Things.

But there's a fine distinction here. Whatever happens, if we learn that someone's using PythonAnywhere to do something illegal then we will shut it down -- if we didn't then we'd be exposing ourselves to liability. A breach of a site's ToS is a different matter.

It's worth noting that our Terms and Conditions #include the AWS Acceptable Use Policy. We think that the limitations that they set out there -- basically, "nothing illegal", "no hacking", "no network abuse", and "no spamming" are pretty reasonable. And TBH we transitively have to enforce them anyway.

Hope that's a bit clearer.

Scheduled tasks shouldn't be configured to run forever, but if a user configures a way to keep it controlled then they are welcomed to keep it running permanently.

That's the case right now, but it might change. We're considering implementing something that would make old instances of a scheduled task die when the next one was kicked off, so that there's no chance of having hundreds of processes piling up.

In general, a good way to have a constantly-running task is to have a scheduled task that checks to see whether it's already running, and kicks it off in the background if it's not, perhaps by checking for the existence of a file. Cartroo has made some good suggestions about how to do that on various forum posts before.

Thank-you for the clarifications! I just love the transparency we get here @ PA!!