0

I'm running into a problem with the following Python 3.2.2 code. The code is an attempt to do some timing tests of another application I'm testing. The idea is to have another script (of any variety) get passed into the timer program and make some changes to the environment. That script should run in a separate thread, so that I can start timing from the start of the script instead of the end. The rest of this script times the application's reaction to that script. I've attempted to draw from the threading module documentation to create this, and I'm confident that I've read it thoroughly, but I'm consistently running into the following error using this code:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "C:\Python32\lib\threading.py", line 669, in start
    if not self._initialized:
AttributeError: 'str' object has no attribute '_initialized'

Here's the thread class definition.

import threading, ...

class AsyncScript(threading.Thread):
    def __init__(self, s):
        self.script = s
    def run(self):
        print ("Beginning script...")
        try:
            os.system("cmd /k " + self.script)
        except:
            sys.exit("Error running script " + self.script)

This is called elsewhere in the script by AsyncScript.start(options.script), where the options class contains the options passed into the script (using the argparse module.)

Any ideas about what I might be doing wrong here?


Okay, an update. The following (stripped-down) version of the code DOES work, and I'm honestly not sure why -- I don't see the difference.

import threading

class AsyncScript(threading.Thread):
    def __init__(self, s):
        threading.Thread.__init__(self)
        self.script = s
    def run(self):
        print("This would run script " + self.script)

AsyncScript("sample script path string").start()

Output is, appropriately,

This would run script sample script path string

Aside from the inclusion of threading.Thread.__init__(self), which I had previously included in earlier versions of this code without success, I'm not really sure what's different here. What am I missing?

2
  • 2
    Side note: Never use a bare except. It masks genius bugs and catches some things that aren't errors and probably shouldn't be caught at all. There's almost always a more specific exception to catch. Commented Nov 7, 2011 at 19:53
  • Good advice (and a great link!). This is supposed to be pretty simple code, so I'm not too worried about it in this case, but that's definitely a good habit to get into. Commented Nov 7, 2011 at 20:31

3 Answers 3

1

This is called elsewhere in the script by AsyncScript.start(options.script)

That invokation is wrong. You're calling threading.Thread's nullary (no arguments - not counting self) start method with your script string as self, instead of instanciating your AsyncScript class (passing the string to __init__) and calling the resulting thread object's .start() method. Obviously, a string is not a thread, so the threading code fails when you give it one as self. It should probably be AsyncScript(options.script).start()

Sign up to request clarification or add additional context in comments.

4 Comments

Just tried calling it with AsyncScript(options.script).start(). I now get AttributeError: 'AsyncScript' object has no attribute '_initialized'
@Kudzu: Ah, you're also missing the call to the parent class __init__. Use super().__init__() (add arguments if you need any, though you override run anyway) or Thread.__init__(self).
Adding super().__init__() as the first line of the overridden __init__ method might have worked. I'm now getting a different error: assert group is None, "group argument must be None for now" / AssertionError: group argument must be None for now This looks like an error in overriding threading.Thread (see link ) but I'm not certain how to do it correctly.
@Kudzu: I can neither understand nor reproduce that error. Are you sure there are no arguments to the super().__init__() call?
0

You don't need to use threads if you run the script in a separate process anyway. Use subprocess instead of os.system().

You don't need to subclass Thread to create a thread:

Thread(target=func, args=func_args).start()

I'm not really sure what's different here. What am I missing?

There are two differences:

  1. AsyncScript.start(options.script) vs. AsyncScript(options.script).start().

    AsyncScript is a class object. AsyncScript(options.script) is an instance of that class.

    AsyncScript.start(options.script) calls an unbound .start method. It expects its first argument to be an AsyncScript instance not a string options.script. The correct way to call a method is obj.method(). In your case obj = AsyncScript(options.script).

  2. Presense of threading.Thread.__init__(self) in the AsyncScript.__init__() method.

    If you don't call threading.Thread.__init__(self) then Thread's attributes such as _initialized are not created/defined.

1 Comment

Passing the function to threading.Thread() makes a lot more sense to me. That should do it -- thanks very much!
0

self.script isn't initialize in your , but you've got self.s - try to use it

1 Comment

Sorry -- I was attempting to do some last-minute edits of the code to make it clearer here, and ended up missing last line. It's slightly better now.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.