Port to Python 3.

All scripts and modules have been ported to Python 3 and appear to
work.  Some changes to the lighttpd configuration were needed.
This commit is contained in:
John "Elwin" Edwards 2013-12-31 13:36:19 -05:00
parent 914f367657
commit aef04a38e1
10 changed files with 58 additions and 71 deletions

2
py/cleandb.py Normal file → Executable file
View file

@ -1,4 +1,4 @@
#!/usr/bin/python
#!/usr/bin/python3
# cleandb.py: empty the database in an orderly fashion
import rlgalldb as rlgall

View file

@ -1,4 +1,4 @@
#!/usr/bin/python
#!/usr/bin/python3
import os
import psycopg2

View file

@ -1,10 +1,11 @@
# rlgalldb.py
# Module for the Roguelike Gallery, using a postgres database
# Requires Python 3.3
import os
import calendar
import psycopg2
from datetime import datetime, tzinfo, timedelta
from datetime import datetime
import pytz
# Configuration
logdir = "/var/dgl/var/games/roguelike/"
@ -49,17 +50,6 @@ headerbook = {"endt":"End time", "score":"Score", "name":"Name", "xl":"XL",
offselstr = "SELECT offbytes FROM games WHERE gname = %s;"
newoffstr = "UPDATE games SET offbytes = %s WHERE gname = %s;"
# A representation of the UTC time zone. They say Py3k can better handle
# this madness.
class UTC(tzinfo):
def utcoffset(self, dt):
return timedelta(0)
def dst(self, dt):
return timedelta(0)
def tzname(self, dt):
return "UTC"
utc = UTC()
def getconn():
"Returns a database connection, or None if the connection fails."
try:
@ -71,7 +61,7 @@ def getconn():
def recnameToTS(filename):
pattern = "%Y-%m-%d.%H:%M:%S.ttyrec"
try:
dt = datetime.strptime(filename, pattern).replace(tzinfo=utc)
dt = datetime.strptime(filename, pattern).replace(tzinfo=pytz.utc)
return dt
except ValueError:
return None
@ -90,7 +80,7 @@ def linktoArchive(entry):
"Takes an entry dict and returns a link to the ttyrec archivist."
lstr = '<a href="/archive.cgi?name={0};game={1};time={2}">{3}</a>'
linktext = entry["endt"].strftime("%Y/%m/%d %H:%M:%S")
stamp = calendar.timegm(entry["endt"].utctimetuple())
stamp = int(entry["endt"].timestamp())
return lstr.format(entry["name"], entry["game"].uname, stamp, linktext)
def maketablerow(cells, isheader=None):
@ -156,7 +146,7 @@ class Game:
if self.sqltypes[item] == "bool":
ndict[item] = bool(int(value))
elif self.sqltypes[item] == "timestamptz":
ndict[item] = datetime.fromtimestamp(int(value), utc)
ndict[item] = datetime.fromtimestamp(int(value), pytz.utc)
else:
ndict[item] = value
return ndict
@ -181,7 +171,7 @@ class Game:
offset = cur.fetchone()[0]
newlist = []
try:
scr = open(self.scores)
scr = open(self.scores, encoding="utf-8")
scr.seek(offset)
self.getEntryDicts(scr, newlist)
except IOError:
@ -215,7 +205,7 @@ class Game:
if result:
prev = result[0]
else:
prev = datetime.fromtimestamp(0, utc);
prev = datetime.fromtimestamp(0, pytz.utc);
ttyrecdir = "/var/dgl/dgldir/ttyrec/{0}/{1}/".format(nameF, self.uname)
allfilekeys = [ (recnameToTS(f), f) for f in os.listdir(ttyrecdir) ]
vfilekeys = [ e for e in allfilekeys if e[0] > prev ]
@ -242,16 +232,17 @@ class Game:
"Prints the most recent games from the logfile, NOT the database."
newest = []
try:
scr = open(self.scores)
except IOError:
scr = open(self.scores, encoding="utf-8")
except FileNotFoundError:
pass
else:
# Text streams don't support random seeking.
try:
scr.seek(self.lookback, 2)
except IOError:
scr.seek(0) # The file wasn't that long, start at the beginning
if scr.tell() != 0:
scr.readline() # Throw away the incomplete line
scr.buffer.seek(self.lookback, 2)
except OSError:
scr.buffer.seek(0) # The file wasn't that long, start at the beginning
if scr.buffer.tell() != 0:
scr.buffer.readline() # Throw away the incomplete line
self.getEntryDicts(scr, newest)
newest.reverse()
scr.close()
@ -274,18 +265,11 @@ class RogueGame(Game):
"ttyrecs": "text ARRAY", "startt": "timestamptz"}
self.logdelim = " "
self.lookback = -1500
colspec = "("
valspec = "("
for i, col in enumerate(self.sqltypes.keys()):
colspec += col
valspec += "%({0})s".format(col)
if i == len(self.sqltypes) - 1:
colspec += ")"
valspec += ")"
else:
colspec += ", "
valspec += ", "
self.insertq = "INSERT INTO {0} {1} VALUES {2};".format(self.uname,
# Construct the insert query
fields = self.sqltypes.keys()
colspec = ", ".join(fields)
valspec = ", ".join([ "%({})s".format(c) for c in fields ])
self.insertq = "INSERT INTO {0} ({1}) VALUES ({2});".format(self.uname,
colspec, valspec)
# Class variables, used by some methods
fields = ["name", "score", "xl", "fate", "endt"]
@ -380,11 +364,12 @@ class RogueGame(Game):
def putIntoDB(self, dictlist, conn):
"Add the entries in dictlist to the database through connection conn, \
which needs the INSERT privilege."
# FIXME this monster needs to be procedurally generated
qstr = "INSERT INTO " + self.uname + " (endt, score, name, xl, fate, ttyrecs, startt) \
VALUES (%(endt)s, %(score)s, %(name)s, %(xl)s, %(fate)s, %(ttyrecs)s, %(startt)s);"
fields = self.sqltypes.keys()
fstr = ", ".join(fields)
vstr = ", ".join([ "%({})s".format(c) for c in fields ])
qstr = "INSERT INTO {0} ({1}) VALUES ({2});".format(self.uname, fstr, vstr);
cur = conn.cursor()
cur.executemany(qstr, [ d for d in dictlist if d["game"] == self ])
cur.executemany(self.insertq, [ d for d in dictlist if d["game"] == self ])
conn.commit()
cur.close()
return
@ -403,18 +388,11 @@ class ARogueGame(Game):
"fate": "text", "ttyrecs": "text ARRAY", "startt": "timestamptz"}
self.logdelim = " "
self.lookback = -1800
colspec = "("
valspec = "("
for i, col in enumerate(self.sqltypes.keys()):
colspec += col
valspec += "%({0})s".format(col)
if i == len(self.sqltypes) - 1:
colspec += ")"
valspec += ")"
else:
colspec += ", "
valspec += ", "
self.insertq = "INSERT INTO {0} {1} VALUES {2};".format(self.uname,
# Construct the insert query
fields = self.sqltypes.keys()
colspec = ", ".join(fields)
valspec = ", ".join([ "%({})s".format(c) for c in fields ])
self.insertq = "INSERT INTO {0} ({1}) VALUES ({2});".format(self.uname,
colspec, valspec)
# Class variables
fields = ["name", "score", "class", "xl", "fate", "endt"]
@ -492,7 +470,7 @@ gamelist = [rogue3, rogue4, rogue5, srogue, arogue5]
def playerpage(pname):
"Generate a player's HTML page"
# Write the beginning of the page
ppagefi = open(ppagename.format(pname), "w")
ppagefi = open(ppagename.format(pname), "w", encoding="utf-8")
ppagefi.write(phead.format(pname))
ppagefi.write(ptop)
ppagefi.write(navplayer.format(pname))
@ -509,7 +487,7 @@ def playerpage(pname):
scoresum = 0
for entry in entries:
scoresum += int(entry["score"])
avgscr = scoresum / len(entries)
avgscr = scoresum // len(entries)
ppagefi.write("<p>Average score: {0}</p>\n".format(avgscr))
# That should settle it. Print the end; then stop.
ppagefi.write(pend)
@ -518,7 +496,7 @@ def playerpage(pname):
def highpage():
# open the page and print the beginning
highpfi = open(hpagename, "w")
highpfi = open(hpagename, "w", encoding="utf-8")
highpfi.write(phead.format("High Scores"))
highpfi.write(ptop)
highpfi.write(navscore.format("High Scores"))

2
py/setupdb.py Normal file → Executable file
View file

@ -1,4 +1,4 @@
#!/usr/bin/python
#!/usr/bin/python3
# setupdb.py: initializes the database tables used by the rlg system.
import rlgalldb as rlgall