getattr and method name

Steven D'Aprano steve+comp.lang.python at pearwood.info
Sun Oct 2 19:21:32 EDT 2011


On Sun, 02 Oct 2011 18:02:05 -0400, Kevin Walzer wrote:

> I'm seeing a very odd error in an application I'm developing using
> Python 2.7.2, on Mac OS 10.7.
> 
> This application uses a wrapper method to look up other method names via
> getattr and then call those methods. I have not previously had an issue
> with this name, but for some reason this functionality no longer works
> as expected.
> 
> Here is the relevant code:
> 
>      #run command with root privileges
>      def runCommand(self, cmd, *args):
>          try:
>              functionstring = args[2]
>              callfunction = getattr(self, functionstring.split('.')[1])
>              self.passtext = self.tk.call('authorize::getAuthPassword')
>              callfunction()
>          except:

Bare excepts should almost never be used. I'd say they certainly 
shouldn't be used like this: you can mask coding bugs, user 
KeyboardInterrupts, and other things which shouldn't be masked.

It also obscures the intent of the code. As far as I can see, it appears 
that this method expects to be called like this:

instance.runCommand(cmd, some, arbitrary, number, of, extra, args)

In this case, the method tries to authenticate and then execute some 
command based on "number" (but ignoring all other arguments, including 
cmd); if ANY failure occurs at all, including too few arguments, missing 
dot in the argument, or failed authentication(?), then try again using 
"cmd" instead. I don't understand the intent of this code.


>              try:
>                  print cmd
>                  functionstring = cmd.split()[2]
>                  callfunction = getattr(self, 
>                       functionstring.split('.')[1]) 
>                  self.passtext = self.tk.call(
>                      'authorize::getAuthPassword')
>                  callfunction()
>              except:
>                  raise

This try block is completely unnecessary. What's the point of catching an 
exception only to immediately raise it again?



> I use this approach to call the method named in the "cmd" parameter
> because I also have to look up a password name that is returned by an
> underlying Tk package that I use in my application (that's the reason
> for the 'self.tk.call'). 

What's a password name? Generally passwords don't have names themselves. 
Do you mean a user or account name?


> What is happening is when I use the
> "callfunction()" call, instead of the method name being called, a string
> like this is being invoked:
> 
> <bound method phynchronicityApp.scanPackages of
> <__main__.phynchronicityApp instance at 0x101b232d8>>


Are you sure that's meant to be a string? It appears to be an actual 
bound method. What makes you think it is a string? Where is that output 
coming from? 

My *guess* is that this is the output of the "print cmd" line. If so, 
that tells you nothing about the type of cmd. It does however tell you 
that you need to look at what is calling the runCommand method. Why is it 
being called with a method as the command? What should it be called with? 
Given that you call cmd.split()[2], I would expect that cmd should be a 
string with at least three words.

Taking a wild guess, perhaps you should call cmd to get a string which 
then gets split into pieces to get the name of the system tool you are 
expecting:

 
> The "scanPackages" method (just to use it as an example) uses Popen to
> call an underlying system tool on the OS. However, when invoked via
> callfunction(), the 'bound method...' string is passed to the OS instead
> as a command! As a result, I get this output from the pipe:
> 
> /bin/sh: bound: No such file or directory


Or possibly the error is in callfunction. What does it do?

 
> I am not sure what in my application is causing this kind of breakage,
> as earlier versions of the app ran fine with similar code on earlier
> versions on the OS. Is this the correct way to structure this kind of
> functionality, or am I better off structuring it some other way?

Frankly, it looks like a mess. But I don't understand your intention well 
enough to make any recommendations.



-- 
Steven



More information about the Python-list mailing list