Skip to content

Commit

Permalink
forking pychallonge; some sql file cleanup
Browse files Browse the repository at this point in the history
  • Loading branch information
lhayhurst committed Apr 6, 2016
1 parent 8e35fef commit 0c56b13
Show file tree
Hide file tree
Showing 12 changed files with 310 additions and 8 deletions.
4 changes: 4 additions & 0 deletions challonge/__init__.py
@@ -0,0 +1,4 @@
__version__ = "1.0.1"

import tournaments, matches, participants
from api import set_credentials, get_credentials, fetch, ChallongeException
132 changes: 132 additions & 0 deletions challonge/api.py
@@ -0,0 +1,132 @@
import decimal
import urllib
import urllib2
try:
from xml.etree import cElementTree as ElementTree
except ImportError:
from xml.etree import ElementTree


CHALLONGE_API_URL = "api.challonge.com/v1/"

_credentials = {
"user": None,
"api_key": None,
}


class ChallongeException(Exception):
pass


def set_credentials(username, api_key):
"""Set the challonge.com api credentials to use."""
_credentials["user"] = username
_credentials["api_key"] = api_key


def get_credentials():
"""Retrieve the challonge.com credentials set with set_credentials()."""
return _credentials["user"], _credentials["api_key"]


def fetch(method, uri, params_prefix=None, **params):
"""Fetch the given uri and return the contents of the response."""
params = urllib.urlencode(_prepare_params(params, params_prefix))

# build the HTTP request
url = "https://%s/%s.xml" % (CHALLONGE_API_URL, uri)
print "fetching url " + url
if method == "GET":
req = urllib2.Request("%s?%s" % (url, params))
else:
req = urllib2.Request(url)
req.add_data(params)
req.get_method = lambda: method
req.add_header("Accept", "application/xml");
req.add_header("Content-Type", "application/xml");

# use basic authentication
user, api_key = get_credentials()
auth_handler = urllib2.HTTPBasicAuthHandler()
auth_handler.add_password(
realm="Application",
uri=req.get_full_url(),
user=user,
passwd=api_key
)
opener = urllib2.build_opener(auth_handler)

try:
response = opener.open(req)
except urllib2.HTTPError, e:
if e.code != 422:
raise
# wrap up application-level errors
doc = ElementTree.parse(e).getroot()
if doc.tag != "errors":
raise
errors = [e.text for e in doc]
raise ChallongeException(*errors)
return response


def fetch_and_parse(method, uri, params_prefix=None, **params):
"""Fetch the given uri and return the root Element of the response."""
doc = ElementTree.parse(fetch(method, uri, params_prefix, **params))
return _parse(doc.getroot())


def _parse(root):
"""Recursively convert an Element into python data types"""
import dateutil.parser
if root.tag == "nil-classes":
return []
elif root.get("type") == "array":
return [_parse(child) for child in root]

d = {}
for child in root:
type = child.get("type") or "string"

if child.get("nil"):
value = None
elif type == "boolean":
value = True if child.text.lower() == "true" else False
elif type == "datetime":
value = dateutil.parser.parse(child.text)
elif type == "decimal":
value = decimal.Decimal(child.text)
elif type == "integer":
value = int(child.text)
else:
value = child.text

d[child.tag] = value
return d


def _prepare_params(dirty_params, prefix=None):
"""Prepares parameters to be sent to challonge.com.
The `prefix` can be used to convert parameters with keys that
look like ("name", "url", "tournament_type") into something like
("tournament[name]", "tournament[url]", "tournament[tournament_type]"),
which is how challonge.com expects parameters describing specific
objects.
"""
params = {}
for k, v in dirty_params.iteritems():
if hasattr(v, "isoformat"):
v = v.isoformat()
elif isinstance(v, bool):
# challonge.com only accepts lowercase true/false
v = str(v).lower()

if prefix:
params["%s[%s]" % (prefix, k)] = v
else:
params[k] = v

return params
25 changes: 25 additions & 0 deletions challonge/matches.py
@@ -0,0 +1,25 @@
from challonge import api


def index(tournament, **params):
"""Retrieve a tournament's match list."""
return api.fetch_and_parse(
"GET",
"tournaments/%s/matches" % tournament,
**params)


def show(tournament, match_id):
"""Retrieve a single match record for a tournament."""
return api.fetch_and_parse(
"GET",
"tournaments/%s/matches/%s" % (tournament, match_id))


def update(tournament, match_id, **params):
"""Update/submit the score(s) for a match."""
api.fetch(
"PUT",
"tournaments/%s/matches/%s" % (tournament, match_id),
"match",
**params)
58 changes: 58 additions & 0 deletions challonge/participants.py
@@ -0,0 +1,58 @@
from challonge import api


def index(tournament):
"""Retrieve a tournament's participant list."""
return api.fetch_and_parse(
"GET",
"tournaments/%s/participants" % tournament)

def create(tournament, name, **params):
"""Add a participant to a tournament."""
params.update({"name": name})

return api.fetch_and_parse(
"POST",
"tournaments/%s/participants" % tournament,
"participant",
**params)


def show(tournament, participant_id):
"""Retrieve a single participant record for a tournament."""
return api.fetch_and_parse(
"GET",
"tournaments/%s/participants/%s" % (tournament, participant_id))


def update(tournament, participant_id, **params):
"""Update the attributes of a tournament participant."""
api.fetch(
"PUT",
"tournaments/%s/participants/%s" % (tournament, participant_id),
"participant",
**params)


def destroy(tournament, participant_id):
"""Destroys or deactivates a participant.
If tournament has not started, delete a participant, automatically
filling in the abandoned seed number.
If tournament is underway, mark a participant inactive, automatically
forfeiting his/her remaining matches.
"""
api.fetch(
"DELETE",
"tournaments/%s/participants/%s" % (tournament, participant_id))


def randomize(tournament):
"""Randomize seeds among participants.
Only applicable before a tournament has started.
"""
api.fetch("POST", "tournaments/%s/participants/randomize" % tournament)
64 changes: 64 additions & 0 deletions challonge/tournaments.py
@@ -0,0 +1,64 @@
from challonge import api


def index(**params):
"""Retrieve a set of tournaments created with your account."""
return api.fetch_and_parse("GET", "tournaments", **params)


def create(name, url, tournament_type="single elimination", **params):
"""Create a new tournament."""
params.update({
"name": name,
"url": url,
"tournament_type": tournament_type,
})

return api.fetch_and_parse("POST", "tournaments", "tournament", **params)


def show(tournament):
"""Retrieve a single tournament record created with your account."""
return api.fetch_and_parse("GET", "tournaments/%s" % tournament)


def update(tournament, **params):
"""Update a tournament's attributes."""
api.fetch("PUT", "tournaments/%s" % tournament, "tournament", **params)


def destroy(tournament):
"""Deletes a tournament along with all its associated records.
There is no undo, so use with care!
"""
api.fetch("DELETE", "tournaments/%s" % tournament)


def publish(tournament):
"""Publish a tournament, making it publically accessible.
The tournament must have at least 2 participants.
"""
api.fetch("POST", "tournaments/publish/%s" % tournament)


def start(tournament):
"""Start a tournament, opening up matches for score reporting.
The tournament must have at least 2 participants.
"""
api.fetch("POST", "tournaments/start/%s" % tournament)


def reset(tournament):
"""Reset a tournament, clearing all of its scores and attachments.
You can then add/remove/edit participants before starting the
tournament again.
"""
api.fetch("POST", "tournaments/reset/%s" % tournament)
17 changes: 17 additions & 0 deletions challonge_helper.py
@@ -1,3 +1,5 @@
import os
import unittest
import challonge


Expand Down Expand Up @@ -29,3 +31,18 @@ def match_index(self, tournament):
def attachments_index(self, tournament, match_id):
url = "tournaments/%s/matches/%s/attachments" % (tournament, match_id)
return challonge.api.fetch_and_parse("GET", url)

class challongeAPITest(unittest.TestCase):

def __init__(self,*args, **kwargs):
super(challongeAPITest, self).__init__(*args, **kwargs)
challonge_user = os.getenv('CHALLONGE_USER')
challonge_key = os.getenv('CHALLONGE_API_KEY')
self.ch = ChallongeHelper(challonge_user, challonge_key)

def testGetTournament(self):
i = self.ch.get_tournament("XWingVassalLeagueSeasonZero")
print i

if __name__ == "__main__":
unittest.main()
File renamed without changes.
File renamed without changes.
1 change: 0 additions & 1 deletion requirements.txt
Expand Up @@ -21,4 +21,3 @@ wsgiref==0.1.2
whoosh==2.5.6
python-jsonschema-objects==0.0.15
iso8601==0.1.11
pychallonge==1.0.1
11 changes: 7 additions & 4 deletions search.py
@@ -1,7 +1,7 @@
import re
import unittest

from sqlalchemy import and_, or_, func
from sqlalchemy import and_, or_, func, not_
from whoosh.qparser import QueryParser
from whoosh.query import Term

Expand All @@ -15,10 +15,12 @@ def wildcard(term):


expression_map = { 'AND' : and_,
'OR' : or_ }
'OR' : or_,
'NOT' : not_}

and_regex = re.compile( r'\s+and\s+')
or_regex = re.compile( r'\s+or\s+')
or_regex = re.compile( r'\s+or\s+')
not_regex = re.compile( r'\s+not\s+')

PILOT_MATCH = "pilot_match"
SHIP_MATCH = "ship_match"
Expand Down Expand Up @@ -67,7 +69,7 @@ def tree_to_expr(tree, subq):
fn = expression_map[tree.JOINT.strip()]
return fn(
*(
[tree_to_expr( child, subq) for child in tree ]
[tree_to_expr( child, subq) for child in tree ]
)
)

Expand Down Expand Up @@ -102,6 +104,7 @@ def __init__(self, search_term):

search_term = re.sub( and_regex, ' AND ', search_term )
search_term = re.sub( or_regex, ' OR ', search_term)
search_term = re.sub( not_regex, ' NOT ', search_term)

parser = QueryParser("content", schema=None)
q = parser.parse(search_term)
Expand Down
Empty file added season_zero_manual_entry.py
Empty file.
6 changes: 3 additions & 3 deletions xwlists.py
Expand Up @@ -161,15 +161,15 @@ def cache_xwvl_players():
print "caching league players"
c = ChallongeHelper( myapp.challonge_user, myapp.challonge_key )
pm = PersistenceManager(myapp.db_connector)
league = pm.get_league("X-Wing Vassal League Season Zero")
league = pm.get_league("X-Wing Vassal League Season Zero Dot Five")
bootstrap_league_players(c, league, pm)
return redirect(url_for('league_players', league_id=league.id))

@app.route( "/league_players")
def league_players():
league_id = request.args.get('league_id') #TODO: unused for now, use when we have more than one league ( if ever )
pm = PersistenceManager(myapp.db_connector)
league = pm.get_league("X-Wing Vassal League Season Zero")
league = pm.get_league("X-Wing Vassal League Season Zero Dot Five")
players = []
for tier in league.tiers:
for division in tier.divisions:
Expand Down Expand Up @@ -232,7 +232,7 @@ def league_admin():
def cache_league_results():
c = ChallongeHelper( myapp.challonge_user, myapp.challonge_key )
pm = PersistenceManager(myapp.db_connector)
league = pm.get_league("X-Wing Vassal League Season Zero")
league = pm.get_league("X-Wing Vassal League Season Zero Dot Five")

for d in league.tiers[0].divisions: #TODO: iterate through tiers when we have tiers to go through
print "fetching match results for division %s" % ( d.name )
Expand Down

0 comments on commit 0c56b13

Please sign in to comment.