Take the 2-minute tour ×
Stack Overflow is a question and answer site for professional and enthusiast programmers. It's 100% free, no registration required.

I have come to my wits end with this one.

So I created a script that captures data from the operating system, inserts it into a dictionary. The next step should be for that data to be inserted into a postgres database. However I am getting the following error when the for loop is executed that loops through the data.

/usr/bin/python2.7 /home/gmastrokostas/PycharmProjects/learning/Violent_Python.py Traceback (most recent call last): File "/home/gmastrokostas/PycharmProjects/learning/Violent_Python.py", line 52, in for db_loop in eval(server_info): TypeError: eval() arg 1 must be a string or code object

Below is the postgres table script and also the python script it self. The name of the table is SERVERS and the columns are "hostname", "OS", "RAM", "CPU".

SQL SCRIPT TO CREATE THE TABLE - PostgreSQL 9.4

CREATE TABLE servers
(
  hostname character varying(50),
  "OS" character varying(25),
  "RAM" numeric(4,2),
  "CPU" character varying(50)
)
WITH (
  OIDS=FALSE
);
ALTER TABLE servers
  OWNER TO dbuser;

PYTHON SCRIPT

#!/usr/bin/python
import psutil
import os
import math
import platform
import subprocess
import socket
import psycopg2
from decimal import *

#Used by the convert values function.
factor = 1024

def Host_name():
    hostname = socket.gethostname()
    return hostname

def OS_make():
    #CPU INFORMATION.
    #cpu_version = platform.dist()[0]+" "+platform.dist()[1]
    cpu_version = platform.dist()[0]
    return  cpu_version

def Virtual_memory_usage():
    cvr_info = psutil.virtual_memory().total
    return round(cvr_info, 2)

def convert_values():
    cvr_info = Virtual_memory_usage()
    i = int(math.log(cvr_info)/math.log(factor))
    result = float(cvr_info)/factor**i
    return result

def get_processor_info():
    if platform.system() == "Windows":
        return platform.processor()
    elif platform.system() == "Darwin":
        return subprocess.check_output(['/usr/sbin/sysctl', "-n", "machdep.cpu.brand_string"]).strip()
    elif platform.system() == "Linux":
        command = "cat /proc/cpuinfo | grep 'model name' | head -1 | awk -F: '{print $2}'"
        return subprocess.check_output(command, shell=True).strip()
    return ""

#Adjusting precision and then appending to list information taken from Virtual_memory_usage function
mem_frmt =   "{0:.2f}".format(convert_values())

server_info = {'hostname': Host_name(), 'OS':OS_make(), 'RAM':mem_frmt, 'CPU':get_processor_info()}

conn = psycopg2.connect("host='10.0.0.41' dbname='serverinfo' user='dbuser'")
cur = conn.cursor()
for db_loop in eval(server_info):
  print db_loop #For testing
  cur.execute("""INSERT INTO servers(hostname,OS,RAM,CPU) VALUES('%s','%s','%s','%s')""" % \
        (db_loop['hostname'], db_loop['OS'], db_loop['RAM'], db_loop['CPU'])

  #FOR TESTING BUT IT DOES NOT WORK EITHER
  #cur.execute("""INSERT INTO servers(hostname) VALUES('%s')""" % \
  #      (db_loop['hostname'])
  )

conn.commit()
share|improve this question

2 Answers 2

The issue is that you are trying to eval a dictionary. The eval function compiles code - ie a string. I'm not sure what your intention was with using eval there.

The good news is that you don't need to invoke eval. And even better news is that I don't see you need a loop at all.

You have constructed a dictionary of named data to insert. All you need to do is open the connection, get a cursor and insert the server_info data, similar to what you're doing with the db_loop line.

share|improve this answer
    
Andrew great tip and I did just that by getting rid of the loop and by having it do the following: cur.execute("INSERT INTO servers(hostname,OS,RAM,CPU) VALUES('%s','%s','%s','%s')" % (Host_name(), OS_make(), mem_frmt, get_processor_info())) Thank you for the great pointers. –  George Mastrokostas Jan 6 at 0:21

The are multiple errors in your code. First of all you want to insert a single row of data (server_info) so you don't need the loop. Also the call to eval() doesn't make any sense because that function is used to evaluate Python code in a string and you're passing it a dictionary as argument.

Then, you should not quote the SQL parameters yourself (e.g., use "%s" and not "'%s'").

And finally, given that you already have the data in a dictionary, use that to provide bound variables to the execute() method.

I would write the code as follows:

server_info = {'hostname': Host_name(), 'OS':OS_make(), 'RAM':mem_frmt, 'CPU':get_processor_info()}

conn = psycopg2.connect("host='10.0.0.41' dbname='serverinfo' user='dbuser'")
curs = conn.cursor()

curs.execute("""INSERT INTO servers (hostname,OS,RAM,CPU) VALUES (%(hostname)s,%(OS)s,%(RAM)s,%(CPU)s)""", server_info)

conn.commit()
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.