Question

I'm unsure again with something what I'm sure is going to be very simple...

Basically, I'm trying to make my first script call/execute a bunch of other scripts but the problem is I want each individual script to contain its own functions not be called from the first secript...

First script/main script:

from datetime import date, timedelta
from sched import scheduler
from time import time, sleep, strftime
import random

s = scheduler(time, sleep)
random.seed()

def periodically(runtime, intsmall, intlarge, function):
     ## Get current time
    currenttime = strftime('%H:%M:%S')

    ## If currenttime is anywhere between 23:40 and 23:50 then...
    if currenttime > '23:40:00' and currenttime < '23:50:00':
        ## Call clear
        clear()
        ## Update time
        currenttime = strftime('%H:%M:%S')

    ## Idle time
    while currenttime > '23:40:00' and currenttime < '23:59:59' or currenttime >= '00:00:00' and currenttime < '01:30:00':
        ## Update time
        currenttime = strftime('%H:%M:%S')

    runtime += random.randrange(intsmall, intlarge)
    s.enter(runtime, 1, function, ())
    s.run()

def callscripts():
    print "Calling Functions"

    errors = open('ERROR(S).txt', 'a')
    try: 
        execfile("data/secondary.py")
    except Exception as e:
        errors.write(str(e))
        errors.write("""
""")         
    errors.close()


while True:
    periodically(2, -1, +1, callscripts)

Below is secondary.py

import win32con
from win32api import *
from win32gui import *

class WindowsBalloonTip:
    def __init__(self, title, msg):
        message_map = { win32con.WM_DESTROY: self.OnDestroy,}

        # Register the window class.
        wc = WNDCLASS()
        hinst = wc.hInstance = GetModuleHandle(None)
        wc.lpszClassName = 'PythonTaskbar'
        wc.lpfnWndProc = message_map # could also specify a wndproc.
        classAtom = RegisterClass(wc)

        # Create the window.
        style = win32con.WS_OVERLAPPED | win32con.WS_SYSMENU
        self.hwnd = CreateWindow(classAtom, "Taskbar", style, 0, 0, win32con.CW_USEDEFAULT, win32con.CW_USEDEFAULT, 0, 0, hinst, None)
        UpdateWindow(self.hwnd)

        # Icons managment
        iconPathName = "icon1.ico" ## LOCATION TO THE ICON FILE
        icon_flags = win32con.LR_LOADFROMFILE | win32con.LR_DEFAULTSIZE
        try:
            hicon = LoadImage(hinst, iconPathName, win32con.IMAGE_ICON, 0, 0, icon_flags)
        except:
            hicon = LoadIcon(0, win32con.IDI_APPLICATION)
        flags = NIF_ICON | NIF_MESSAGE | NIF_TIP
        nid = (self.hwnd, 0, flags, win32con.WM_USER+20, hicon, 'Tooltip')

        # Notify
        Shell_NotifyIcon(NIM_ADD, nid)
        Shell_NotifyIcon(NIM_MODIFY, (self.hwnd, 0, NIF_INFO, win32con.WM_USER+20, hicon, 'Balloon Tooltip', msg, 200, title))
        # self.show_balloon(title, msg)
        sleep(5)

        # Destroy
        DestroyWindow(self.hwnd)
        classAtom = UnregisterClass(classAtom, hinst)
    def OnDestroy(self, hwnd, msg, wparam, lparam):
        nid = (self.hwnd, 0)
        Shell_NotifyIcon(NIM_DELETE, nid)
        PostQuitMessage(0) # Terminate the app.

# Function
def balloon_tip(title, msg):
    w=WindowsBalloonTip(title, msg)


balloon_tip("test test", "Running")

def hi():
    print "hi"

hi()

Error:

global name 'WindowsBalloonTip' is not defined

Full Error:

Traceback (most recent call last):
  File "C:\Main.py", line 48, in <module>
    periodically(2, -1, +1, callscripts)
  File "C:\Main.py", line 27, in periodically
    s.run()
  File "C:\Python27\lib\sched.py", line 117, in run
    action(*argument)
  File "Main.py", line 34, in callscripts
    execfile("data/secondary.py")
  File "data/secondary.py", line 93, in <module>
    balloon_tip("test test", "Running")
  File "data/secondary.py", line 78, in balloon_tip
    w=WindowsBalloonTip(title, msg)
NameError: global name 'WindowsBalloonTip' is not defined

How would I go about fixing this?

Thanks in advance Hyflex

Was it helpful?

Solution

First of all,

class WindowsBalloonTip:

should be

class WindowsBalloonTip(object):

because the former is an old style class, which has disappeared in Python 3 and is in recent versions of Python 2.x only for backwards compatibility.

Ethan's answer is correct, but probably unclear to you if you're asking this question. A full explanation is here.

When ballon_tip() is run, it first searches the local namespace -- balloon_tip()'s namespace -- for something called WindowsBalloonTip. When it can't find it, it searches the global namespace. Since you didn't provide anything to the globals parameter to execfile(), it defaults to the namespace of callscripts(), which doesn't have anything named WindowsBaloonTip inside of it, and errors.

To fix this, you can pass globals() as an argument to execfile, but this will pollute the global namespace of your main script, which you probably don't want. You can also declare everything inside of secondary.py to be global, but you probably don't want to do that since the whole point is to test secondary.py.

The issue is execfile. execfile is an ugly, hack-y way to do things. import is better. One solution would be to write something like this inside secondary.py:

def test_harness():
    balloon_tip("test test", "Running")
    hi()

then, import secondary, traceback inside your main script, and change callscripts() like this:

def callscripts():
        print "Calling Functions"
        errors = open("ERRORS(S).txt", "a")

        try:
            secondary.test_harness()
        except:
            errors.write(traceback.format_exc() + '\n')

EDIT in response to comment: At the top of your script, import traceback, then:

def callscripts():
        print "Calling Functions"
        errors = open("ERRORS(S).txt", "a")

        try:
            execfile("data/secondary.py", {})
        except:
            errors.write(traceback.format_exc() + '\n')

OTHER TIPS

The problem is execfile.

Basically, execfile is a fancy exec with a file. So when you call execfile 'secondary.py' Python executes all the lines of secondary.py in the context of where execfile was called. Which, in this case, is inside the callscripts function.

What you probably want is subprocess.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top