[Tutor] I Give Up. - Follow up post

Brian Gustin brian at daviesinc.com
Tue Jul 4 22:49:11 CEST 2006



Danny Yoo wrote:
>> I tried it by opening a file , but could find no way to do variable 
>> variables
> 
> 
> 
> Hi Brian,
> 
> Look for the concept of dictionaries in Python.  "Variable variables" in 
> languages like PHP and Perl are doable in Python, but a dictionary 
> usually handles such situations in a safer way.

Yeah I am familiar with the concept , and it would work nicely for some 
applications, but I couldnt make it work the way I need it to for this 
application :)

Reason: It's more to do with the further functions in the application 
that I did not paste in the follow up :)

The issue, again is that I want to call a variable by *name* , but I do 
not *KNOW* what that variable's name is, exactly

For example, say I have apache running on port 80, apache-ssl on 443, 
apache2 on port 81, and Caudium on port 8080 (yes I do have a machine 
running not only those servers, but AOLServer, simultaneously)

If I want to configure a protocol to check, *for multiple machines*  I 
might do

(pseudo function)

Check_Host(machine,protocol,port,last_results)

Now, if I want to iterate over a list of machines , and check each 
machine for whatever it was set for (in the config file)

I cannot obviously have a config that says
(Protocol = Port)
http = 80
http = 81
http = 8080
smtp = 25

So the config file requires http to be the first part of the string , 
followed by something to make it unique (I.E. http1, http2, http3)

Now, if I pass each value in turn to check_host, how do I tell what type 
of check to make ? (Obviously if I want to get a string from a web page, 
I need to SEND a GET request, but if I am checking smtp, I cannot use 
that same function, SO.... )

I check for the base of the configuration (if http in protocol: then run 
http request, else something else)

so that I can run the correct request type on the correct port , and 
maintain a log, but I cannot do that as effectively if it is a 
dictionary or list or even a foreach ..

As I said, I have looked at this from every angle I could see, but using 
dictionary (which was my *first* choice) did not work the way I needed 
it to, nor did simply reading a file to get name value pairs  I needed 
the name to be an actual variable name..

believe me I have tried dictionaries, Ive tried parsing the file by 
other means, but the only way I could get results I needed was through 
configparser

> 
>> and then read it in as a file , which builds an array (AKA dictionary)
>> and then just assign thus:
>>
>> foreach ($filearray as $key => $value)
>> {
>>     $$key = $value
>> }

> 
> This is not safe in Python, because the $key given could easily be the 
> name of something that shouldn't be treated as configuration, such as 
> the built-in functions.  It also makes debugging a bit harder if we have 
> variables in a program that aren't explicitely named.
Yes, I am well aware of the dangers of  taking values unchecked into an 
array such as this method shows (simplified).. I rarely ever use it, or 
if I do, it is on *known* clean data (example, pulling config data out 
of a database , reading a .ini file, etc.. not untrusted user input)

I have seen people use this method to extract POST and GET data for 
example (untrusted user input) , which I find horrifying :)

> 
> The safe way to do this is to sandbox these variables in a dictionary. 
> Conceptually, the pseudocode looks like:
> 
> ################################
> config_options = {}
> for (name, value) in the file:
>     config_options[name] = value
> ################################
> 
> and the real code to do this doesn't look too much different.
> 
Yeah, basically you carry values in a dictionary named by keyname , 
but..  there have been situations where I need the key name as the 
variable name , I.E. config_options[name] = value could become

name = value as if it was explicitly defined that way

It's difficult to grasp or even effectively explain the concept or idea, 
but sometimes you need to KNOW the key name, *without* knowing the key 
name :)  (confused yet? hahaha)

> 
> 
> Let's look at some of the config-reading code:
> 
>>     if cfg.has_section("Parameters"):
>>         myparams = cfg.items("Parameters")
>>         for item in myparams:
>>             parameter[item[0]] = item[1]
>>     else:
>>         log_error("Parameters","not found")
>>     if cfg.has_section("Ports"):
>>         ports = cfg.items("Ports")
>>         for port in ports:
>>             watch_port[port[0]] = port[1]
>>     else:
>>         log_error("Ports","Not Found")
>>     if cfg.has_section("Hosts"):
>>         hostnames = cfg.items("Hosts")
>>         for hostname in hostnames:
>>             watch_hosts[hostname[0]] = hostname[1]
>>     else:
>>         log_error("Hosts","Not Found")
>>     if cfg.has_section("IP Addresses"):
>>         ips = cfg.items("IP Addresses")
>>         for ip in ips:
>>             watch_ips[ip[0]] = ip[1]
>>     else:
>>         log_error("IP Addresses","Not Found")
>>     if cfg.has_section("Alerts"):
>>         alerts_to = cfg.items("Alerts")
>>     else:
>>         log_error("Hosts","Not Found")
> 
> 
> 
> There's a lot of repetition here.  When we have the temptation to copy 
> and paste, try to see if a helper function can do some lifting.

Agreed. however I just set this as a preliminary - in no way is this 
code finished. :)  I actually intended to build a function to do this.
(In perl, I use Switch/Case statements, does Python have anything 
similar?  - with switch/case, you can set a final default "catch-all" at 
which point I log a "unknown event" message )

> 
> In fact, there's a bug there because of the copy-and-paste.  If there 
> are no Alerts, the system will spuriously blame Hosts.  I resent being 
> blamed for things I don't do, and I'm sure my programs feel the same.  
> *grin*

Yep. see above comment :-D
> 
> Here's a possible refactoring:
> 
> #########################################################
> def read_config_section(section_name, output_dictionary):
>     if cfg.has_section(section_name)
>         section = cfg.items(section_name)
>     else:
>         log_error(section_name, "Not Found")
>     for key_value in section:
>         output_dictionary[key_value[0]] = key_value[1]
> #########################################################
> 
> Once we have this, we can then do:
> 
>     read_config_section("Parameters", parameter)
>     read_config_section("Ports", watch_port)
>     ...
> 
> and eliminate a lot of that repetitive code.
> 
> 
> Does this make sense?  Feel free to ask more questions.

Yeah it makes sense,, a lot of what I posted here is just some 
preliminary stuff- related to the O.P. that I could not fnid sufficient 
documentation or examples of ConfigParser to get it to do what I needed, 
which is to set variable namespace according to defined config (ini) file

In php, I would make a .ini file and use parse_ini_file() function.

For the worknig perl monitoring script, I used Parse::RecDescent

Anyhow, the main point of this follow up is a basic example for the 
future if someone else runs into the same issues I did (Python's 
documentation is not well written at all, and difficult to use)




> 
> !DSPAM:44aac00477171290140515!
> 
> 


More information about the Tutor mailing list