[Zope] Returning a list of dictionaries from an external method yields "Loop over non-sequence" when tested
Thomas Weholt
t-weh@online.no
Tue, 9 Jul 2002 01:03:36 +0200
This is a multi-part message in MIME format.
------=_NextPart_000_004B_01C226E4.742A3F80
Content-Type: text/plain;
charset="iso-8859-1"
Content-Transfer-Encoding: quoted-printable
I've got a simple external method that returns a list containing =
dictionaries. If I run it from python it works fine, imported and used =
in Zope it raises an exception "Loop over non-sequence".
The script extracts some data from a table, containing the results from =
a parsed logfile, created by the game Counter-strike ( if you're =
interested ). I'm no expert in SQL ( as the code below probably shows )
but doing it in Python is no match ( even if the code is verbose and =
perhaps a bit inefficient. Tips and clues are appreciated if you can =
make anything out of it ).=20
I import the method in Zope, calling it PlayerStats, from the module =
CSPlayerStats. The file itself is the Extensions-folder under the Zope =
main-folder. Try to test it in the ZMI and the error pops up. Thought of =
using it like so :
<dtml-in PlayerStats>
<dtml-let item=3Dsequence-item>
<dtml-var "item['player']"><!-- more fields from the dictionary, =
here represented as item --><br>
</dtml-let>
</dtml-in>
The external method :
import MySQLdb
SQL_PLAYER_INFO =3D """
select
cs_attacker,
cs_attacker_clantag,
cs_weapon,
cs_event,
cs_health,
cs_damage,
cs_armor,
cs_damage_armor,
cs_victim,
cs_team_attacker,
cs_team_victim
from cs_log
order by
cs_attacker,
cs_event,
cs_weapon
"""
SQL_DEATHS =3D """
select
cs_victim,
count(*) as deaths
from cs_log
where cs_event =3D 1
group by cs_victim
order by deaths desc
"""
SQL_KILLS =3D """
select
cs_attacker,
count(*) as kills
from cs_log
where cs_event =3D 1
group by cs_attacker
order by kills desc
"""
SQL_HOSTAGE_KILLS =3D """
select
cs_attacker,
count(*) as kills
from cs_log
where cs_event =3D 5
group by cs_attacker
order by kills desc
"""
SQL_TEAM_KILLS =3D """
select
cs_attacker,
count(*) as kills
from cs_log
where cs_event =3D 3
group by cs_attacker
order by kills desc
"""
SQL_RESCUED_HOSTAGE =3D """
select
cs_attacker,
count(*) as rescued_hostages
from cs_log
where cs_event =3D 7
group by cs_attacker
order by rescued_hostages desc
"""
SQL_MOST_TEAM_DAMAGE =3D """
select cs_attacker, sum(cs_damage) + sum(cs_damage_armor) as damage
from cs_log
where cs_event =3D 4
group by cs_attacker
order by damage desc
"""
SQL_MOST_DAMAGE =3D """
select cs_attacker, sum(cs_damage)+sum(cs_damage_armor) as damage
from cs_log
where cs_event =3D 2
group by cs_attacker
order by damage desc
"""
def PlayerStats(self):
players =3D {}
db =3D MySQLdb.connect(db=3D'zopetest')
cur =3D db.cursor()
cur.execute(SQL_KILLS)
for player, kills in cur.fetchall():
players[player] =3D {'kills':kills,
'deaths':0,
'team_kills':0,
'team_damage':0,
'hostage_kills':0,
'hostage_rescued':0}
cur.execute(SQL_DEATHS)
res =3D cur.fetchall()
for player, deaths in res:
if not players.has_key(player):
players[player] =3D {}
players[player]['deaths'] =3D deaths
cur.execute(SQL_TEAM_KILLS)
res =3D cur.fetchall()
for player, team_kills in res:
if not players.has_key(player):
players[player] =3D {}
players[player]['team_kills'] =3D team_kills
cur.execute(SQL_RESCUED_HOSTAGE)
res =3D cur.fetchall()
for player, hostage_rescued in res:
if not players.has_key(player):
players[player] =3D {}
players[player]['hostage_rescued'] =3D hostage_rescued
cur.execute(SQL_MOST_TEAM_DAMAGE)
res =3D cur.fetchall()
for player, team_damage in res:
if not players.has_key(player):
players[player] =3D {}
players[player]['team_damage'] =3D team_damage
cur.execute(SQL_MOST_DAMAGE)
res =3D cur.fetchall()
for player, damage in res:
if not players.has_key(player):
players[player] =3D {}
players[player]['damage'] =3D damage
cur.execute(SQL_HOSTAGE_KILLS)
res =3D cur.fetchall()
for player, hostage_kills in res:
if not players.has_key(player):
players[player] =3D {}
players[player]['hostage_kills'] =3D hostage_kills
result =3D []
for player in players:
kill_death_ratio =3D float(players[player]['kills']) / =
float(players[player]['deaths'])
damage_team_damage_ratio =3D float(players[player]['damage']) / =
float(players[player]['team_damage'])
score =3D kill_death_ratio * damage_team_damage_ratio
=20
result.append((score, player, players[player]['kills'], =
players[player]['deaths'], players[player]['damage'], =
players[player]['team_damage'], kill_death_ratio, =
damage_team_damage_ratio))
result.sort()
result.reverse()
stats =3D []
for piece in result:
score, player, kills, deaths, damage, team_damage, kd_ratio, =
dt_ratio =3D piece
stats.append({'player':player, 'score':score, 'kills': kills, =
'deaths': deaths, 'damage': damage, 'team_damage': team_damage, =
'kd_ratio':kd_ratio, 'dt_ratio':dt_ratio})
return stats
Doing something simple like this :
def AList(self):
return [{'fname':'Thomas'}, {'fname':'Roger'}]
in a module and importing it works just fine. Testing is ok and the same =
DTML-piece fitted to the simple method works like a charm.
What am I doing wrong???
Appreciate any help you can provide.
Best regards,
Thomas Weholt, not yet Zope-meister but want to be ;-)
------=_NextPart_000_004B_01C226E4.742A3F80
Content-Type: text/html;
charset="iso-8859-1"
Content-Transfer-Encoding: quoted-printable
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML><HEAD>
<META http-equiv=3DContent-Type content=3D"text/html; =
charset=3Diso-8859-1">
<META content=3D"MSHTML 6.00.2716.2200" name=3DGENERATOR>
<STYLE></STYLE>
</HEAD>
<BODY bgColor=3D#ffffff>
<DIV><FONT face=3DArial size=3D2>I've got a simple external method that =
returns a=20
list containing dictionaries. If I run it from python it works fine, =
imported=20
and used in Zope it raises an exception "Loop over=20
non-sequence".</FONT></DIV>
<DIV><FONT face=3DArial size=3D2>The script extracts some data from a =
table,=20
containing the results from a parsed logfile, created by the game =
Counter-strike=20
( if you're interested ). I'm no expert in SQL ( as the code below =
probably=20
shows )</FONT></DIV>
<DIV><FONT face=3DArial size=3D2>but doing it in Python is no match ( =
even if the=20
code is verbose and perhaps a bit inefficient. Tips and clues are =
appreciated if=20
you can make anything out of it ). </FONT></DIV>
<DIV><FONT face=3DArial size=3D2></FONT> </DIV>
<DIV><FONT face=3DArial size=3D2>I import the method in Zope, calling it =
PlayerStats, from the module CSPlayerStats. The file itself is the=20
Extensions-folder under the Zope main-folder. Try to test it in the ZMI =
and the=20
error pops up. Thought of using it like so :</FONT></DIV>
<DIV><FONT face=3DArial size=3D2></FONT> </DIV>
<DIV><FONT face=3DArial size=3D2><dtml-in PlayerStats><BR> =
<dtml-let=20
item=3Dsequence-item><BR> <dtml-var=20
"item['player']"><!-- more fields from the dictionary, here =
represented as=20
item --><br><BR> =20
</dtml-let><BR></dtml-in><BR></FONT></DIV>
<DIV><FONT face=3DArial size=3D2>The external method :</FONT></DIV>
<DIV><FONT face=3DArial size=3D2></FONT> </DIV>
<DIV><FONT face=3DArial size=3D2>import MySQLdb</FONT></DIV>
<DIV> </DIV>
<DIV><FONT face=3DArial size=3D2>SQL_PLAYER_INFO =3D=20
"""<BR>select<BR> cs_attacker,<BR> =20
cs_attacker_clantag,<BR> =
cs_weapon,<BR> =20
cs_event,<BR> cs_health,<BR> =20
cs_damage,<BR> cs_armor,<BR> =20
cs_damage_armor,<BR> cs_victim,<BR> =20
cs_team_attacker,<BR> cs_team_victim<BR>from =
cs_log<BR>order=20
by<BR> cs_attacker,<BR> =20
cs_event,<BR> cs_weapon<BR>"""</FONT></DIV>
<DIV> </DIV>
<DIV><FONT face=3DArial size=3D2>SQL_DEATHS =3D =
"""<BR>select<BR> =20
cs_victim,<BR> count(*) as deaths<BR>from cs_log<BR>where =
cs_event =3D=20
1<BR>group by cs_victim<BR>order by deaths desc<BR>"""</FONT></DIV>
<DIV> </DIV>
<DIV><FONT face=3DArial size=3D2>SQL_KILLS =3D =
"""<BR>select<BR> =20
cs_attacker,<BR> count(*) as kills<BR>from cs_log<BR>where =
cs_event=20
=3D 1<BR>group by cs_attacker<BR>order by kills desc<BR>"""</FONT></DIV>
<DIV> </DIV>
<DIV><FONT face=3DArial size=3D2>SQL_HOSTAGE_KILLS =3D =
"""<BR>select<BR> =20
cs_attacker,<BR> count(*) as kills<BR>from cs_log<BR>where =
cs_event=20
=3D 5<BR>group by cs_attacker<BR>order by kills desc<BR>"""</FONT></DIV>
<DIV> </DIV>
<DIV><FONT face=3DArial size=3D2>SQL_TEAM_KILLS =3D =
"""<BR>select<BR> =20
cs_attacker,<BR> count(*) as kills<BR>from cs_log<BR>where =
cs_event=20
=3D 3<BR>group by cs_attacker<BR>order by kills desc<BR>"""</FONT></DIV>
<DIV> </DIV>
<DIV><FONT face=3DArial size=3D2>SQL_RESCUED_HOSTAGE =3D =
"""<BR>select<BR> =20
cs_attacker,<BR> count(*) as rescued_hostages<BR>from=20
cs_log<BR>where cs_event =3D 7<BR>group by cs_attacker<BR>order by=20
rescued_hostages desc<BR>"""</FONT></DIV>
<DIV> </DIV>
<DIV><FONT face=3DArial size=3D2>SQL_MOST_TEAM_DAMAGE =3D """<BR>select =
cs_attacker,=20
sum(cs_damage) + sum(cs_damage_armor) as damage<BR>from cs_log<BR>where =
cs_event=20
=3D 4<BR>group by cs_attacker<BR>order by damage =
desc<BR>"""</FONT></DIV>
<DIV> </DIV>
<DIV><FONT face=3DArial size=3D2>SQL_MOST_DAMAGE =3D """<BR>select =
cs_attacker,=20
sum(cs_damage)+sum(cs_damage_armor) as damage<BR>from cs_log<BR>where =
cs_event =3D=20
2<BR>group by cs_attacker<BR>order by damage desc<BR>"""</FONT></DIV>
<DIV> </DIV>
<DIV><FONT face=3DArial size=3D2>def =
PlayerStats(self):<BR> =20
players =3D {}<BR> db =3D=20
MySQLdb.connect(db=3D'zopetest')<BR> cur =3D=20
db.cursor()</FONT></DIV>
<DIV> </DIV>
<DIV><FONT face=3DArial size=3D2> =20
cur.execute(SQL_KILLS)<BR> for player, kills in=20
cur.fetchall():<BR> =
players[player] =3D=20
{'kills':kills,<BR> =
&=
nbsp; =20
'deaths':0,<BR> &nbs=
p;  =
; =20
'team_kills':0,<BR> =
&=
nbsp; =20
'team_damage':0,<BR>  =
; =
=20
'hostage_kills':0,<BR> &nb=
sp; &nbs=
p; =20
'hostage_rescued':0}</FONT></DIV>
<DIV> </DIV>
<DIV><FONT face=3DArial size=3D2> =20
cur.execute(SQL_DEATHS)<BR> res =3D=20
cur.fetchall()<BR> for player, deaths in=20
res:<BR> if not=20
players.has_key(player):<BR> &nb=
sp; =20
players[player] =3D {}<BR> =20
players[player]['deaths'] =3D deaths</FONT></DIV>
<DIV><FONT face=3DArial size=3D2></FONT> </DIV>
<DIV><FONT face=3DArial size=3D2> =20
cur.execute(SQL_TEAM_KILLS)<BR> res =3D=20
cur.fetchall()<BR> for player, team_kills in=20
res:<BR> if not=20
players.has_key(player):<BR> &nb=
sp; =20
players[player] =3D {}<BR> =20
players[player]['team_kills'] =3D team_kills</FONT></DIV>
<DIV> </DIV>
<DIV><FONT face=3DArial size=3D2> =20
cur.execute(SQL_RESCUED_HOSTAGE)<BR> res =3D=20
cur.fetchall()<BR> for player, hostage_rescued in=20
res:<BR> if not=20
players.has_key(player):<BR> &nb=
sp; =20
players[player] =3D {}<BR> =20
players[player]['hostage_rescued'] =3D hostage_rescued</FONT></DIV>
<DIV> </DIV>
<DIV><FONT face=3DArial size=3D2> =20
cur.execute(SQL_MOST_TEAM_DAMAGE)<BR> res =3D=20
cur.fetchall()<BR> for player, team_damage in=20
res:<BR> if not=20
players.has_key(player):<BR> &nb=
sp; =20
players[player] =3D {}<BR> =20
players[player]['team_damage'] =3D team_damage</FONT></DIV>
<DIV> </DIV>
<DIV><FONT face=3DArial size=3D2> =20
cur.execute(SQL_MOST_DAMAGE)<BR> res =3D=20
cur.fetchall()<BR> for player, damage in=20
res:<BR> if not=20
players.has_key(player):<BR> &nb=
sp; =20
players[player] =3D {}<BR> =20
players[player]['damage'] =3D damage</FONT></DIV>
<DIV> </DIV>
<DIV><FONT face=3DArial size=3D2> =20
cur.execute(SQL_HOSTAGE_KILLS)<BR> res =3D=20
cur.fetchall()<BR> for player, hostage_kills in=20
res:<BR> if not=20
players.has_key(player):<BR> &nb=
sp; =20
players[player] =3D {}<BR> =20
players[player]['hostage_kills'] =3D hostage_kills</FONT></DIV>
<DIV> </DIV>
<DIV><FONT face=3DArial size=3D2> result =3D=20
[]<BR> for player in=20
players:<BR> kill_death_ratio =
=3D=20
float(players[player]['kills']) /=20
float(players[player]['deaths'])<BR> &=
nbsp;=20
damage_team_damage_ratio =3D float(players[player]['damage']) /=20
float(players[player]['team_damage'])<BR> &n=
bsp; =20
score =3D kill_death_ratio *=20
damage_team_damage_ratio<BR> =20
<BR> result.append((score, =
player,=20
players[player]['kills'], players[player]['deaths'], =
players[player]['damage'],=20
players[player]['team_damage'], kill_death_ratio,=20
damage_team_damage_ratio))</FONT></DIV>
<DIV> </DIV>
<DIV><FONT face=3DArial size=3D2> =20
result.sort()<BR> =
result.reverse()<BR> stats=20
=3D []<BR> for piece in=20
result:<BR> score, player, =
kills,=20
deaths, damage, team_damage, kd_ratio, dt_ratio =3D=20
piece<BR> =20
stats.append({'player':player, 'score':score, 'kills': kills, 'deaths': =
deaths,=20
'damage': damage, 'team_damage': team_damage, 'kd_ratio':kd_ratio,=20
'dt_ratio':dt_ratio})</FONT></DIV>
<DIV> </DIV>
<DIV><FONT face=3DArial size=3D2> return =
stats</FONT></DIV>
<DIV><FONT face=3DArial size=3D2></FONT> </DIV>
<DIV><FONT face=3DArial size=3D2>Doing something simple like this =
:</FONT></DIV>
<DIV><FONT face=3DArial size=3D2></FONT> </DIV>
<DIV><FONT face=3DArial size=3D2>def AList(self):<BR> =
return=20
[{'fname':'Thomas'}, {'fname':'Roger'}]</FONT></DIV>
<DIV><FONT face=3DArial size=3D2></FONT> </DIV>
<DIV><FONT face=3DArial size=3D2>in a module and importing it works just =
fine.=20
Testing is ok and the same DTML-piece fitted to the simple method works =
like a=20
charm.</FONT></DIV>
<DIV><FONT face=3DArial size=3D2></FONT> </DIV>
<DIV><FONT face=3DArial size=3D2>What am I doing wrong???</FONT></DIV>
<DIV><FONT face=3DArial size=3D2></FONT> </DIV>
<DIV><FONT face=3DArial size=3D2>Appreciate any help you can =
provide.</FONT></DIV>
<DIV><FONT face=3DArial size=3D2></FONT> </DIV>
<DIV><FONT face=3DArial size=3D2>Best regards,</FONT></DIV>
<DIV><FONT face=3DArial size=3D2>Thomas Weholt, not yet Zope-meister but =
want to be=20
;-)</FONT></DIV></BODY></HTML>
------=_NextPart_000_004B_01C226E4.742A3F80--