summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xdumps/second-a-lap.py18
-rwxr-xr-xelo.py26
-rw-r--r--f1elo/db.py9
-rw-r--r--f1elo/elo.py12
-rw-r--r--f1elo/interface.py27
-rw-r--r--f1elo/model.py89
6 files changed, 139 insertions, 42 deletions
diff --git a/dumps/second-a-lap.py b/dumps/second-a-lap.py
index 867d7d3..a6665c9 100755
--- a/dumps/second-a-lap.py
+++ b/dumps/second-a-lap.py
@@ -11,14 +11,14 @@ import urllib2
import urlparse
from sys import argv
-from lxml import etree, html
-
from bs4 import BeautifulSoup
+from lxml import etree, html
def fetch(url):
print url
- contents = json.loads(urllib2.urlopen('http://second-a-lap.blogspot.com/feeds/posts/default?'+urllib.urlencode({ 'alt': 'json', 'v': 2, 'dynamicviews': 1, 'path': url })).read())
+ contents = json.loads(urllib2.urlopen('http://second-a-lap.blogspot.com/feeds/posts/default?' +
+ urllib.urlencode({'alt': 'json', 'v': 2, 'dynamicviews': 1, 'path': url})).read())
title = contents['feed']['entry'][0]['title']['$t']
print title
text = contents['feed']['entry'][0]['content']['$t']
@@ -31,13 +31,19 @@ def fetch(url):
path = open(os.path.join('second-a-lap', name + '.txt'), 'w')
table = etree.tostring(table)
print >>path, table
- csv_file = csv.writer(open(os.path.join('second-a-lap', 'csv', name + '.csv'), 'w'))
+ csv_file = csv.writer(
+ open(os.path.join('second-a-lap', 'csv', name + '.csv'), 'w'))
soup = BeautifulSoup(table)
for row in soup.find_all('tr'):
- row = map(lambda t: re.sub('\s+', ' ', " ".join(t.stripped_strings)).encode('utf-8'), row.find_all(re.compile('t[dh]')))
+ row = map(
+ lambda t: re.sub('\s+',
+ ' ',
+ " ".join(t.stripped_strings)).encode('utf-8'),
+ row.find_all(re.compile('t[dh]')))
csv_file.writerow(row)
i += 1
+
def compile(files):
headers = set()
values = []
@@ -57,7 +63,7 @@ def compile(files):
data['Race'] = race_id
i += 1
values.append(data)
- writer.writerow([race_id,path,'','',''])
+ writer.writerow([race_id, path, '', '', ''])
race_id += 1
except IOError:
pass
diff --git a/elo.py b/elo.py
index 7f88113..8aacfc8 100755
--- a/elo.py
+++ b/elo.py
@@ -1,9 +1,12 @@
#!/usr/bin/env python
import argparse
-import dateutil.parser
import sys
-parser = argparse.ArgumentParser(description='Ranks Formula One drivers using Elo rating',
+import dateutil.parser
+from f1elo.interface import Interface
+
+parser = argparse.ArgumentParser(
+ description='Ranks Formula One drivers using Elo rating',
formatter_class=argparse.RawTextHelpFormatter)
parser.add_argument('command', metavar='COMMAND', nargs='?',
help="Action to execute against the database:\n"
@@ -18,9 +21,19 @@ parser.add_argument('--date',
'Print ratings for DATE,\n'
'reset ratings all the way down to DATE\n'
'or rank the races all the way up to DATE.')
-parser.add_argument('--limit', help='Ranking list (display) cut-off point.', type=int)
-parser.add_argument('-v', help='Display verbose info on rating progress to STDERR.', action='store_true')
-parser.add_argument('--force', '-f', help='Force database initialization (for "init" command).', action='store_true')
+parser.add_argument(
+ '--limit',
+ help='Ranking list (display) cut-off point.',
+ type=int)
+parser.add_argument(
+ '-v',
+ help='Display verbose info on rating progress to STDERR.',
+ action='store_true')
+parser.add_argument(
+ '--force',
+ '-f',
+ help='Force database initialization (for "init" command).',
+ action='store_true')
arguments = parser.parse_args()
@@ -30,13 +43,12 @@ date = arguments.date
if date:
date = dateutil.parser.parse(date).date()
-from f1elo.interface import Interface
interface = Interface(date)
if command == 'reset':
interface.reset(_debug=arguments.v)
elif command == 'rate':
- interface.rate( _debug=arguments.v)
+ interface.rate(_debug=arguments.v)
elif command == 'init':
interface.init_db(force=arguments.force)
sys.exit(0)
diff --git a/f1elo/db.py b/f1elo/db.py
index 554a061..58e7a8a 100644
--- a/f1elo/db.py
+++ b/f1elo/db.py
@@ -5,13 +5,16 @@ import __main__
from sqlalchemy import create_engine, event
from sqlalchemy.orm import sessionmaker
-config = json.load(open(path.join(path.dirname(__main__.__file__), 'config', 'db.json')))
+config = json.load(
+ open(path.join(path.dirname(__main__.__file__), 'config', 'db.json')))
if config['engine'] == 'mysql':
- engine = create_engine("mysql://{0[user]}:{0[pass]}@{0[host]}/{0[db]}?charset=utf8".format(config))
+ engine = create_engine(
+ "mysql://{0[user]}:{0[pass]}@{0[host]}/{0[db]}?charset=utf8".format(config))
elif config['engine'] == 'sqlite':
engine = create_engine("sqlite:///{0[file]}".format(config))
+
def fk_pragma(conn, record):
- conn.execute('PRAGMA FOREIGN_KEYS=ON');
+ conn.execute('PRAGMA FOREIGN_KEYS=ON')
event.listen(engine, 'connect', fk_pragma)
Session = sessionmaker(bind=engine)
diff --git a/f1elo/elo.py b/f1elo/elo.py
index 6a007d8..51c9e23 100644
--- a/f1elo/elo.py
+++ b/f1elo/elo.py
@@ -7,9 +7,11 @@ from f1elo.model import *
class Elo:
+
def __init__(self, session):
self.session = session
- self.config = json.load(open(path.join(path.dirname(__main__.__file__), 'config', 'elo.json')))
+ self.config = json.load(
+ open(path.join(path.dirname(__main__.__file__), 'config', 'elo.json')))
def get_ranking(self, driver, rank_date=None):
rank = driver.get_ranking(rank_date)
@@ -31,7 +33,12 @@ class Elo:
if e.result_group:
entries_to_compare.append(e)
for c in combinations(entries_to_compare, 2):
- score = self.get_score(rankings[c[0]] - rankings[c[1]], self.get_outcome(c), self.get_importance(race, [rankings[c[0]], rankings[c[1]]]))
+ score = self.get_score(
+ rankings[c[0]] - rankings[c[1]],
+ self.get_outcome(c),
+ self.get_importance(race,
+ [rankings[c[0]],
+ rankings[c[1]]]))
new_rankings[c[0]] += score
new_rankings[c[1]] -= score
return new_rankings
@@ -45,7 +52,6 @@ class Elo:
return base_importance * 0.75
return base_importance / 2
-
def get_outcome(self, entries):
if entries[0].result_group < entries[1].result_group:
return 1
diff --git a/f1elo/interface.py b/f1elo/interface.py
index 6cb8fc6..de472b5 100644
--- a/f1elo/interface.py
+++ b/f1elo/interface.py
@@ -1,16 +1,17 @@
from __future__ import print_function
import datetime
-import dateutil.relativedelta
import sys
-from sqlalchemy import MetaData
-
+import dateutil.relativedelta
from f1elo.db import Session
from f1elo.elo import Elo
from f1elo.model import *
+from sqlalchemy import MetaData
+
class Interface:
+
def __init__(self, date=None):
self.session = Session()
self.date = date
@@ -69,8 +70,8 @@ class Interface:
for entry, rank in ranks.iteritems():
correction = rank / len(entry.drivers)
for driver in entry.drivers:
- if not driver_ranks.has_key(driver):
- driver_ranks[driver] = 0;
+ if driver not in driver_ranks:
+ driver_ranks[driver] = 0
driver_ranks[driver] += correction
for driver, rank in driver_ranks.iteritems():
ranking = Ranking()
@@ -81,7 +82,12 @@ class Interface:
if _debug:
for entry in race.entries:
- print(entry, elo.get_entry_ranking(entry, race.date), elo.get_entry_ranking(entry), file=sys.stderr)
+ print(
+ entry,
+ elo.get_entry_ranking(entry,
+ race.date),
+ elo.get_entry_ranking(entry),
+ file=sys.stderr)
print('', file=sys.stderr)
race.ranked = True
@@ -104,11 +110,16 @@ class Interface:
date += datetime.timedelta(1)
one_year = dateutil.relativedelta.relativedelta(years=1)
- rankings = self.session.query(Ranking).filter(Ranking.rank_date > (date - one_year)).filter(Ranking.rank_date <= date).all()
+ rankings = self.session.query(
+ Ranking).filter(
+ Ranking.rank_date > (
+ date - one_year)).filter(
+ Ranking.rank_date <= date).all(
+ )
drivers = {}
for ranking in rankings:
- if not drivers.has_key(ranking.driver):
+ if ranking.driver not in drivers:
drivers[ranking.driver] = ranking.driver.get_ranking(date)
self.date = date
diff --git a/f1elo/model.py b/f1elo/model.py
index 2fc4c0c..7757564 100644
--- a/f1elo/model.py
+++ b/f1elo/model.py
@@ -5,6 +5,7 @@ from sqlalchemy.types import Boolean, Date, Float, Integer, String
Base = declarative_base()
+
class Driver(Base):
__tablename__ = 'drivers'
@@ -12,7 +13,12 @@ class Driver(Base):
driver = Column(String(1024))
country = Column(String(255))
- rankings = relationship('Ranking', order_by='Ranking.rank_date', back_populates='driver', cascade="all", passive_deletes=True)
+ rankings = relationship(
+ 'Ranking',
+ order_by='Ranking.rank_date',
+ back_populates='driver',
+ cascade="all",
+ passive_deletes=True)
def __repr__(self):
return (u"<%s (#%d)>" % (self.driver, self.id)).encode('utf8')
@@ -27,7 +33,7 @@ class Driver(Base):
@staticmethod
def fetch(name, country, session):
- driver = session.query(Driver).filter(Driver.driver==name).first()
+ driver = session.query(Driver).filter(Driver.driver == name).first()
if not driver:
driver = Driver()
driver.driver = name
@@ -36,10 +42,23 @@ class Driver(Base):
return driver
driver_entry = Table('driver_entries', Base.metadata,
- Column('_driver', Integer, ForeignKey('drivers.id', onupdate="CASCADE", ondelete="CASCADE")),
- Column('_entry', Integer, ForeignKey('entries.id', onupdate="CASCADE", ondelete="CASCADE")),
+ Column(
+ '_driver',
+ Integer,
+ ForeignKey(
+ 'drivers.id',
+ onupdate="CASCADE",
+ ondelete="CASCADE")),
+ Column(
+ '_entry',
+ Integer,
+ ForeignKey(
+ 'entries.id',
+ onupdate="CASCADE",
+ ondelete="CASCADE")),
Column('id', Integer, primary_key=True))
+
class Entry(Base):
__tablename__ = 'entries'
@@ -48,14 +67,27 @@ class Entry(Base):
car_no = Column(String(255))
result_group = Column(Integer)
- _race = Column(Integer, ForeignKey('races.id', onupdate="CASCADE", ondelete="CASCADE"))
- race = relationship('Race', back_populates='entries', order_by=result_group)
-
- drivers = relationship('Driver', secondary=driver_entry, cascade="all", passive_deletes=True)
+ _race = Column(
+ Integer,
+ ForeignKey(
+ 'races.id',
+ onupdate="CASCADE",
+ ondelete="CASCADE"))
+ race = relationship(
+ 'Race',
+ back_populates='entries',
+ order_by=result_group)
+
+ drivers = relationship(
+ 'Driver',
+ secondary=driver_entry,
+ cascade="all",
+ passive_deletes=True)
def __repr__(self):
return ('#%s (%s) %s[%d]' % (self.car_no, ', '.join([driver.__repr__().decode('utf8') for driver in self.drivers]), self.result, self.result_group)).encode('utf8')
+
class Race(Base):
__tablename__ = 'races'
@@ -64,14 +96,28 @@ class Race(Base):
date = Column(Date)
ranked = Column(Boolean, default=False)
- _type = Column(Integer, ForeignKey('race_types.id', onupdate="CASCADE", ondelete="CASCADE"))
- type = relationship('RaceType', back_populates='races', order_by='Race.date')
-
- entries = relationship('Entry', back_populates='race', order_by='Entry.result_group', cascade="all", passive_deletes=True)
+ _type = Column(
+ Integer,
+ ForeignKey(
+ 'race_types.id',
+ onupdate="CASCADE",
+ ondelete="CASCADE"))
+ type = relationship(
+ 'RaceType',
+ back_populates='races',
+ order_by='Race.date')
+
+ entries = relationship(
+ 'Entry',
+ back_populates='race',
+ order_by='Entry.result_group',
+ cascade="all",
+ passive_deletes=True)
def __repr__(self):
return ('%s (%s)' % (self.race, self.date)).encode('utf8')
+
class RaceType(Base):
__tablename__ = 'race_types'
@@ -79,11 +125,16 @@ class RaceType(Base):
code = Column(String(255))
description = Column(String(1024))
- races = relationship('Race', back_populates='type', cascade="all", passive_deletes=True)
+ races = relationship(
+ 'Race',
+ back_populates='type',
+ cascade="all",
+ passive_deletes=True)
def __repr__(self):
return ('%s (%s)' % (self.description, self.code)).encode('utf8')
+
class Ranking(Base):
__tablename__ = 'rankings'
@@ -91,8 +142,16 @@ class Ranking(Base):
rank_date = Column(Date)
ranking = Column(Float)
- _driver = Column(Integer, ForeignKey('drivers.id', onupdate="CASCADE", ondelete="CASCADE"))
- driver = relationship('Driver', back_populates='rankings', order_by=rank_date)
+ _driver = Column(
+ Integer,
+ ForeignKey(
+ 'drivers.id',
+ onupdate="CASCADE",
+ ondelete="CASCADE"))
+ driver = relationship(
+ 'Driver',
+ back_populates='rankings',
+ order_by=rank_date)
def __repr__(self):
return ("%s: %0.2f (%s)" % (self.driver.__repr__().decode('utf8'), self.ranking, self. rank_date)).encode('utf8')