From 1d92c8ebe76c56154e8f72f258050e849c25a647 Mon Sep 17 00:00:00 2001 From: Eivind Fonn Date: Mon, 10 Aug 2015 21:46:39 +0200 Subject: [PATCH] Aesthetic overhaul - Delete trailing whitespace - Remove {{{ and }}} vim folding markers - Kill linter warnings (unused imports, PEP8, etc) - Turn many comments into docstrings --- aligulac/aligulac/tools.py | 57 +-- aligulac/aligulac/urls.py | 6 +- aligulac/aligulac/views.py | 39 +- aligulac/domination.py | 12 +- aligulac/dump.py | 11 +- aligulac/event_sort.py | 3 +- aligulac/period.py | 33 +- aligulac/rating.py | 9 +- aligulac/ratings/admin.py | 2 +- aligulac/ratings/comparisons.py | 2 +- aligulac/ratings/inference_views.py | 152 +++---- aligulac/ratings/misc_views.py | 77 ++-- aligulac/ratings/model_tools.py | 2 +- aligulac/ratings/models.py | 608 +++++++++++----------------- aligulac/ratings/player_views.py | 62 +-- aligulac/ratings/ranking_views.py | 32 +- aligulac/ratings/records_views.py | 12 +- aligulac/ratings/reports_views.py | 4 +- aligulac/ratings/results_views.py | 98 ++--- aligulac/ratings/team_views.py | 26 +- aligulac/ratings/tools.py | 66 +-- aligulac/reports.py | 12 +- aligulac/smoothing.py | 15 +- aligulac/teamranks.py | 9 +- aligulac/teamratings.py | 3 +- 25 files changed, 530 insertions(+), 822 deletions(-) diff --git a/aligulac/aligulac/tools.py b/aligulac/aligulac/tools.py index 4960383..2b8a34d 100644 --- a/aligulac/aligulac/tools.py +++ b/aligulac/aligulac/tools.py @@ -1,4 +1,4 @@ -# {{{ Imports +# Imports from itertools import chain import json import random @@ -37,9 +37,8 @@ from ratings.tools import get_latest_period, find_player from ratings.templatetags.ratings_extras import urlfilter from django.utils.translation import ugettext as _ -# }}} -# {{{ JsonResponse +# JsonResponse # Works similarily to HttpResponse but returns JSON instead. class JsonResponse(HttpResponse): @@ -50,10 +49,9 @@ def __init__(self, content, *args, **kwargs): kwargs["content_type"] = "application/json" super().__init__(scontent, *args, **kwargs) -# }}} -# {{{ Message +# Message # This class encodes error/success/warning messages sent to the templates. # context['messages'] should point to a list of Message objects. class Message: @@ -76,9 +74,8 @@ def __init__(self, text=None, title='', type='info', error=None, field=None, msg self.text = field + ': ' + error self.type = self.ERROR self.id = ''.join([random.choice(string.ascii_letters+string.digits) for _ in range(10)]) -# }}} -# {{{ NotUniquePlayerMessage +# NotUniquePlayerMessage class NotUniquePlayerMessage(Message): def __init__(self, search, players, update=None, updateline=None, type='error'): @@ -104,14 +101,12 @@ def __init__(self, search, players, update=None, updateline=None, type='error'): Message.__init__(self, s, _('\'%s\' not unique') % search, type) self.id = id -# }}} -# {{{ generate_messages: Generates a list of message objects for an object that supports them. +# generate_messages: Generates a list of message objects for an object that supports them. def generate_messages(obj): return [Message(m.get_message(), m.get_title(), m.type) for m in obj.message_set.all()] -# }}} -# {{{ login_message: Generates a message notifying about login status. +# login_message: Generates a message notifying about login status. def login_message(base, extra=''): if not base['adm']: text = ' '.join([_('You are not logged in.'), extra, '(%s)' % _('login')]) @@ -124,9 +119,8 @@ def login_message(base, extra=''): ) ]) base['messages'].append(Message(text, type=Message.INFO)) -# }}} -# {{{ StrippedCharField: Subclass of CharField that performs stripping. +# StrippedCharField: Subclass of CharField that performs stripping. class StrippedCharField(forms.CharField): def clean(self, value): value = super(StrippedCharField, self).clean(value) @@ -138,17 +132,15 @@ def clean(self, value): return None return value return None -# }}} -# {{{ get_param(request, param, default): Returns request.GET[param] if available, default if not. +# get_param(request, param, default): Returns request.GET[param] if available, default if not. def get_param(request, param, default): try: return request.GET[param] except: return default -# }}} -# {{{ get_param_choice(request, param, choices, default): Returns request.GET[param] if available and in +# get_param_choice(request, param, choices, default): Returns request.GET[param] if available and in # the list choices, default if not. def get_param_choice(request, param, choices, default): try: @@ -157,9 +149,8 @@ def get_param_choice(request, param, choices, default): return val except: return default -# }}} -# {{{ get_param_range(request, param, range, default): Returns request.GET[param] as an int, restricted to the +# get_param_range(request, param, range, default): Returns request.GET[param] as an int, restricted to the # range given (a tuple (min,max)), or default if not. def get_param_range(request, param, rng, default): try: @@ -167,27 +158,24 @@ def get_param_range(request, param, rng, default): return min(max(val, rng[0]), rng[1]) except: return default -# }}} -# {{{ get_param_date(request, param, default): Converts a GET param to a date. +# get_param_date(request, param, default): Converts a GET param to a date. def get_param_date(request, param, default): param = get_param(request, param, None) try: return datetime.strptime(param, '%Y-%m-%d').date() except: return default -# }}} -# {{{ post_param(request, param, default): Returns request.POST[param] if available, default if not. +# post_param(request, param, default): Returns request.POST[param] if available, default if not. # If you're using this method, consider deploying a form instead. def post_param(request, param, default): try: return request.POST[param] except: return default -# }}} -# {{{ base_ctx: Generates a minimal context, required to render the site layout and menus +# base_ctx: Generates a minimal context, required to render the site layout and menus # Parameters: # - section: A string, name of the current major section (or None) # - subpage: A string, name of the current subsection (or None) @@ -333,9 +321,8 @@ def add_subnav(title, url): base['commitbranch'] = p.communicate()[0].decode().strip() return base -# }}} -# {{{ cache_login_protect: Decorator for caching only if user is not logged in. +# cache_login_protect: Decorator for caching only if user is not logged in. # Use this in place of BOTH cache_page and csrf_protect, and only on pages that require a CSRF token IF AND # ONLY IF the user is logged in. If the view ALWAYS issues a CSRF token (or SOMETIMES does, but you can't tell # when easily), use neither cache_page nor csrf_protect. If the view NEVER issues a CSRF token, use cache_page @@ -348,25 +335,22 @@ def handler(request, *args, **kwargs): final_view = cache_page(view) return final_view(request, *args, **kwargs) return handler -# }}} -# {{{ etn: Executes a function and returns its result if it doesn't throw an exception, or None if it does. +# etn: Executes a function and returns its result if it doesn't throw an exception, or None if it does. def etn(f): try: return f() except: return None -# }}} -# {{{ ntz: Helper function with aggregation, sending None to 0, so that the sum of an empty list is 0. +# ntz: Helper function with aggregation, sending None to 0, so that the sum of an empty list is 0. # AS IT FUCKING SHOULD BE. ntz = lambda k: k if k is not None else 0 -# }}} -# {{{ search: Helper function for performing searches +# search: Helper function for performing searches def search(query, search_for=['players', 'teams', 'events'], strict=False): - # {{{ Split query + # Split query lex = shlex.shlex(query, posix=True) lex.wordchars += "'#-" lex.commenters = '' @@ -375,9 +359,8 @@ def search(query, search_for=['players', 'teams', 'events'], strict=False): terms = [s.strip() for s in list(lex) if s.strip() != ''] if len(terms) == 0: return None - # }}} - # {{{ Search for players, teams and events + # Search for players, teams and events if 'players' in search_for: players = find_player(lst=terms, make=False, soft=True, strict=strict) else: @@ -404,7 +387,5 @@ def search(query, search_for=['players', 'teams', 'events'], strict=False): if 'teams' in search_for: teams = teams.distinct() - # }}} return players, teams, events -# }}} diff --git a/aligulac/aligulac/urls.py b/aligulac/aligulac/urls.py index 95abdfd..b9913ec 100644 --- a/aligulac/aligulac/urls.py +++ b/aligulac/aligulac/urls.py @@ -1,4 +1,4 @@ -# {{{ Imports +# Imports from os.path import normpath, dirname, join from tastypie.api import Api @@ -29,7 +29,6 @@ from django.contrib import admin admin.autodiscover() -# }}} handler404 = 'aligulac.views.h404' handler500 = 'aligulac.views.h500' @@ -139,7 +138,7 @@ url(r'^api/', include(v1_api.urls)), ) -# {{{ If in debug mode (i.e. with the django server), we must serve CSS and JS ourselves. +# If in debug mode (i.e. with the django server), we must serve CSS and JS ourselves. if settings.DEBUG: resources = join(dirname(normpath(settings.PROJECT_PATH)), 'resources') urlpatterns += patterns('', @@ -152,4 +151,3 @@ url(r'^img/(?P.*)$', 'django.views.static.serve', {'document_root': join(resources, 'img')}) ) -# }}} diff --git a/aligulac/aligulac/views.py b/aligulac/aligulac/views.py index 190299c..333fced 100644 --- a/aligulac/aligulac/views.py +++ b/aligulac/aligulac/views.py @@ -1,4 +1,4 @@ -# {{{ Imports +# Imports from datetime import datetime from itertools import zip_longest import os @@ -53,9 +53,8 @@ filter_active, populate_teams, ) -# }}} -# {{{ DB table specification +# DB table specification DBTABLES = [{ 'name': 'player', 'desc': _('Contains player information.'), @@ -330,9 +329,8 @@ ] }, ] -# }}} -# {{{ Home page +# Home page @cache_page def home(request): base = base_ctx(request=request) @@ -357,9 +355,8 @@ def home(request): }) return render_to_response('index.djhtml', base) -# }}} -# {{{ Language change page +# Language change page def language(request): base = base_ctx(request=request) @@ -370,9 +367,8 @@ def language(request): base['return'] = '/' return render_to_response('language.djhtml', base) -# }}} -# {{{ db view +# db view @cache_page def db(request): base = base_ctx('About', 'Database', request) @@ -430,14 +426,13 @@ def db(request): }) return render_to_response('db.djhtml', base) -# }}} -# {{{ API documentation and keys +# API documentation and keys class APIKeyForm(forms.Form): organization = StrippedCharField(max_length=200, required=True, label=_('Name/organization')) contact = forms.EmailField(max_length=200, required=True, label=_('Contact')) - # {{{ Constructor + # Constructor def __init__(self, request=None, player=None): if request is not None: super(APIKeyForm, self).__init__(request.POST) @@ -445,9 +440,8 @@ def __init__(self, request=None, player=None): super(APIKeyForm, self).__init__() self.label_suffix = '' - # }}} - # {{{ add_key: Adds key if valid, returns messages + # add_key: Adds key if valid, returns messages def add_key(self): ret = [] @@ -471,7 +465,6 @@ def add_key(self): _("Your API key is %s. Please keep it safe.") % key.key, type=Message.SUCCESS)) return ret -# }}} def api(request): base = base_ctx('About', 'API', request) @@ -497,9 +490,8 @@ def api(request): }) return render_to_response('api.djhtml', base) -# }}} -# {{{ search view +# search view @cache_page def search(request): base = base_ctx(request=request) @@ -511,14 +503,13 @@ def search(request): players, teams, events = results - # {{{ Redirect if only one hit + # Redirect if only one hit if players.count() == 1 and teams.count() == 0 and events.count() == 0: return redirect('/players/%i-%s/' % (players.first().id, urlfilter(players.first().tag))) elif players.count() == 0 and teams.count() == 1 and events.count() == 0: return redirect('/teams/%i-%s/' % (teams.first().id, urlfilter(teams.first().name))) elif players.count() == 0 and teams.count() == 0 and events.count() == 1: return redirect('/results/events/%i-%s/' % (events.first().id, urlfilter(events.first().fullname))) - # }}} base.update({ 'results': zip_longest(players, teams, events, fillvalue=None), @@ -529,9 +520,8 @@ def search(request): }) return render_to_response('search.djhtml', base) -# }}} -# {{{ auto-complete search view +# auto-complete search view EXTRA_NULL_SELECT = { 'null_curr': 'CASE WHEN player.current_rating_id IS NULL THEN 0 ELSE 1 END' } @@ -587,9 +577,8 @@ def auto_complete_search(request): } for e in events[:num]] return JsonResponse(data) -# }}} -# {{{ Login, logout and change password +# Login, logout and change password def login_view(request): base = base_ctx(request=request) login_message(base) @@ -629,9 +618,8 @@ def changepwd(request): ) return render_to_response('changepwd.djhtml', base) -# }}} -# {{{ Error handlers +# Error handlers @cache_page def h404(request): base = base_ctx(request=request) @@ -641,4 +629,3 @@ def h404(request): def h500(request): base = base_ctx(request=request) return HttpResponseNotFound(render_to_string('500.djhtml', base)) -# }}} diff --git a/aligulac/domination.py b/aligulac/domination.py index cec698f..54a36ce 100755 --- a/aligulac/domination.py +++ b/aligulac/domination.py @@ -23,7 +23,7 @@ # Nothing counts before here. FIRST_PERIOD = 25 -# {{{ Evaluate the domination scores +# Evaluate the domination scores #print('[%s] Erasing domination scores' % str(datetime.now()), flush=True) #Rating.objects.update(domination=None) @@ -31,9 +31,8 @@ for period in Period.objects.filter(computed=True, id__gte=FIRST_PERIOD): benchmark = filter_active(period.rating_set.all()).order_by('-rating')[LIMIT-1].rating filter_active(period.rating_set.all()).update(domination=F('rating')-benchmark) -# }}} -# {{{ Hall of fame +# Hall of fame print('[%s] Reevaluating hall of fame' % str(datetime.now()), flush=True) for player in Player.objects.all(): ratings = list( @@ -45,7 +44,7 @@ if len(ratings) == 0: continue - # {{{ Collect a list of indices where the domination switches sign (always pick the positive side) + # Collect a list of indices where the domination switches sign (always pick the positive side) inds = set() for i in range(1, len(ratings)): if ratings[i]['domination'] is None or ratings[i-1]['domination'] is None: @@ -57,9 +56,8 @@ if ratings[-1]['domination'] is not None and ratings[-1]['domination'] > 0: inds.add(len(ratings) - 1) inds = sorted(list(inds)) - # }}} - # {{{ Try out combinations of start and end indices to find the optimal choice + # Try out combinations of start and end indices to find the optimal choice dom, init, fin = 0, None, None for i1, i2 in combinations(inds, 2): d = sum([r['domination'] for r in ratings[i1:i2+1] if r['domination'] != None]) @@ -71,10 +69,8 @@ init, _ = min(enumerate(ratings), key=lambda e: e[1]['domination'] or 10000) fin = init dom = ratings[init]['domination'] - # }}} player.dom_val = dom player.dom_start_id = init + FIRST_PERIOD player.dom_end_id = fin + FIRST_PERIOD + 1 player.save() -# }}} diff --git a/aligulac/dump.py b/aligulac/dump.py index d5161be..7ba8a18 100755 --- a/aligulac/dump.py +++ b/aligulac/dump.py @@ -32,7 +32,7 @@ def info(string): dt = datetime.now() -# {{{ Backup and private dump +# Backup and private dump info("Dumping full database.") @@ -47,9 +47,8 @@ def info(string): p_pg = Popen(pg_dump, stdout=subprocess.PIPE) p_gzip = Popen(["gzip"], stdin=p_pg.stdout, stdout=f) p_gzip.communicate() -# }}} -# {{{ Public dump +# Public dump info("Dumping public database.") @@ -65,9 +64,8 @@ def info(string): with open(public_path, 'w') as f: subprocess.call(pub_pg_dump, stdout=f) -# }}} -# {{{ Compress/decompress files +# Compress/decompress files def compress_file(source): info("Compressing {}".format(source)) @@ -81,8 +79,5 @@ def decompress_file(source): with open(source[:-3], "w") as dst: subprocess.call(["gunzip"], stdin=src, stdout=dst) - compress_file(public_path) decompress_file(full_path) - -# }}} diff --git a/aligulac/event_sort.py b/aligulac/event_sort.py index ac44d13..fb289bd 100755 --- a/aligulac/event_sort.py +++ b/aligulac/event_sort.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 -# {{{ Imports +# Imports import os os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'aligulac.settings') @@ -13,7 +13,6 @@ from django.db import connection, transaction from ratings.models import Event -# }}} print('[%s] Refreshing event sort indices' % str(datetime.now()), flush=True) diff --git a/aligulac/period.py b/aligulac/period.py index 2858f01..cc63ca3 100755 --- a/aligulac/period.py +++ b/aligulac/period.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 -# {{{ Imports +# Imports import os os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'aligulac.settings') @@ -42,9 +42,8 @@ filter_active, cdf, ) -# }}} -# {{{ Initialize periods +# Initialize periods try: period = Period.objects.get(id=sys.argv[1]) except: @@ -61,9 +60,8 @@ #sys.exit(1) prev = etn(lambda: Period.objects.get(id=period.id-1)) -# }}} -# {{{ Get players +# Get players players = {} if prev: @@ -89,15 +87,13 @@ 'prev_devs': { 'M': INIT_DEV, 'P': INIT_DEV, 'T': INIT_DEV, 'Z': INIT_DEV }, 'opp_c': [], 'opp_r': [], 'opp_d': [], 'wins': [], 'losses': [], } -# }}} -# {{{ Decay all ratings +# Decay all ratings for p in players.values(): for r in p['prev_devs']: p['prev_devs'][r] = min(sqrt(p['prev_devs'][r]**2 + DECAY_DEV**2), INIT_DEV) -# }}} -# {{{ Collect match information +# Collect match information ngames = 0 for m in Match.objects.filter(period=period).select_related('pla','plb'): @@ -126,11 +122,10 @@ players[m.plb_id]['losses'].append(m.sca * weight) ngames += m.sca + m.scb -# }}} print('[%s] Initialized %i players and %i games' % (str(datetime.now()), len(players), ngames), flush=True) -# {{{ Compute new ratings, devs and performances +# Compute new ratings, devs and performances for p in players.values(): new_ratings, new_devs = update( array( @@ -152,26 +147,23 @@ 'new_devs': { 'M': new_devs[0], 'P': new_devs[1], 'T': new_devs[2], 'Z': new_devs[3] }, 'perfs': { 'M': perfs[0], 'P': perfs[1], 'T': perfs[2], 'Z': perfs[3] }, }) -# }}} -# {{{ Prepare to commit +# Prepare to commit extant_ids = {r.player_id for r in Rating.objects.filter(period=period)} computed_ids = {p['player'].id for p in players.values()} insert_ids = computed_ids - extant_ids update_ids = computed_ids & extant_ids delete_ids = extant_ids - computed_ids -# }}} -# {{{ Delete extant ratings that shouldn't be there +# Delete extant ratings that shouldn't be there Match.objects.filter(rta__period=period, rta__player_id__in=delete_ids).update(rta=None) Match.objects.filter(rtb__period=period, rtb__player_id__in=delete_ids).update(rtb=None) Rating.objects.filter(prev__period=period, prev__player_id__in=delete_ids).update(prev=None) Rating.objects.filter(period=period, player_id__in=delete_ids).delete() -# }}} cur = connection.cursor() -# {{{ Update extant ratings +# Update extant ratings if update_ids: cur.execute('BEGIN') cur.execute( @@ -205,9 +197,8 @@ 'FROM temp_rating AS t WHERE r.player_id=t.player_id AND r.period_id=%i' % period.id ) cur.execute('COMMIT') - # }}} -# {{{ Insert new ratings +# Insert new ratings Rating.objects.bulk_create([Rating( period = period, player = p['player'], @@ -255,9 +246,8 @@ WHERE period_id=%i AND plb_id IN (%s)''' % (period.id, period.id+1, ','.join(str_ids)) ) -# }}} -# {{{ Bookkeeping +# Bookkeeping Match.objects.filter(period=period).update(treated=True) def mean(a): @@ -293,7 +283,6 @@ def mean(a): ) r WHERE rating.id = r.id''' % (period.id, INACTIVE_THRESHOLD) ) -# }}} print( '[%s] Deleted: %i, Updated: %i, Inserted: %i' diff --git a/aligulac/rating.py b/aligulac/rating.py index 825b32a..4983ca1 100644 --- a/aligulac/rating.py +++ b/aligulac/rating.py @@ -216,7 +216,7 @@ def dim(x): myrc = myr[[0]+played_cats_p1] mysc = mys[[0]+played_cats_p1] - # {{{ Objective function + # Objective function def logL(x): Mv = x[0] + extend(x)[loc(oppc)+1] Phi = array([gen_Phi(i,Mv[i]) for i in range(0,M)]) @@ -228,9 +228,8 @@ def logE(x): return sum(log(1 - tanh(alpha*(extend(x)-myrc)/mysc)**2)) logF = lambda x: logL(x) + logE(x) - # }}} - # {{{ Derivative + # Derivative def DlogL(x): Mv = x[0] + extend(x)[loc(oppc)+1] phi = array([gen_phi(i,Mv[i]) for i in range(0,M)]) @@ -244,9 +243,8 @@ def DlogE(x): return ret DlogF = lambda x: DlogL(x) + DlogE(x) - # }}} - # {{{ Hessian + # Hessian def D2logL(x, DM, C): Mv = x[0] + extend(x)[loc(oppc)+1] phi = array([gen_phi(i,Mv[i]) for i in range(0,M)]) @@ -270,7 +268,6 @@ def D2logEx(x): return diag(diags) D2logF = lambda x: D2logL(x,DM,C) + D2logE(x) - # }}} # Prepare initial guess in unrestricted format and maximize x = hstack((myr[0], myr[played_cats_p1]))[0:-1] diff --git a/aligulac/ratings/admin.py b/aligulac/ratings/admin.py index 831ceff..b625324 100644 --- a/aligulac/ratings/admin.py +++ b/aligulac/ratings/admin.py @@ -1,4 +1,4 @@ -# {{{ Imports +# Imports from datetime import datetime from django.contrib import admin diff --git a/aligulac/ratings/comparisons.py b/aligulac/ratings/comparisons.py index 6f94e94..7162ad2 100644 --- a/aligulac/ratings/comparisons.py +++ b/aligulac/ratings/comparisons.py @@ -12,7 +12,7 @@ ratscale ) -# {{{ Metaclass magic! This is not really necessary, but fun! +# Metaclass magic! This is not really necessary, but fun! def cached_properties(cls_name, cls_parents, cls_attrs): """ Creates a class where it caches properties marked with Cached() diff --git a/aligulac/ratings/inference_views.py b/aligulac/ratings/inference_views.py index 5000a84..9d7ddf4 100644 --- a/aligulac/ratings/inference_views.py +++ b/aligulac/ratings/inference_views.py @@ -1,4 +1,4 @@ -# {{{ Imports +# Imports from datetime import date from dateutil.relativedelta import relativedelta from math import log @@ -48,9 +48,8 @@ from simul.formats.sebracket import SEBracket from simul.formats.rrgroup import RRGroup from simul.formats.teampl import TeamPL -# }}} -# {{{ Prediction formats +# Prediction formats FORMATS = [{ 'url': 'match', 'name': _('Best-of-N match'), @@ -88,9 +87,8 @@ 'bo-check': lambda a: a == 1, 'bo-errmsg': _("Expected exactly one 'best of'."), }] -# }}} -# {{{ PredictForm: Form for entering a prediction request. +# PredictForm: Form for entering a prediction request. class PredictForm(forms.Form): format = forms.ChoiceField( choices=[(i, f['name']) for i, f in enumerate(FORMATS)], @@ -101,7 +99,7 @@ class PredictForm(forms.Form): bestof = StrippedCharField(max_length=100, required=True, label=_('Best of'), initial='1') players = forms.CharField(max_length=10000, required=True, label=_('Players'), initial='') - # {{{ Constructor + # Constructor def __init__(self, request=None): self.messages = [] @@ -111,9 +109,8 @@ def __init__(self, request=None): super(PredictForm, self).__init__() self.label_suffix = '' - # }}} - # {{{ Custom validation of bestof and players + # Custom validation of bestof and players def clean_bestof(self): try: ret = [] @@ -156,9 +153,8 @@ def clean_players(self): raise ValidationError(_('One or more errors found in player list.')) return players - # }}} - # {{{ Combined validation of format, bestof and players + # Combined validation of format, bestof and players def clean(self): self.cleaned_data['format'] = min(max(int(self.cleaned_data['format']), 0), len(FORMATS)) fmt = FORMATS[self.cleaned_data['format']] @@ -169,9 +165,8 @@ def clean(self): raise ValidationError(fmt['bo-errmsg']) return self.cleaned_data - # }}} - # {{{ get_messages: Returns a list of messages after validation + # get_messages: Returns a list of messages after validation def get_messages(self): if not self.is_valid(): ret = [] @@ -184,24 +179,21 @@ def get_messages(self): return self.messages + ret return self.messages - # }}} - # {{{ generate_url: Returns an URL to continue to (assumes validation has passed) + # generate_url: Returns an URL to continue to (assumes validation has passed) def generate_url(self): return '/inference/%s/?bo=%s&ps=%s' % ( FORMATS[self.cleaned_data['format']]['url'], '%2C'.join([str(b) for b in self.cleaned_data['bestof']]), '%2C'.join([str(p.id) if p is not None else '0' for p in self.cleaned_data['players']]), ) - # }}} -# }}} -# {{{ SetupForm: Form for getting the bo and player data from GET for each prediction format. +# SetupForm: Form for getting the bo and player data from GET for each prediction format. class SetupForm(forms.Form): bo = forms.CharField(max_length=200, required=True) ps = forms.CharField(max_length=200, required=True) - # {{{ Cleaning methods. NO VALIDATION IS PERFORMED HERE. + # Cleaning methods. NO VALIDATION IS PERFORMED HERE. def clean_bo(self): return [(int(a)+1)//2 for a in self.cleaned_data['bo'].split(',')] @@ -209,10 +201,8 @@ def clean_ps(self): ids = [int(a) for a in self.cleaned_data['ps'].split(',')] players = Player.objects.in_bulk(ids) return [players[id] if id in players else None for id in ids] - # }}} -# }}} -# {{{ group_by: Works the same as itertools.groupby but makes a list. +# group_by: Works the same as itertools.groupby but makes a list. def group_by(lst, key): ret = [(key(lst[0]), [lst[0]])] for e in lst[1:]: @@ -221,9 +211,8 @@ def group_by(lst, key): else: ret[-1][1].append(e) return ret -# }}} -# {{{ predict view +# predict view @cache_page def predict(request): base = base_ctx('Inference', 'Predict', request=request) @@ -238,11 +227,10 @@ def predict(request): if not base['form'].is_valid(): return render_to_response('predict.djhtml', base) return redirect(base['form'].generate_url()) -# }}} -# {{{ Match predictions +# Match predictions -# {{{ MatchPredictionResult +# MatchPredictionResult class MatchPredictionResult: def range(self, i, mn, mx): return min(max(i, mn), mx) @@ -278,14 +266,13 @@ def __init__(self, dbpl=None, bos=None, s1=None, s2=None): def generate_updates(self): return '&'.join(['s1=%s' % self.sca, 's2=%s' % self.scb]) -# }}} -# {{{ Match prediction view +# Match prediction view @cache_page def match(request): base = base_ctx('Inference', 'Predict', request=request) - # {{{ Get data, set up and simulate + # Get data, set up and simulate form = SetupForm(request.GET) if not form.is_valid(): return redirect('/inference/') @@ -296,9 +283,8 @@ def match(request): s1=get_param(request, 's1', 0), s2=get_param(request, 's2', 0), ) - # }}} - # {{{ Postprocessing + # Postprocessing base.update({ 'form': form, 'dbpl': result.dbpl, @@ -321,9 +307,8 @@ def match(request): else: resb = [None] * (len(resa) - len(resb)) + resb base['res'] = list(zip(resa, resb)) - # }}} - # {{{ Scores and other data + # Scores and other data dbpl = result.dbpl thr = date.today() - relativedelta(months=2) pla_matches = dbpl[0].get_matchset() @@ -353,16 +338,12 @@ def match(request): .order_by('-date', 'id'), fix_left=dbpl[0], ) - # }}} postable_match(base, request) return render_to_response('pred_match.djhtml', base) -# }}} -# }}} - -# {{{ Superclass for combination format results +# Superclass for combination format results class CombinationPredictionResult: def range(self, i, mn, mx): return min(max(int(i), mn), mx) @@ -451,11 +432,10 @@ def create_median_matches(self, sim, prefixes, modify=True): def generate_updates(self): return '&'.join('%s=%s' % up for up in self.updates) -# }}} -# {{{ Dual tournament predictions +# Dual tournament predictions -# {{{ DualPredictionResult +# DualPredictionResult class DualPredictionResult(CombinationPredictionResult): def __init__(self, dbpl=None, bos=None, args=None): if dbpl is None: @@ -490,14 +470,13 @@ def __init__(self, dbpl=None, bos=None, args=None): self.matches = self.create_matches(obj, rounds) self.meanres = self.create_median_matches(obj, rounds) -# }}} -# {{{ Dual tournament prediction view +# Dual tournament prediction view @cache_page def dual(request): base = base_ctx('Inference', 'Predict', request=request) - # {{{ Get data, set up and simulate + # Get data, set up and simulate form = SetupForm(request.GET) if not form.is_valid(): return redirect('/inference/') @@ -507,27 +486,22 @@ def dual(request): bos=form.cleaned_data['bo'], args=request.GET, ) - # }}} - # {{{ Post-processing + # Post-processing base.update({ 'table': result.table, 'matches': result.matches, 'meanres': result.meanres, 'form': form, }) - # }}} postable_dual(base, request) return render_to_response('pred_4pswiss.djhtml', base) -# }}} - -# }}} -# {{{ Single elimination predictions +# Single elimination predictions -# {{{ SingleEliminationPredictionResult +# SingleEliminationPredictionResult class SingleEliminationPredictionResult(CombinationPredictionResult): def __init__(self, dbpl=None, bos=None, args=None): if dbpl is None: @@ -566,14 +540,13 @@ def __init__(self, dbpl=None, bos=None, args=None): self.matches = self.create_matches(obj, rounds) self.meanres = self.create_median_matches(obj, rounds) self.nrounds = nrounds -# }}} -# {{{ Single tournament prediction view +# Single tournament prediction view @cache_page def sebracket(request): base = base_ctx('Inference', 'Predict', request=request) - # {{{ Get data, set up and simulate + # Get data, set up and simulate form = SetupForm(request.GET) if not form.is_valid(): return redirect('/inference/') @@ -583,9 +556,8 @@ def sebracket(request): bos=form.cleaned_data['bo'], args=request.GET, ) - # }}} - # {{{ Post-processing + # Post-processing base.update({ 'table': result.table, 'matches': result.matches, @@ -593,18 +565,14 @@ def sebracket(request): 'nrounds': result.nrounds, 'form': form, }) - # }}} postable_sebracket(base, request, group_by(base['meanres'], key=lambda a: a['eventtext'])) return render_to_response('pred_sebracket.djhtml', base) -# }}} - -# }}} -# {{{ Round robin predictions +# Round robin predictions -# {{{ RoundRobinPredictionResult +# RoundRobinPredictionResult class RoundRobinPredictionResult(CombinationPredictionResult): def __init__(self, dbpl=None, bos=None, args=None): if dbpl is None: @@ -653,14 +621,13 @@ def __init__(self, dbpl=None, bos=None, args=None): 'exp_set_wins': p.mtally.exp_sscore()[0], 'exp_set_losses': p.mtally.exp_sscore()[1], } for p in obj.table] -# }}} -# {{{ Round robin group prediction view +# Round robin group prediction view @cache_page def rrgroup(request): base = base_ctx('Inference', 'Predict', request=request) - # {{{ Get data, set up and simulate + # Get data, set up and simulate form = SetupForm(request.GET) if not form.is_valid(): return redirect('/inference/') @@ -670,9 +637,7 @@ def rrgroup(request): bos=form.cleaned_data['bo'], args=request.GET, ) - # }}} - #{{{ Post-processing base.update({ 'table': result.table, 'mtable': result.mtable, @@ -680,18 +645,14 @@ def rrgroup(request): 'meanres': result.meanres, 'form': form, }) - # }}} postable_rrgroup(base, request) return render_to_response('pred_rrgroup.djhtml', base) -# }}} -# }}} +# Proleague predictions -# {{{ Proleague predictions - -# {{{ ProleaguePredictionResult +# ProleaguePredictionResult class ProleaguePredictionResult(CombinationPredictionResult): def __init__(self, dbpl=None, bos=None, args=None): if dbpl is None: @@ -736,14 +697,13 @@ def __init__(self, dbpl=None, bos=None, args=None): self.probb = sum(r['probb'] for r in self.outcomes) self.meanres = self.create_median_matches(obj, [(_('Matches'), prefixes)]) -# }}} -# {{{ Proleage prediction view +# Proleage prediction view @cache_page def proleague(request): base = base_ctx('Inference', 'Predict', request=request) - # {{{ Get data, set up and simulate + # Get data, set up and simulate form = SetupForm(request.GET) if not form.is_valid(): return redirect('/inference/') @@ -753,9 +713,8 @@ def proleague(request): bos=form.cleaned_data['bo'], args=request.GET, ) - # }}} - # {{{ Post-processing + # Post-processing base.update({ 's1': result.s1, 's2': result.s2, @@ -767,18 +726,14 @@ def proleague(request): 'meanres': result.meanres, 'form': form, }) - # }}} postable_proleague(base, request) return render_to_response('pred_proleague.djhtml', base) -# }}} - -# }}} -# {{{ Postables +# Postables -# {{{ Headers and footers +# Headers and footers TL_HEADER = '[center][code]' TL_SEBRACKET_MIDDLE = ( '[/code][/center][b]%(medoutbr)s[/b]\n' @@ -797,9 +752,8 @@ def proleague(request): REDDIT_HEADER = '' REDDIT_FOOTER = '\n\n^(%(estby)s) [^Aligulac](http://aligulac.com/)^. [^%(modify)s](%(modurl)s)^.' -# }}} -# {{{ ordinal: Converts an integer to its ordinal (string) representation +# ordinal: Converts an integer to its ordinal (string) representation def ordinal(value): return str(value) @@ -815,9 +769,8 @@ def ordinal(value): #if value % 100 in (11, 12, 13): #return "%d%s" % (value, suffixes[0]) #return "%d%s" % (value, suffixes[value % 10]) -## }}} -# {{{ left_center_right(strings, gap=2, justify=True, indent=0): Aid for pretty-printing tables +# left_center_right(strings, gap=2, justify=True, indent=0): Aid for pretty-printing tables # Takes a list of triples (strings), each element a line with left, center and right entries. # gap: The number of spaces between columns # justify: If true, makes the left and right columns equally wide @@ -849,9 +802,8 @@ def left_center_right(strings, gap=2, justify=True, indent=0): ) return '\n'.join(out) -# }}} -# {{{ postable_match +# postable_match def postable_match(base, request): pla = base['match'].get_player(0) plb = base['match'].get_player(1) @@ -907,9 +859,8 @@ def postable_match(base, request): 'estby': _('Estimated by'), } ) -# }}} -# {{{ postable_dual +# postable_dual def postable_dual(base, request): numlen = max([len(p['player']['tag']) for p in base['table'] if p['player']['id'] is not None]) @@ -947,9 +898,8 @@ def postable_dual(base, request): 'estby': _('Estimated by'), } ) -# }}} -# {{{ postable_sebracket +# postable_sebracket def postable_sebracket(base, request, bracket): numlen = max([len(p['player']['tag']) for p in base['table'] if p['player']['id'] is not None]) @@ -1000,9 +950,8 @@ def postable_sebracket(base, request, bracket): 'estby': _('Estimated by'), } ) -# }}} -# {{{ create_postable_bracket +# create_postable_bracket def create_postable_bracket(bracket, indent=0): nrounds = len(bracket) @@ -1045,9 +994,8 @@ def create_postable_bracket(bracket, indent=0): postable_result += ' '*indent + ''.join(block[line] for block in result if line < len(block)) + '\n' return postable_result.rstrip() -# }}} -# {{{ postable_rrgroup +# postable_rrgroup def postable_rrgroup(base, request): numlen = max([len(p['player']['tag']) for p in base['table']]) @@ -1081,9 +1029,8 @@ def postable_rrgroup(base, request): 'estby': _('Estimated by'), } ) -# }}} -# {{{ postable_proleague +# postable_proleague def postable_proleague(base, request): numlen = len(str((len(base['matches']) + 1) // 2)) strings = [( @@ -1129,6 +1076,3 @@ def postable_proleague(base, request): 'estby': _('Estimated by'), } ) -# }}} - -# }}} diff --git a/aligulac/ratings/misc_views.py b/aligulac/ratings/misc_views.py index 2396e6e..a55899f 100644 --- a/aligulac/ratings/misc_views.py +++ b/aligulac/ratings/misc_views.py @@ -1,36 +1,29 @@ -# {{{ Imports +# Imports import re from countries.data import cca2_to_ccn -from collections import Counter, namedtuple +from collections import namedtuple from datetime import datetime from django import forms -from django.core.exceptions import PermissionDenied, ValidationError -from django.db.models import F, Q, Sum -from django.http import HttpResponse -from django.shortcuts import get_object_or_404, render_to_response, redirect +from django.core.exceptions import ValidationError +from django.db.models import F, Q +from django.shortcuts import render_to_response, redirect from django.utils.translation import ugettext_lazy as _ -from itertools import zip_longest - from urllib.parse import quote from ratings.comparisons import ( - Comparison, EarningsComparison, FormComparison, MatchComparison, MetaComparison, - PercentageComparison, PredictionComparison, RatingComparison, - SimpleComparison ) from ratings.models import ( Event, Group, - GroupMembership, Match, Player, ) @@ -41,36 +34,30 @@ Message, NotUniquePlayerMessage ) -from ratings.tools import display_matches, find_player, ntz -from ratings.templatetags.ratings_extras import ( - add_sep_and_cur, - ratscale, - ratscalediff, -) -# }}} +from ratings.tools import display_matches, find_player + @cache_page def home(request): ctx = base_ctx('Misc', request=request) ctx["miscpages"] = ( - { "url": "/misc/balance/", - "title": _("Balance Report"), - "desc": _("Charts showing balance in StarCraft II over time.") - }, - { "url": "/misc/days/", - "title": _("Number of days since..."), - "desc": _("Page showing the most recent time some things happened.") - }, - { "url": "/misc/compare/", - "title": _("Compare"), - "desc": _("Tool for comparing players.") - } + {"url": "/misc/balance/", + "title": _("Balance Report"), + "desc": _("Charts showing balance in StarCraft II over time.") + }, + {"url": "/misc/days/", + "title": _("Number of days since..."), + "desc": _("Page showing the most recent time some things happened.") + }, + {"url": "/misc/compare/", + "title": _("Compare"), + "desc": _("Tool for comparing players.") + } ) return render_to_response("misc.djhtml", ctx) -# {{{ Clocks # Format (description, hover_description, queryset, type) Clock = namedtuple('Clock', ['desc', 'alt_desc', 'object', 'type', 'date', 'years', 'days', 'extra']) @@ -248,6 +235,7 @@ def home(request): ) ] + @cache_page def clocks(request): ctx = base_ctx('Misc', 'Days Sinceā€¦', request) @@ -295,10 +283,7 @@ def clocks(request): ctx["clocks"].sort(key=lambda c: c.date, reverse=True) return render_to_response("clocks.djhtml", ctx) -# }}} - -# {{{ Compare players class CompareForm(forms.Form): players = forms.CharField( @@ -307,14 +292,12 @@ class CompareForm(forms.Form): label=_('Players'), initial='') - # {{{ Constructor def __init__(self, request=None): if request is not None: super().__init__(request.GET) else: super().__init__() self.messages = [] - # }}} # Copied from inference_views.PredictForm def clean_players(self): @@ -343,14 +326,13 @@ def clean_players(self): if not ok: raise ValidationError(_('One or more errors found in player list.')) - if len(players) < 2: raise ValidationError(_('Enter at least two players.')) if len(players) > 6: raise ValidationError(_('Enter at most six players.')) return players - # {{{ get_messages: Returns a list of messages after validation + # get_messages: Returns a list of messages after validation def get_messages(self): if not self.is_valid(): ret = [] @@ -363,9 +345,8 @@ def get_messages(self): return self.messages + ret return self.messages - # }}} - # {{{ generate_url: Returns an URL to continue to (assumes validation has passed) + # generate_url: Returns an URL to continue to (assumes validation has passed) def generate_url(self): return '/misc/compare/%s/' % ( ','.join( @@ -373,12 +354,10 @@ def generate_url(self): for p in self.cleaned_data['players'] ), ) - # }}} @cache_page def compare_search(request): - base = base_ctx('Misc', 'Compare', request) if "op" in request.GET: @@ -407,11 +386,12 @@ def compare_search(request): return redirect(form.generate_url()) + @cache_page def compare(request, players): base = base_ctx('Misc', 'Compare', request) - # {{{ Check that we have enough players + # Check that we have enough players if players is None: return redirect('/misc/compare/') @@ -425,14 +405,13 @@ def compare(request, players): except: return redirect('/misc/compare/') - fail_url = ( + fail_url = ( "/misc/compare/?op=edit&players=" + quote('\n'.join(str(x) for x in players)) ) if len(players) < 2 or len(players) > 6: return redirect(fail_url) - # }}} q = Player.objects.filter(id__in=players)\ .prefetch_related('current_rating') @@ -443,14 +422,13 @@ def compare(request, players): idx = players.index(p.id) clean_players[idx] = p - def fmt_url_player(x): if isinstance(x, int): return str(x) else: return x.tag + " " + str(x.id) - edit_url = ( + edit_url = ( "/misc/compare/?op=edit&players=" + quote('\n').join(quote(fmt_url_player(x)) for x in clean_players) ) @@ -561,6 +539,3 @@ def fmt_url_player(x): (('current_rating', lambda x: x.get_totalrating_vt()), _("vT")), (('current_rating', lambda x: x.get_totalrating_vz()), _("vZ")) ) - -# }}} - diff --git a/aligulac/ratings/model_tools.py b/aligulac/ratings/model_tools.py index 77e8f9d..997e501 100644 --- a/aligulac/ratings/model_tools.py +++ b/aligulac/ratings/model_tools.py @@ -2,7 +2,7 @@ from django.db.models.expressions import F, BaseExpression import re -# {{{ +# _swap_regex = re.compile(r"^(sc|pl|rc)(a|b)") def swap_q_object(q): qs = Q(*[_swap_q_child(c) for c in q.children]) diff --git a/aligulac/ratings/models.py b/aligulac/ratings/models.py index acd5d95..e9f4e35 100644 --- a/aligulac/ratings/models.py +++ b/aligulac/ratings/models.py @@ -1,9 +1,8 @@ -# {{{ Imports +# Imports import datetime from itertools import islice from math import sqrt, ceil import random -import re import string from django.contrib.auth.models import User @@ -12,7 +11,6 @@ transaction, ) from django.db.models import ( - F, Max, Min, Q, @@ -35,7 +33,6 @@ data, ) from ratings.model_tools import swap_q_object -# }}} # List of countries # This is used in a couple of models, although it adds a bit of overhead, it would be better to do this @@ -43,47 +40,47 @@ countries = [(code, transformations.cc_to_cn(code)) for code in data.ccn_to_cca2.values()] countries.sort(key=lambda a: a[1]) -# {{{ Various enum-types -TLPD_DB_WOLKOREAN = 0b00001 +# Various enum-types +TLPD_DB_WOLKOREAN = 0b00001 TLPD_DB_WOLINTERNATIONAL = 0b00010 -TLPD_DB_HOTS = 0b00100 -TLPD_DB_HOTSBETA = 0b01000 -TLPD_DB_WOLBETA = 0b10000 +TLPD_DB_HOTS = 0b00100 +TLPD_DB_HOTSBETA = 0b01000 +TLPD_DB_WOLBETA = 0b10000 TLPD_DBS = [ # Translators: TLPD database - (TLPD_DB_WOLBETA, _('WoL Beta')), + (TLPD_DB_WOLBETA, _('WoL Beta')), # Translators: TLPD database - (TLPD_DB_WOLKOREAN, _('WoL Korean')), + (TLPD_DB_WOLKOREAN, _('WoL Korean')), # Translators: TLPD database (TLPD_DB_WOLINTERNATIONAL, _('WoL International')), # Translators: TLPD database - (TLPD_DB_HOTSBETA, _('HotS Beta')), + (TLPD_DB_HOTSBETA, _('HotS Beta')), # Translators: TLPD database - (TLPD_DB_HOTS, _('HotS')), + (TLPD_DB_HOTS, _('HotS')), ] CAT_INDIVIDUAL = 'individual' -CAT_TEAM = 'team' -CAT_FREQUENT = 'frequent' +CAT_TEAM = 'team' +CAT_FREQUENT = 'frequent' EVENT_CATEGORIES = [ # Translators: Event category (CAT_INDIVIDUAL, _('Individual')), # Translators: Event category - (CAT_TEAM, _('Team')), + (CAT_TEAM, _('Team')), # Translators: Event category - (CAT_FREQUENT, _('Frequent')), + (CAT_FREQUENT, _('Frequent')), ] TYPE_CATEGORY = 'category' -TYPE_EVENT = 'event' -TYPE_ROUND = 'round' +TYPE_EVENT = 'event' +TYPE_ROUND = 'round' EVENT_TYPES = [ # Translators: Event type (TYPE_CATEGORY, _('Category')), # Translators: Event type - (TYPE_EVENT, _('Event')), + (TYPE_EVENT, _('Event')), # Translators: Event type - (TYPE_ROUND, _('Round')), + (TYPE_ROUND, _('Round')), ] WCS_YEARS = [ @@ -122,26 +119,26 @@ ]) MRACES = RACES[:-1] -WOL = 'WoL' +WOL = 'WoL' HOTS = 'HotS' LOTV = 'LotV' GAMES = [ - (WOL, _('Wings of Liberty')), + (WOL, _('Wings of Liberty')), (HOTS, _('Heart of the Swarm')), (LOTV, _('Legacy of the Void')), ] -TYPE_INFO = 'info' +TYPE_INFO = 'info' TYPE_WARNING = 'warning' -TYPE_ERROR = 'error' +TYPE_ERROR = 'error' TYPE_SUCCESS = 'success' MESSAGE_TYPES = [ # Translators: Message type - (TYPE_INFO, _('info')), + (TYPE_INFO, _('info')), # Translators: Message type (TYPE_WARNING, _('warning')), # Translators: Message type - (TYPE_ERROR, _('error')), + (TYPE_ERROR, _('error')), # Translators: Message type (TYPE_SUCCESS, _('success')), ] @@ -193,7 +190,7 @@ _('%(player)s switched to %(race)s after game %(num)s.')), (_('Smurf'), '%(player)s was smurfing for %(otherplayer)s.', _('%(player)s was smurfing for %(otherplayer)s.')), - (_('Smurf'), + (_('Smurf'), '%(player)s was smurfing as %(otherplayer)s.', _('%(player)s was smurfing as %(otherplayer)s.')), (_('Smurf'), '%(player)s was smurfing as %(otherplayer)s and was disqualified due to residency rules.', @@ -243,7 +240,7 @@ (_('Seed'), '%(player)s was seeded.', _('%(player)s was seededs.')), (_('Seeds'), '%(players)s and %(player)s were seeded.', _('%(players)s and %(player)s were seeded.')), (_('Draw'), - 'Game %(num)s was a draw and had to be replayed.', + 'Game %(num)s was a draw and had to be replayed.', _('Game %(num)s was a draw and had to be replayed.')), ] MESSAGES = list(map(lambda m: (m[1], m[2]), MESSAGES_SRC)) @@ -253,7 +250,7 @@ STORIES = [ ('%(player)s wins %(event)s', _('%(player)s wins %(event)s')), - ('%(player)s defeats %(opponent)s and wins %(event)s', + ('%(player)s defeats %(opponent)s and wins %(event)s', _('%(player)s defeats %(opponent)s and wins %(event)s')), ('%(player)s wins %(event)s as a royal roader', _('%(player)s wins %(event)s as a royal roader')), ('%(player)s defeats %(opponent)s and wins %(event)s as a royal roader', @@ -283,14 +280,12 @@ ] STORIES_DICT = dict(STORIES) STORIES_IDX = list(map(lambda m: m[0], STORIES)) -# }}} -# {{{ Periods + class Period(models.Model): class Meta: db_table = 'period' - # {{{ Fields start = models.DateField( 'Start date', null=False, db_index=True, help_text='Start date' @@ -328,26 +323,20 @@ class Meta: 'Zerg OP value', null=True, help_text='Zerg OP value' ) - # }}} - # {{{ String representation def __str__(self): return 'Period #' + str(self.id) + ': ' + str(self.start) + ' to ' + str(self.end) - # }}} - # {{{ is_preview: Checks whether this period is still a preview def is_preview(self): + "Checks whether this period is still a preview" return self.end >= datetime.date.today() - # }}} -# }}} -# {{{ Events + class Event(models.Model): class Meta: ordering = ['idx', 'latest', 'fullname'] db_table = 'event' - # {{{ Fields name = models.CharField( 'Name', max_length=100, help_text='Event name' @@ -380,7 +369,7 @@ class Meta: # tlpd_db contains information in binary form on which TLPD databases to use: # 1 for Korean, 10 for International, 100 for HotS, 1000 for Hots beta, 10000 for WoL beta - # So a value of 5 (00101 in binary) would correspond to a link to the Korean and HotS TLPD. + # So a value of 5 (00101 in binary) would correspond to a link to the Korean and HotS TLPD. # Use bitwise AND (&) with the flags to check. tlpd_id = models.IntegerField( 'TLPD ID', blank=True, null=True, @@ -422,41 +411,35 @@ class Meta: wcs_year = models.IntegerField('WCS year', blank=True, null=True, choices=WCS_YEARS) wcs_tier = models.IntegerField('WCS tier', blank=True, null=True, choices=WCS_TIERS) - # }}} - # {{{ open_events: Not used... is this useful? + # Not used... is this useful? @staticmethod def open_events(): qset = ( Event.objects.filter(closed=False) - .exclude(downlink__distance__gt=0) - .order_by('idx', 'fullname') - .values('id', 'fullname') + .exclude(downlink__distance__gt=0) + .order_by('idx', 'fullname') + .values('id', 'fullname') ) for e in qset: yield (e['id'], e['fullname']) - # }}} - # {{{ String representation def __str__(self): return self.fullname - # }}} - # {{{ get_parent(): Returns the parent, or null def get_parent(self): + "Returns the parent, or null" try: return self.uplink.get(distance=1).parent except: return None - # }}} - - # {{{ get_ancestors(id=False): Returns a queryset/list containing the - # ancestors sorted by distance. - # If id=True, the queryset/list contains the object itself. - # - # get_ancestors_list is preferred if no modifications to the queryset is - # needed as it gets a performance boost from prefetch_related + def get_ancestors(self, id=False): + """Returns a queryset/list containing the ancestors sorted by distance. + If id=True, the queryset/list contains the object itself. + + get_ancestors_list is preferred if no modifications to the queryset is + needed as it gets a performance boost from prefetch_related""" q = Event.objects.filter(downlink__child=self) if not id: q = q.filter(downlink__distance__gt=0) @@ -470,48 +453,43 @@ def get_ancestors_list(self, id=False): ] results.sort(key=lambda link: -link.distance) return [link.parent for link in results] - # }}} - # {{{ get_ancestors_print: Returns a list containing the printable ancestors def get_ancestors_print(self, id=True): + "Returns a list containing the printable ancestors" return [event for event in self.get_ancestors_list(id) if not event.noprint] - # }}} - # {{{ get_ancestors_event: Returns a list containing printable ancestors of type event or category def get_ancestors_event(self): + """Returns a list containing printable ancestors of type event or + category""" return [ x for x in self.get_ancestors_list(id=True) if x.type in (TYPE_CATEGORY, TYPE_EVENT) ] - # }}} - # {{{ get_root: Returns the farthest removed ancestor def get_root(self): + "Returns the farthest removed ancestor" return self.get_ancestors_list(id=True)[0] - # }}} - # {{{ get_children(types=[category,event,round], id=False): Returns a queryset containing the children - # of this event, with the matching criteria def get_children(self, types=[TYPE_CATEGORY, TYPE_EVENT, TYPE_ROUND], id=False): + """Returns a queryset containing the children of this event, with the + matching criteria""" if not id: qset = Event.objects.filter(uplink__parent=self, uplink__distance__gt=0) else: qset = Event.objects.filter(uplink__parent=self) return qset.filter(type__in=types) - # }}} - # {{{ get_immediate_children: Returns a queryset of immediate children def get_immediate_children(self): + "Returns a queryset of immediate children" return Event.objects.filter(uplink__parent=self, uplink__distance=1) - # }}} - # {{{ has_children: Returns true if this event has children, false if not def has_children(self): + "Returns true if this event has children, false if not" return self.downlink.filter(distance__gt=0).exists() - # }}} - # {{{ update_name: Refreshes the fullname field (must be called after changing name of ancestors) def update_name(self, newname=None): + """Refreshes the fullname field (must be called after changing name of + ancestors)""" if newname is not None: self.name = newname self.save() @@ -519,65 +497,56 @@ def update_name(self, newname=None): ancestors = self.get_ancestors_print() self.fullname = ' '.join([e.name for e in ancestors]) self.save() - # }}} - # {{{ get_event_fullname: Returns the fullname of the nearest ancestor of type event or category - # This is not cached and will query the DB! def get_event_fullname(self): + """Returns the fullname of the nearest ancestor of type event or + category. This is not cached and will query the DB!""" return self.get_ancestors_event()[-1].fullname - # }}} - # {{{ get_event: Returns the nearest ancestor of type event or category def get_event_event(self): + "Returns the nearest ancestor of type event or category" return self.get_ancestors_event()[-1] - # }}} - - # {{{ get_homepage: Returns the URL if one can be found, None otherwise - # This is not cached and will query the DB! + def get_homepage(self): + """Returns the URL if one can be found, None otherwise. This is not + cached and will query the DB!""" try: return self.get_ancestors(id=True).filter(homepage__isnull=False).last().homepage except: return None - # }}} - # {{{ get_lp_name: Returns the Liquipedia title if one can be found, None otherwise - # This is not cached and will query the DB! def get_lp_name(self): + """Returns the Liquipedia title if one can be found, None otherwise. + This is not cached and will query the DB!""" try: return self.get_ancestors(id=True).filter(lp_name__isnull=False).last().lp_name except: return None - # }}} - # {{{ get_tl_thread: Returns the ID of the TL thread if one can be found, None otherwise + # get_tl_thread: Returns the ID of the TL thread if one can be found, None otherwise def get_tl_thread(self): try: return self.get_ancestors(id=True).filter(tl_thread__isnull=False).last().tl_thread except: return None - # }}} - # {{{ get_matchset: Returns a queryset of matches + # get_matchset: Returns a queryset of matches def get_matchset(self): return Match.objects.filter(eventobj__uplink__parent=self) - # }}} - # {{{ get_immediate_matchset: Returns a queryset of matches attached to this event only. (May be faster + # get_immediate_matchset: Returns a queryset of matches attached to this event only. (May be faster # leaves.) def get_immediate_matchset(self): return self.match_set.all() - # }}} - # {{{ update_dates: Updates the fields earliest and latest + # update_dates: Updates the fields earliest and latest def update_dates(self): res = self.get_matchset().aggregate(Max('date'), Min('date')) self.latest = res['date__max'] self.earliest = res['date__min'] self.save() - # }}} - # {{{ change_type(type): Modifies the type of this event, and possibly all ancestors and events + # change_type(type): Modifies the type of this event, and possibly all ancestors and events @transaction.atomic def change_type(self, tp): # If EVENT or ROUND, children must be ROUND @@ -590,9 +559,8 @@ def change_type(self, tp): self.type = tp self.save() - # }}} - # {{{ Standard setters + # Standard setters def set_big(self, big): self.big = big self.save() @@ -632,9 +600,8 @@ def set_latest(self, date): def set_idx(self, idx): self.idx = idx self.save() - # }}} - # {{{ add_child(name, type, noprint=False, closed=False): Adds a new child to the right of all existing + # add_child(name, type, noprint=False, closed=False): Adds a new child to the right of all existing # children @transaction.atomic def add_child(self, name, type, big=False, noprint=False): @@ -643,7 +610,7 @@ def add_child(self, name, type, big=False, noprint=False): new.save() links = [ - EventAdjacency(parent_id=l.parent_id, child=new, distance=l.distance+1) + EventAdjacency(parent_id=l.parent_id, child=new, distance=l.distance+1) for l in self.uplink.all() ] EventAdjacency.objects.bulk_create(links) @@ -653,9 +620,8 @@ def add_child(self, name, type, big=False, noprint=False): new.change_type(type) return new - # }}} - # {{{ add_root(name, type, big=False, noprint=False): Adds a new root node + # add_root(name, type, big=False, noprint=False): Adds a new root node @staticmethod @transaction.atomic def add_root(name, type, big=False, noprint=False): @@ -669,43 +635,32 @@ def add_root(name, type, big=False, noprint=False): new.change_type(type) return new - # }}} - # {{{ close: Closes this event and all children - def close(self): - self.get_children(id=True).update(closed=True) - # }}} - - # {{{ open: Opens this event and all ancestors + # open: Opens this event and all ancestors def open(self): self.get_ancestors(id=True).update(closed=False) - # }}} - # {{{ delete_earnings(ranked=True): Deletes earnings objects associated to this event fulfilling the + # delete_earnings(ranked=True): Deletes earnings objects associated to this event fulfilling the # criteria. def delete_earnings(self, ranked=True): if ranked: Earnings.objects.filter(event=self).exclude(placement__exact=0).delete() else: Earnings.objects.filter(event=self, placement__exact=0).delete() - # }}} - # {{{ move_earnings(new_event): Moves earnings from this event to the new event + # move_earnings(new_event): Moves earnings from this event to the new event # Will update the type of the new event to EVENT. def move_earnings(self, new_event): Earnings.objects.filter(event=self).update(event=new_event) self.set_prizepool(None) new_event.set_prizepool(True) new_event.change_type(Event.EVENT) - # }}} - # {{{ delete_points: Deletes WCS points objects associated with this event + # delete_points: Deletes WCS points objects associated with this event def delete_points(self): WCSPoints.objects.filter(event=self).delete() - # }}} -# }}} -# {{{ EventAdjacencies + class EventAdjacency(models.Model): class Meta: db_table = 'eventadjacency' @@ -714,19 +669,16 @@ class Meta: child = models.ForeignKey(Event, null=False, db_index=True, related_name='uplink') distance = models.IntegerField(null=True, default=None) - # {{{ String representation def __str__(self): return str(self.parent) + ' -> ' + str(self.child) + ' (' + str(self.distance) + ')' - # }}} -# }}} -# {{{ Players + class Player(models.Model): class Meta: ordering = ['tag'] db_table = 'player' - # {{{ Fields + # Fields tag = models.CharField( 'In-game name', max_length=30, null=False, db_index=True, help_text='Player tag' @@ -750,7 +702,7 @@ class Meta: # tlpd_db contains information in binary form on which TLPD databases to use: # 1 for Korean, 10 for International, 100 for HotS, 1000 for Hots beta, 10000 for WoL beta - # So a value of 5 (00101 in binary) would correspond to a link to the Korean and HotS TLPD. + # So a value of 5 (00101 in binary) would correspond to a link to the Korean and HotS TLPD. # Use bitwise AND (&) with the flags to check. tlpd_id = models.IntegerField( 'TLPD ID', blank=True, null=True, @@ -798,17 +750,15 @@ class Meta: Period, blank=True, null=True, related_name='player_dom_end', help_text='End of domination period' ) - # }}} - # {{{ String representation + # String representation def __str__(self): - if self.country != None and self.country != '': + if self.country is not None and self.country != '': return self.tag + ' (' + self.race + ', ' + self.country + ')' else: return self.tag + ' (' + self.race + ')' - # }}} - # {{{ Standard setters + # Standard setters def set_tag(self, tag): self.tag = tag self.save() @@ -816,11 +766,11 @@ def set_tag(self, tag): def set_race(self, race): self.race = race self.save() - + def set_country(self, country): self.country = country self.save() - + def set_name(self, name): self.name = None if name == '' else name self.save() @@ -828,7 +778,7 @@ def set_name(self, name): def set_romanized_name(self, name): self.romanized_name = None if name == '' else name self.save() - + def set_birthday(self, birthday): self.birthday = None if birthday == '' else birthday self.save() @@ -848,9 +798,8 @@ def set_sc2e_id(self, sc2e_id): def set_lp_name(self, lp_name): self.lp_name = None if lp_name == '' else lp_name self.save() - # }}} - # {{{ Adding and removing TLPD databases + # Adding and removing TLPD databases def add_tlpd_db(self, tlpd_db): self.tlpd_db |= tlpd_db self.save() @@ -859,12 +808,7 @@ def remove_tlpd_db(self, tlpd_db): self.tlpd_db -= self.tlpd_db & tlpd_db self.save() - def set_tlpd_db(self, tlpd_db): - self.tlpd_db = tlpd_db - self.save() - # }}} - - # {{{ set_aliases: Set aliases + # set_aliases: Set aliases # Input: An array of string aliases, which are compared to existing aliases. # New ones are added, existing superfluous ones are removed. Returns True if something changed. def set_aliases(self, aliases): @@ -893,23 +837,20 @@ def set_aliases(self, aliases): old.delete() return True return False - # }}} - # {{{ get_aliases: Returns all aliases as a list + # get_aliases: Returns all aliases as a list def get_aliases(self): return [a.name for a in self.alias_set.all()] - # }}} - # {{{ get_current_teammembership: Gets the current team membership object of this player, if any. + # get_current_teammembership: Gets the current team membership object of this player, if any. def get_current_teammembership(self): try: groups = self.groupmembership_set.all() return next(x for x in groups if x.group.is_team and x.current) except: return None - # }}} - # {{{ get_current_team: Gets the current team object of this player, if any. + # get_current_team: Gets the current team object of this player, if any. def get_current_team(self): try: return ( @@ -920,9 +861,8 @@ def get_current_team(self): ) except: return None - # }}} - # {{{ get_current_rating: Gets the current rating, if any. + # get_current_rating: Gets the current rating, if any. def get_current_rating(self): try: return ( @@ -932,22 +872,19 @@ def get_current_rating(self): ) except: return None - # }}} - # {{{ get_latest_rating_update: Gets the latest rating of this player with decay zero, or None. + # get_latest_rating_update: Gets the latest rating of this player with decay zero, or None. def get_latest_rating_update(self): try: return self.rating_set.filter(decay=0).latest('period') except: return None - # }}} - # {{{ has_earnings: Checks whether the player has any earnings. + # has_earnings: Checks whether the player has any earnings. def has_earnings(self): return self.earnings_set.exists() - # }}} - # {{{ get_matchset: Returns a queryset of all this player's matches. + # get_matchset: Returns a queryset of all this player's matches. def get_matchset(self, related=[]): qset = Match.objects.filter(Q(pla=self) | Q(plb=self)) @@ -956,20 +893,19 @@ def get_matchset(self, related=[]): qset = qset.prefetch_related('message_set') return qset.order_by('-date', '-id') - # }}} - # {{{ get_rank: Calculates the rank for the player with country as filter + # get_rank: Calculates the rank for the player with country as filter def get_rank(self, country=''): if '_ranks' not in dir(self): self._ranks = dict() if country in self._ranks: return self._ranks[country] - q = Rating.objects.filter(period=self.current_rating.period, - rating__gt=self.current_rating.rating, - decay__lt=INACTIVE_THRESHOLD)\ - .exclude(player=self) - + q = (Rating.objects.filter(period=self.current_rating.period, + rating__gt=self.current_rating.rating, + decay__lt=INACTIVE_THRESHOLD) + .exclude(player=self)) + if country == "foreigners": q = q.exclude(player__country='KR') elif country != '': @@ -1007,10 +943,6 @@ def foreigner_rank(self): def foreigner_rank_page(self): return self.rank_page('foreigner_rank') - # }}} - - - # {{{ rivalries @property def rivals(self): if '_rivals' in dir(self): @@ -1060,59 +992,54 @@ def _nemesis_victim_helper(self): def rivals_pretty(self): return ', '.join(str(x) for x in self.rivals) - # }}} PLAYER_RIVAL_QUERY = """ -SELECT "player"."id", "player"."country", "player"."tag", "player"."race", Count(T2."plid") AS "matches" -FROM player +SELECT "player"."id", "player"."country", "player"."tag", "player"."race", Count(T2."plid") AS "matches" +FROM player JOIN ( - SELECT "player"."id" AS "plid", "match"."id" AS "mid" - FROM player JOIN match ON - ("player"."id" = "match"."pla_id" OR "player"."id" = "match"."plb_id") - WHERE ("match"."pla_id" = %(id)s OR "match"."plb_id" = %(id)s) AND "player"."id" != %(id)s - ) T2 -ON "player"."id" = T2."plid" + SELECT "player"."id" AS "plid", "match"."id" AS "mid" + FROM player JOIN match ON + ("player"."id" = "match"."pla_id" OR "player"."id" = "match"."plb_id") + WHERE ("match"."pla_id" = %(id)s OR "match"."plb_id" = %(id)s) AND "player"."id" != %(id)s + ) T2 +ON "player"."id" = T2."plid" GROUP BY "player"."id", "player"."country", "player"."tag", "player"."race" ORDER BY "matches" DESC LIMIT 5;""" PLAYER_PM_QUERY = """ -SELECT "player"."id", "player"."country", "player"."tag", "player"."race", +SELECT "player"."id", "player"."country", "player"."tag", "player"."race", Sum(T2."for") - Sum(T2."against") AS "pm" FROM player JOIN ( - SELECT - "player"."id" AS "plid", - "match"."id" AS "mid", - (CASE - WHEN "player"."id" = "match"."pla_id" THEN - "match"."scb" - ELSE - "match"."sca" - END - ) AS "for", - (CASE - WHEN "player"."id" = "match"."pla_id" THEN - "match"."sca" - ELSE - "match"."scb" - END - ) AS "against", - "match"."sca" AS "sca", - "match"."scb" AS "scb", - "match"."pla_id", - "match"."plb_id" - FROM player JOIN match ON - ("player"."id" = "match"."pla_id" OR "player"."id" = "match"."plb_id") + SELECT + "player"."id" AS "plid", + "match"."id" AS "mid", + (CASE WHEN "player"."id" = "match"."pla_id" THEN + "match"."scb" + ELSE + "match"."sca" + END + ) AS "for", + (CASE WHEN "player"."id" = "match"."pla_id" THEN + "match"."sca" + ELSE + "match"."scb" + END + ) AS "against", + "match"."sca" AS "sca", + "match"."scb" AS "scb", + "match"."pla_id", + "match"."plb_id" + FROM player JOIN match ON + ("player"."id" = "match"."pla_id" OR "player"."id" = "match"."plb_id") WHERE ("match"."pla_id" = %(id)s OR "match"."plb_id" = %(id)s) AND "player"."id" != %(id)s - ) T2 - ON "player"."id" = T2."plid" + ) T2 + ON "player"."id" = T2."plid" GROUP BY "player"."id", "player"."country", "player"."tag", "player"."race" ORDER BY "pm" DESC; """ -# }}} -# {{{ Stories class Story(models.Model): class Meta: db_table = 'story' @@ -1129,7 +1056,6 @@ class Meta: def __str__(self): try: - params = self.get_param_dict() return STORIES_DICT[self.message] % self.get_param_dict() except: return '[[[Error]]]' @@ -1152,18 +1078,17 @@ def get_param_dict(self): def verify(self): try: - _ = self.message % self.get_param_dict() + self.message % self.get_param_dict() return True except: return False -# }}} -# {{{ Groups + class Group(models.Model): class Meta: db_table = 'group' - # {{{ Fields + # Fields name = models.CharField( 'Name', max_length=100, null=False, db_index=True, help_text='Team name' @@ -1208,18 +1133,16 @@ class Meta: is_team = models.BooleanField('Team', null=False, default=True, db_index=True) is_manual = models.BooleanField('Manual entry', null=False, default=True) - # }}} - # {{{ String representation + # String representation def __str__(self): return self.name - # }}} - # {{{ Standard setters + # Standard setters def set_name(self, name): self.name = name self.save() - + def set_shortname(self, shortname): self.shortname = None if shortname == '' else shortname self.save() @@ -1227,13 +1150,12 @@ def set_shortname(self, shortname): def set_homepage(self, homepage): self.homepage = None if homepage == '' else homepage self.save() - + def set_lp_name(self, lp_name): self.lp_name = None if lp_name == '' else lp_name - self.save() - # }}} - - # {{{ set_aliases: Set aliases + self.save() + + # set_aliases: Set aliases # Input: An array of string aliases, which are compared to existing aliases. # New ones are added, existing superfluous ones are removed. def set_aliases(self, aliases): @@ -1253,14 +1175,12 @@ def set_aliases(self, aliases): else: Alias.objects.filter(group=self).delete() - # }}} - # {{{ get_aliases: Returns all aliases as a list + # get_aliases: Returns all aliases as a list def get_aliases(self): return [a.name for a in self.alias_set.all()] - # }}} - # {{{ get_rank: Calculates the rank for the team given a metric + # get_rank: Calculates the rank for the team given a metric def get_rank(self, rank_type): if rank_type not in {"scoreak", "scorepl", "meanrating"}: raise Exception() @@ -1314,11 +1234,8 @@ def ranks(self): def has_ranks(self): return self.ak_rank or self.pl_rank or self.rating_rank - # }}} - -# }}} -# {{{ GroupMemberships +# GroupMemberships class GroupMembership(models.Model): class Meta: db_table = 'groupmembership' @@ -1330,17 +1247,15 @@ class Meta: end = models.DateField('Date left', blank=True, null=True) current = models.BooleanField('Current', default=True, null=False, db_index=True) playing = models.BooleanField('Playing', default=True, null=False, db_index=True) - - # {{{ String representation + + # String representation def __str__(self): return ( - 'Player: %s Group: %s (%s - %s)' % + 'Player: %s Group: %s (%s - %s)' % (self.player.tag, self.group.name, str(self.start), str(self.end)) ) - # }}} -# }}} -# {{{ Aliases + class Alias(models.Model): class Meta: verbose_name_plural = 'aliases' @@ -1350,16 +1265,15 @@ class Meta: player = models.ForeignKey(Player, null=True) group = models.ForeignKey(Group, null=True) - # {{{ String representation + # String representation def __str__(self): return self.name - # }}} def save(self, *args, **kwargs): self.name = self.name.strip() super().save(*args, **kwargs) - # {{{ Standard adders + # Standard adders @staticmethod def add_player_alias(player, name): new = Alias(player=player, name=name) @@ -1369,10 +1283,7 @@ def add_player_alias(player, name): def add_group_alias(group, name): new = Alias(group=group, name=name) new.save() - # }}} -# }}} -# {{{ Matches # This can operate on querysets in the current dev branch # of Django. Worth noting for the future. So currently it @@ -1390,6 +1301,7 @@ def symmetric_filter(self, *args, **kwargs): swapped = swap_q_object(q) return super().filter(q | swapped) + class Match(models.Model): class Meta: verbose_name_plural = 'matches' @@ -1397,7 +1309,7 @@ class Meta: objects = MatchManager() - # {{{ Fields + # Fields period = models.ForeignKey( Period, null=False, help_text='Period in which the match was played' @@ -1464,66 +1376,61 @@ class Meta: 'Rating', related_name='rtb', verbose_name='Rating B', null=True, help_text='Rating for player B at the time the match was played' ) - # }}} - # {{{ populate_orig: Populates the original data fields, to check later if anything changed. + # populate_orig: Populates the original data fields, to check later if anything changed. def populate_orig(self): if self.pk: try: - self.orig_pla = self.pla_id - self.orig_plb = self.plb_id - self.orig_rca = self.rca - self.orig_rcb = self.rcb - self.orig_sca = self.sca - self.orig_scb = self.scb - self.orig_date = self.date + self.orig_pla = self.pla_id + self.orig_plb = self.plb_id + self.orig_rca = self.rca + self.orig_rcb = self.rcb + self.orig_sca = self.sca + self.orig_scb = self.scb + self.orig_date = self.date self.orig_period = self.period_id except: - self.orig_pla = None - self.orig_plb = None - self.orig_rca = None - self.orig_rcb = None - self.orig_sca = None - self.orig_scb = None - self.orig_date = None + self.orig_pla = None + self.orig_plb = None + self.orig_rca = None + self.orig_rcb = None + self.orig_sca = None + self.orig_scb = None + self.orig_date = None self.orig_period = None else: - self.orig_pla = None - self.orig_plb = None - self.orig_rca = None - self.orig_rcb = None - self.orig_sca = None - self.orig_scb = None - self.orig_date = None + self.orig_pla = None + self.orig_plb = None + self.orig_rca = None + self.orig_rcb = None + self.orig_sca = None + self.orig_scb = None + self.orig_date = None self.orig_period = None - # }}} - # {{{ changed_effect: Returns true if an effective change (requiring recomputation) has been made. + # changed_effect: Returns true if an effective change (requiring recomputation) has been made. def changed_effect(self): - return ( - self.orig_pla != self.pla_id or self.orig_plb != self.plb_id - or self.orig_rca != self.rca or self.orig_rcb != self.rcb - or self.orig_sca != self.sca or self.orig_scb != self.scb - ) - # }}} - - # {{{ changed_date: Returns true if the date has been changed. + return (self.orig_pla != self.pla_id or + self.orig_plb != self.plb_id or + self.orig_rca != self.rca or + self.orig_rcb != self.rcb or + self.orig_sca != self.sca or + self.orig_scb != self.scb) + + # changed_date: Returns true if the date has been changed. def changed_date(self): return self.orig_date != self.date - # }}} - # {{{ changed_period: Returns true if the period has been changed. + # changed_period: Returns true if the period has been changed. def changed_period(self): return self.orig_period != self.period_id - # }}} - # {{{ __init__: Has been overloaded to call populate_orig. + # __init__: Has been overloaded to call populate_orig. def __init__(self, *args, **kwargs): super(Match, self).__init__(*args, **kwargs) self.populate_orig() - # }}} - # {{{ save: Has been overloaded to check for effective changes, flagging a period as needing recomputation + # save: Has been overloaded to check for effective changes, flagging a period as needing recomputation # if necessary. def save(self, force_insert=False, force_update=False, *args, **kwargs): # Check if the date have been changed. If it has, move to a different period if necessary. @@ -1562,30 +1469,27 @@ def save(self, force_insert=False, force_update=False, *args, **kwargs): event.set_earliest(self.date) if event.latest is None or self.date > event.latest: event.set_latest(self.date) - # }}} - # {{{ delete: Has been overloaded to check for effective changes, flagging a period as needing + # delete: Has been overloaded to check for effective changes, flagging a period as needing # recomputation if necessary. - def delete(self, *args, **kwargs): + def delete(self, *args, **kwargs): self.period.needs_recompute = True self.period.save() eventobj = self.eventobj super(Match, self).delete(*args, **kwargs) - # This is very slow if used for many matches, but that should rarely happen. + # This is very slow if used for many matches, but that should rarely happen. if eventobj: for event in self.eventobj.get_ancestors(id=True): event.update_dates() - # }}} - # {{{ set_period: Sets the correct period for this match depending on the date. + # set_period: Sets the correct period for this match depending on the date. def set_period(self): pers = Period.objects.filter(start__lte=self.date).filter(end__gte=self.date) self.period = pers[0] - # }}} - # {{{ set_ratings: Sets the ratings of the players if they exist. + # set_ratings: Sets the ratings of the players if they exist. def set_ratings(self): try: self.rta = Rating.objects.get(player=self.pla, period_id=self.period_id-1) @@ -1596,17 +1500,15 @@ def set_ratings(self): self.rtb = Rating.objects.get(player=self.plb, period_id=self.period_id-1) except: self.rtb = None - # }}} - # {{{ set_date(date): Exactly what it says on the tin. + # set_date(date): Exactly what it says on the tin. def set_date(self, date): self.date = date self.save() - # }}} - # {{{ set_event(event): Updates the earliest and latest fields for both new and old event. + # set_event(event): Updates the earliest and latest fields for both new and old event. def set_event(self, event): - old = self.eventobj + oldevent = self.eventobj self.eventobj = event self.save() @@ -1620,55 +1522,46 @@ def set_event(self, event): if oldevent: for event in oldevent.get_ancestors(id=True): event.update_dates() - # }}} - # {{{ String representation + # String representation def __str__(self): return '%s %s %s - %s %s' % (str(self.date), self.pla.tag, self.sca, self.scb, self.plb.tag) - # }}} - # {{{ get_winner: Returns the winner of this match, or None if tie. + # get_winner: Returns the winner of this match, or None if tie. def get_winner(self): if self.sca > self.scb: return self.pla elif self.scb > self.sca: return self.plb return None - # }}} - # {{{ get_winner_id + # get_winner_id def get_winner_id(self): if self.sca > self.scb: return self.pla_id elif self.scb > self.sca: return self.plb_id return None - # }}} - # {{{ get_winner_score: Returns the score of the winner. + # get_winner_score: Returns the score of the winner. def get_winner_score(self): return max(self.sca, self.scb) - # }}} - # {{{ get_loser_score: Returns the score of the loser. + # get_loser_score: Returns the score of the loser. def get_loser_score(self): return min(self.sca, self.scb) - # }}} - # {{{ event_fullpath: Returns the full event name, taken from event object if available, or event text if + # event_fullpath: Returns the full event name, taken from event object if available, or event text if # not. Can be None. def event_fullpath(self): return self.event if self.eventobj is None else self.eventobj.fullname - # }}} - # {{{ event_partpath: Returns the partial event name (up to the nearest non-ROUND ancestor), taken from + # event_partpath: Returns the partial event name (up to the nearest non-ROUND ancestor), taken from # event object if available, or event text if not. Can be None. def event_partpath(self): return self.event if self.eventobj is None else self.eventobj.get_event_fullname() - # }}} -# }}} -# {{{ Messages + class Message(models.Model): class Meta: db_table = 'message' @@ -1686,7 +1579,6 @@ class Meta: def __str__(self): try: - params = self.get_param_dict() return MESSAGES_DICT[self.message] % self.get_param_dict() except: return _('Error') @@ -1715,19 +1607,18 @@ def get_param_dict(self): def verify(self): try: - _ = self.message % self.get_param_dict() + self.message % self.get_param_dict() return True except: return False -# }}} -# {{{ WCS points + class WCSPoints(models.Model): class Meta: db_table = 'wcspoints' ordering = ['-points'] - # {{{ Fields + # Fields event = models.ForeignKey( Event, verbose_name='Event', null=False, help_text='Event in which these WCS points was awarded' @@ -1738,9 +1629,8 @@ class Meta: ) points = models.IntegerField('Points', null=False, help_text='Number of points awarded') placement = models.IntegerField('Place', help_text='Placement') - # }}} - # {{{ set_points(event, entries): Sets WCS points for a given event + # set_points(event, entries): Sets WCS points for a given event # Payouts is a list of dicts with keys 'player', 'points' and 'placement'. # TODO: Probably should be more subtle and not delete everything on change @staticmethod @@ -1757,16 +1647,14 @@ def set_points(event, entries): points=entry['points'], ) new.save() - # }}} -# }}} -# {{{ Earnings + class Earnings(models.Model): class Meta: db_table = 'earnings' ordering = ['-earnings'] - # {{{ Fields + # Fields event = models.ForeignKey( Event, verbose_name='Event', null=False, help_text='Event in which this prize was awarded' @@ -1782,7 +1670,7 @@ class Meta: origearnings = models.DecimalField( 'Earnings (original currency)', help_text='Prize money in original currency', - decimal_places=8, # Bitcoin uses 8 places + decimal_places=8, # Bitcoin uses 8 places max_digits=12+8 ) currency = models.CharField( @@ -1793,9 +1681,8 @@ class Meta: 'Place', help_text='Placement' ) - # }}} - # {{{ set_earnings(event, payouts, currency): Sets earnings for a given event. + # set_earnings(event, payouts, currency): Sets earnings for a given event. # Payouts is a list of dicts with keys 'player', 'prize' and 'placement'. # TODO: Probably should be more subtle and not delete everything on change @staticmethod @@ -1817,9 +1704,8 @@ def set_earnings(event, payouts, currency, ranked): Earnings.convert_earnings(event) event.set_prizepool(True) - # }}} - # {{{ convert_earnings(event): Performs currency conversion for all earnings associated to an event. + # convert_earnings(event): Performs currency conversion for all earnings associated to an event. @staticmethod def convert_earnings(event): earningobjs = Earnings.objects.filter(event=event) @@ -1833,15 +1719,12 @@ def convert_earnings(event): exchangerates = ExchangeRates(date) earning.earnings = round(exchangerates.convert(earning.origearnings, earning.currency)) earning.save() - # }}} - # {{{ String representation + # String representation def __str__(self): return '#%i at %s: %s $%s' % (self.placement, self.event.fullname, self.player.tag, self.earnings) - # }}} -# }}} -# {{{ PreMatchGroups + class PreMatchGroup(models.Model): class Meta: db_table = 'prematchgroup' @@ -1857,13 +1740,11 @@ class Meta: game = models.CharField('Game', max_length=10, default='wol', blank=False, null=False, choices=GAMES) offline = models.BooleanField(default=False, null=False) - # {{{ String representation + # String representation def __str__(self): return str(self.date) + ' ' + self.event - # }}} -# }}} -# {{{ PreMatches + class PreMatch(models.Model): class Meta: db_table = 'prematch' @@ -1883,36 +1764,32 @@ class Meta: rca = models.CharField(max_length=1, choices=MRACES, null=True, verbose_name='Race A') rcb = models.CharField(max_length=1, choices=MRACES, null=True, verbose_name='Race B') - # {{{ String representation + # String representation def __str__(self): ret = '(' + self.group.event + ') ' ret += self.pla.tag if self.pla else self.pla_string ret += ' %i-%i ' % (self.sca, self.scb) ret += self.plb.tag if self.plb else self.plb_string return ret - # }}} - # {{{ event_fullpath and event_partpath: For compatibility with Match objects, where needed + # event_fullpath and event_partpath: For compatibility with Match objects, where needed def event_fullpath(self): return self.group.event def event_partpath(self): return self.group.event - # }}} - # {{{ is_valid: Checks if this can be turned into a Match. + # is_valid: Checks if this can be turned into a Match. def is_valid(self): return self.pla is not None and self.plb is not None - # }}} -# }}} -# {{{ Ratings + class Rating(models.Model): class Meta: ordering = ['period'] db_table = 'rating' - # {{{ Fields + # Fields period = models.ForeignKey( Period, null=False, verbose_name='Period', help_text='This rating applies to the given period' @@ -2044,14 +1921,12 @@ class Meta: null=True, blank=True, help_text='Difference from number 7 on rating list' ) - # }}} - # {{{ String representation + # String representation def __str__(self): return self.player.tag + ' P' + str(self.period.id) - # }}} - # {{{ get_next: Get next rating object for the same palyer + # get_next: Get next rating object for the same palyer def get_next(self): try: if self.next: @@ -2064,19 +1939,16 @@ def get_next(self): return self.next except: return None - # }}} - # {{{ get_ratings: Return all rating information in a list + # get_ratings: Return all rating information in a list def ratings(self): return [self.rating, self.rating_vp, self.rating_vt, self.rating_vz] - # }}} - # {{{ get_devs: Return all RD information in a list + # get_devs: Return all RD information in a list def get_devs(self): return [self.dev, self.dev_vp, self.dev_vt, self.dev_vz] - # }}} - # {{{ rating_diff(_vx): Differences in rating between this and previous period + # rating_diff(_vx): Differences in rating between this and previous period def rating_diff(self, race=None): if self.prev is not None: a = self.get_totalrating(race) - self.prev.get_totalrating(race) @@ -2091,9 +1963,8 @@ def rating_diff_vt(self): def rating_diff_vz(self): return self.rating_diff('Z') - # }}} - # {{{ get_rating(race=None): Return rating delta by race + # get_rating(race=None): Return rating delta by race def get_rating(self, race=None): if race == 'P': return self.rating_vp @@ -2102,9 +1973,8 @@ def get_rating(self, race=None): elif race == 'Z': return self.rating_vz return self.rating - # }}} - # {{{ get_dev(race=None): Return RD by race + # get_dev(race=None): Return RD by race def get_dev(self, race=None): if race == 'P': return self.dev_vp @@ -2113,9 +1983,8 @@ def get_dev(self, race=None): elif race == 'Z': return self.dev_vz return self.dev - # }}} - # {{{ get_totalrating(race): Return total rating by race + # get_totalrating(race): Return total rating by race def get_totalrating(self, race): if race in ['P','T','Z']: return self.rating + self.get_rating(race) @@ -2130,9 +1999,8 @@ def get_totalrating_vt(self): def get_totalrating_vz(self): return self.get_totalrating('Z') - # }}} - # {{{ get_totaldev(race): Return total RD by race (expected total RD if None) + # get_totaldev(race): Return total RD by race (expected total RD if None) def get_totaldev(self, race): if race in ['P','T','Z']: return sqrt(self.get_dev(None)**2 + self.get_dev(race)**2) @@ -2141,9 +2009,8 @@ def get_totaldev(self, race): for r in ['P','T','Z']: d += self.get_dev(r)**2/9 return sqrt(d) - # }}} - # {{{ set_rating(d, write_bf=False): Sets rating numbers as given by the dict d with keys MPTZ, writes + # set_rating(d, write_bf=False): Sets rating numbers as given by the dict d with keys MPTZ, writes # them to bf if write_bf is True def set_rating(self, d, write_bf=False): self.rating = d['M'] @@ -2156,9 +2023,8 @@ def set_rating(self, d, write_bf=False): self.bf_rating_vp = self.rating_vp self.bf_rating_vt = self.rating_vt self.bf_rating_vz = self.rating_vz - # }}} - # {{{ set_dev(d, write_bf=False): Sets RD as given by the dict d with keys MPTZ, writes to bf if write_bf + # set_dev(d, write_bf=False): Sets RD as given by the dict d with keys MPTZ, writes to bf if write_bf # is True def set_dev(self, d, write_bf=False): self.dev = d['M'] @@ -2171,26 +2037,22 @@ def set_dev(self, d, write_bf=False): self.bf_dev_vp = self.dev_vp self.bf_dev_vt = self.dev_vt self.bf_dev_vz = self.dev_vz - # }}} - # {{{ set_comp_rating(d): Sets performance ratings as given by the dict d with keys MPTZ + # set_comp_rating(d): Sets performance ratings as given by the dict d with keys MPTZ def set_comp_rating(self, d): self.comp_rat = d['M'] self.comp_rat_vp = d['P'] self.comp_rat_vt = d['T'] self.comp_rat_vz = d['Z'] - # }}} - # {{{ set_comp_dev(d): Sets performance RD as given by the dict d with keys MPTZ + # set_comp_dev(d): Sets performance RD as given by the dict d with keys MPTZ def set_comp_dev(self, d): self.comp_dev = d['M'] self.comp_dev_vp = d['P'] self.comp_dev_vt = d['T'] self.comp_dev_vz = d['Z'] - # }}} -# }}} -# {{{ BalanceEntries + class BalanceEntry(models.Model): class Meta: db_table = 'balanceentry' @@ -2205,9 +2067,8 @@ class Meta: p_gains = models.FloatField('P gains', null=False) t_gains = models.FloatField('T gains', null=False) z_gains = models.FloatField('Z gains', null=False) -# }}} -# {{{ API access keys + class APIKey(models.Model): class Meta: db_table = 'apikey' @@ -2224,4 +2085,3 @@ def __str__(self): def generate_key(self): characters = string.ascii_letters + string.digits self.key = ''.join([random.choice(characters) for _ in range(20)]) -# }}} diff --git a/aligulac/ratings/player_views.py b/aligulac/ratings/player_views.py index 767fb8c..6cac328 100644 --- a/aligulac/ratings/player_views.py +++ b/aligulac/ratings/player_views.py @@ -1,4 +1,4 @@ -# {{{ Imports +# Imports import shlex from datetime import datetime, date, timedelta @@ -70,7 +70,7 @@ ) msg_nochart = _('%s has no rating chart on account of having played matches in fewer than two periods.') -# {{{ meandate: Rudimentary function for sorting objects with a start and end date. +# meandate: Rudimentary function for sorting objects with a start and end date. def meandate(tm): if tm.start is not None and tm.end is not None: return (tm.start.toordinal() + tm.end.toordinal()) / 2 @@ -82,7 +82,7 @@ def meandate(tm): return 1000000 # }}} -# {{{ interp_rating: Takes a date and a rating list, and interpolates linearly. +# interp_rating: Takes a date and a rating list, and interpolates linearly. def interp_rating(date, ratings): for ind, r in enumerate(ratings): if (r.period.end - date).days >= 0: @@ -95,7 +95,7 @@ def interp_rating(date, ratings): return ratings[-1].bf_rating # }}} -# {{{ PlayerModForm: Form for modifying a player. +# PlayerModForm: Form for modifying a player. class PlayerModForm(forms.Form): tag = StrippedCharField(max_length=30, required=True, label=_('Tag')) race = forms.ChoiceField(choices=RACES, required=True, label=_('Race')) @@ -112,7 +112,7 @@ class PlayerModForm(forms.Form): country = forms.ChoiceField(choices=data.countries, required=False, label=_('Country')) - # {{{ Constructor + # Constructor def __init__(self, request=None, player=None): if request is not None: super(PlayerModForm, self).__init__(request.POST) @@ -134,7 +134,7 @@ def __init__(self, request=None, player=None): self.label_suffix = '' # }}} - # {{{ update_player: Pushes updates to player, responds with messages + # update_player: Pushes updates to player, responds with messages def update_player(self, player): ret = [] @@ -169,7 +169,7 @@ def update(value, attr, setter, label): # }}} # }}} -# {{{ ResultsFilterForm: Form for filtering results. +# ResultsFilterForm: Form for filtering results. class ResultsFilterForm(forms.Form): after = forms.DateField(required=False, label=_('After')) before = forms.DateField(required=False, label=_('Before')) @@ -227,14 +227,14 @@ class ResultsFilterForm(forms.Form): game = forms.ChoiceField( choices=[('all','All')]+GAMES, required=False, label=_('Game version'), initial='all') - # {{{ Constructor + # Constructor def __init__(self, *args, **kwargs): super(ResultsFilterForm, self).__init__(*args, **kwargs) self.label_suffix = '' # }}} - # {{{ Cleaning with default values + # Cleaning with default values def clean_default(self, field): if not self[field].html_name in self.data: return self.fields[field].initial @@ -250,10 +250,10 @@ def clean_default(self, field): # }}} # }}} -# {{{ player view +# player view @cache_login_protect def player(request, player_id): - # {{{ Get player object and base context, generate messages and make changes if needed + # Get player object and base context, generate messages and make changes if needed player = get_object_or_404(Player, id=player_id) base = base_ctx('Ranking', 'Summary', request, context=player) @@ -266,7 +266,7 @@ def player(request, player_id): base['messages'] += generate_messages(player) # }}} - # {{{ Various easy data + # Various easy data matches = player.get_matchset() recent = matches.filter(date__gte=(date.today() - relativedelta(months=2))) @@ -300,13 +300,13 @@ def player(request, player_id): base['countryfull'] = transformations.cc_to_cn(player.country) # }}} - # {{{ Recent matches + # Recent matches matches = player.get_matchset(related=['rta','rtb','pla','plb','eventobj'])[0:10] if matches.exists(): base['matches'] = display_matches(matches, fix_left=player, ratings=True) # }}} - # {{{ Team memberships + # Team memberships team_memberships = list(player.groupmembership_set.filter(group__is_team=True).select_related('group')) team_memberships.sort(key=lambda t: t.id, reverse=True) team_memberships.sort(key=meandate, reverse=True) @@ -314,7 +314,7 @@ def player(request, player_id): base['teammems'] = team_memberships # }}} - # {{{ If the player has at least one rating + # If the player has at least one rating if player.current_rating: ratings = total_ratings(player.rating_set.filter(period__computed=True)).select_related('period') base.update({ @@ -338,7 +338,7 @@ def player(request, player_id): base['charts'] = False # }}} - # {{{ If the player has enough games to make a chart + # If the player has enough games to make a chart if base['charts']: ratings = ( total_ratings(player.rating_set.filter(period_id__lte=base['recentchange'].period_id)) @@ -347,7 +347,7 @@ def player(request, player_id): .order_by('period') ) - # {{{ Add stories and other extra information + # Add stories and other extra information earliest = base['firstrating'] latest = base['recentchange'] @@ -404,10 +404,10 @@ def player(request, player_id): return render_to_response('player.djhtml', base) # }}} -# {{{ adjustment view +# adjustment view @cache_page def adjustment(request, player_id, period_id): - # {{{ Get objects + # Get objects period = get_object_or_404(Period, id=period_id, computed=True) player = get_object_or_404(Player, id=player_id) rating = get_object_or_404(Rating, player=player, period=period) @@ -422,7 +422,7 @@ def adjustment(request, player_id, period_id): }) # }}} - # {{{ Matches + # Matches matches = player.get_matchset(related=['rta','rtb','pla','plb','eventobj']).filter(period=period) # If there are no matches, we don't need to continue @@ -436,7 +436,7 @@ def adjustment(request, player_id, period_id): }) # }}} - # {{{ Perform calculations + # Perform calculations tot_rating = {'M': 0.0, 'P': 0.0, 'T': 0.0, 'Z': 0.0} ngames = {'M': 0.0, 'P': 0.0, 'T': 0.0, 'Z': 0.0} expwins = {'M': 0.0, 'P': 0.0, 'T': 0.0, 'Z': 0.0} @@ -481,17 +481,17 @@ def adjustment(request, player_id, period_id): return render_to_response('ratingdetails.djhtml', base) # }}} -# {{{ results view +# results view @cache_page def results(request, player_id): - # {{{ Get objects + # Get objects player = get_object_or_404(Player, id=player_id) base = base_ctx('Ranking', 'Match history', request, context=player) base['player'] = player # }}} - # {{{ Filtering + # Filtering matches = player.get_matchset(related=['pla','plb','eventobj']) form = ResultsFilterForm(request.GET) @@ -559,7 +559,7 @@ def results(request, player_id): matches = matches.distinct() # }}} - # {{{ Statistics + # Statistics disp_matches = display_matches(matches, fix_left=player) base['matches'] = disp_matches base.update({ @@ -582,7 +582,7 @@ def results(request, player_id): }) # }}} - # {{{ TL Postable + # TL Postable has_after = form.cleaned_data['after'] is not None has_before = form.cleaned_data['before'] is not None @@ -770,7 +770,7 @@ def calc_percent(s): return render_to_response('player_results.djhtml', base) # }}} -# {{{ historical view +# historical view @cache_page def historical(request, player_id): player = get_object_or_404(Player, id=player_id) @@ -794,7 +794,7 @@ def historical(request, player_id): return render_to_response('historical.djhtml', base) # }}} -# {{{ earnings view +# earnings view @cache_page def earnings(request, player_id): player = get_object_or_404(Player, id=player_id) @@ -802,7 +802,7 @@ def earnings(request, player_id): year = get_param(request, 'year', 'all') - # {{{ Gather data + # Gather data earnings = player.earnings_set if year != 'all': earnings = earnings.filter(event__latest__year=year) @@ -822,7 +822,7 @@ def year_is_valid(y): e.rng = rng # }}} - # {{{ Sum up earnings by currency + # Sum up earnings by currency currencies = {e.currency for e in earnings} by_currency = {cur: sum([e.origearnings for e in earnings if e.currency == cur]) for cur in currencies} if len(by_currency) == 1 and 'USD' in by_currency: @@ -842,7 +842,7 @@ def year_is_valid(y): # }}} -# {{{ Postable templates +# Postable templates TL_HISTORY_TEMPLATE = ( "{resfor} {player_country_formatted} :{player_race}: " + "[url={url}/players/{pid}/]{player_tag}[/url]{date}.\n" + diff --git a/aligulac/ratings/ranking_views.py b/aligulac/ratings/ranking_views.py index d525622..4f05dda 100644 --- a/aligulac/ratings/ranking_views.py +++ b/aligulac/ratings/ranking_views.py @@ -1,4 +1,4 @@ -# {{{ Imports +# Imports from django.shortcuts import ( get_object_or_404, render_to_response, @@ -43,7 +43,7 @@ msg_preview = _('This is a preview of the next rating list. It will not be finalized until %s.') -# {{{ periods view +# periods view @cache_page def periods(request): base = base_ctx('Ranking', 'History', request) @@ -52,12 +52,12 @@ def periods(request): return render_to_response('periods.djhtml', base) # }}} -# {{{ period view +# period view @cache_page def period(request, period_id=None): base = base_ctx('Ranking', 'Current', request) - # {{{ Get period object + # Get period object if not period_id: period = base['curp'] else: @@ -71,7 +71,7 @@ def period(request, period_id=None): base['curpage'] = '' # }}} - # {{{ Best and most specialised players + # Best and most specialised players qset = total_ratings(filter_active(Rating.objects.filter(period=period))).select_related('player') qsetp = qset.filter(player__race=P) qsett = qset.filter(player__race=T) @@ -108,7 +108,7 @@ def period(request, period_id=None): }) # }}} - # {{{ Highest gainer and biggest losers + # Highest gainer and biggest losers # TODO: Fix these queries, highly dependent on the way django does things. gainers = filter_active(Rating.objects.filter(period=period))\ @@ -127,7 +127,7 @@ def period(request, period_id=None): }) # }}} - # {{{ Matchup statistics + # Matchup statistics qset = period.match_set base['pvt_wins'], base['pvt_loss'] = count_matchup_games(qset, 'P', 'T') base['pvz_wins'], base['pvz_loss'] = count_matchup_games(qset, 'P', 'Z') @@ -141,12 +141,12 @@ def period(request, period_id=None): base['tot_mirror'] = base['pvp_games'] + base['tvt_games'] + base['zvz_games'] # }}} - # {{{ Build country list + # Build country list all_players = Player.objects.filter(rating__period_id=period.id, rating__decay__lt=INACTIVE_THRESHOLD) base['countries'] = country_list(all_players) # }}} - # {{{ Initial filtering of ratings + # Initial filtering of ratings entries = filter_active(period.rating_set).select_related('player') # Race filter @@ -179,7 +179,7 @@ def period(request, period_id=None): }) # }}} - # {{{ Pages etc. + # Pages etc. pagesize = SHOW_PER_LIST_PAGE page = int(get_param(request, 'page', 1)) nitems = entries.count() @@ -217,18 +217,18 @@ def period(request, period_id=None): return render_to_response('period.djhtml', base) # }}} -# {{{ earnings view +# earnings view @cache_page def earnings(request): base = base_ctx('Ranking', 'Earnings', request) - # {{{ Build country and currency list + # Build country and currency list all_players = Player.objects.filter(earnings__player__isnull=False).distinct() base['countries'] = country_list(all_players) base['currencies'] = currency_list(Earnings.objects) # }}} - # {{{ Initial filtering of earnings + # Initial filtering of earnings preranking = Earnings.objects.filter(earnings__isnull=False) # Filtering by year @@ -258,14 +258,14 @@ def earnings(request): ) # }}} - # {{{ Calculate total earnings + # Calculate total earnings base.update({ 'totalorigprizepool': preranking.aggregate(Sum('origearnings'))['origearnings__sum'], 'totalprizepool': preranking.aggregate(Sum('earnings'))['earnings__sum'], }) # }}} - # {{{ Pages, etc. + # Pages, etc. pagesize = SHOW_PER_LIST_PAGE page = int(get_param(request, 'page', 1)) nitems = ranking.count() @@ -295,7 +295,7 @@ def earnings(request): base['empty'] = True # }}} - # {{{ Populate with player and team objects + # Populate with player and team objects ids = [p['player'] for p in ranking] players = Player.objects.in_bulk(ids) for p in ranking: diff --git a/aligulac/ratings/records_views.py b/aligulac/ratings/records_views.py index 72cbc10..7c0d7f9 100644 --- a/aligulac/ratings/records_views.py +++ b/aligulac/ratings/records_views.py @@ -1,4 +1,4 @@ -# {{{ Imports +# Imports from django.db.models import ( Q, Max, @@ -31,12 +31,12 @@ from countries import data # }}} -# {{{ history view +# history view @cache_page def history(request): base = base_ctx('Records', 'History', request) - # {{{ Filtering (appears faster with custom SQL) + # Filtering (appears faster with custom SQL) nplayers = int(get_param(request, 'nplayers', '5')) race = get_param_choice(request, 'race', ['ptzrs','p','t','z','ptrs','tzrs','pzrs'], 'ptzrs') nats = get_param_choice(request, 'nats', ['all','foreigners'] + list(data.ccn_to_cca2.values()), 'all') @@ -71,7 +71,7 @@ def history(request): return render_to_response('history.djhtml', base) # }}} -# {{{ hof view +# hof view @cache_page def hof(request): base = base_ctx('Records', 'HoF', request) @@ -84,12 +84,12 @@ def hof(request): return render_to_response('hof.djhtml', base) # }}} -# {{{ filter stolen from templatetags/ratings_extras.py +# filter stolen from templatetags/ratings_extras.py def racefull(value): return dict(RACES)[value] # }}} -# {{{ race view +# race view @cache_page def race(request): race = get_param(request, 'race', 'all') diff --git a/aligulac/ratings/reports_views.py b/aligulac/ratings/reports_views.py index af9f083..12c0059 100644 --- a/aligulac/ratings/reports_views.py +++ b/aligulac/ratings/reports_views.py @@ -1,4 +1,4 @@ -# {{{ Imports +# Imports from datetime import date from dateutil.relativedelta import relativedelta @@ -25,7 +25,7 @@ ) # }}} -# {{{ Balance report view +# Balance report view @cache_page def balance(request): base = base_ctx('Misc', 'Balance Report', request) diff --git a/aligulac/ratings/results_views.py b/aligulac/ratings/results_views.py index 71d4f00..a7f5327 100644 --- a/aligulac/ratings/results_views.py +++ b/aligulac/ratings/results_views.py @@ -1,4 +1,4 @@ -# {{{ Imports +# Imports from datetime import ( datetime, date, @@ -76,7 +76,7 @@ ) # }}} -# {{{ earnings_code, wcs_points_code: Converts a queryset of earnings or +# earnings_code, wcs_points_code: Converts a queryset of earnings or # wcs points to the corresponding code. def earnings_code(queryset): if not queryset.exists(): @@ -97,7 +97,7 @@ def wcs_points_code(queryset): ]) # }}} -# {{{ EventModForm: Form for modifying an event. +# EventModForm: Form for modifying an event. class EventModForm(forms.Form): name = StrippedCharField(max_length=100, required=True, label='Name') date = forms.DateField(required=False, label='Date') @@ -123,7 +123,7 @@ class EventModForm(forms.Form): tl_thread = forms.IntegerField(required=False, label=_('TL thread')) lp_name = StrippedCharField(max_length=200, required=False, label=_('Liquipedia title')) - # {{{ Constructor + # Constructor def __init__(self, request=None, event=None): if request is not None: super(EventModForm, self).__init__(request.POST) @@ -145,7 +145,7 @@ def __init__(self, request=None, event=None): self.label_suffix = '' # }}} - # {{{ update_event: Pushes updates to event, responds with messages + # update_event: Pushes updates to event, responds with messages def update_event(self, event): ret = [] @@ -293,7 +293,7 @@ def update_event(self, event): return ret -# {{{ WCSModForm: Form for changing WCS status. +# WCSModForm: Form for changing WCS status. class WCSModForm(forms.Form): year = forms.ChoiceField(choices=[(None, _('None'))] + WCS_YEARS, required=False, label=_('Year')) # Translators: WCS event tier @@ -314,7 +314,7 @@ def __init__(self, request=None, event=None): self.label_suffix = '' - # {{{ Function for parsing a single line + # Function for parsing a single line def line_to_data(self, line): ind = line.find(' ') points = int(line[:ind]) @@ -328,7 +328,7 @@ def line_to_data(self, line): return points, queryset.first() # }}} - # {{{ update_event: Pushes changes to event object + # update_event: Pushes changes to event object def update_event(self, event): ret = [] @@ -339,7 +339,7 @@ def update_event(self, event): ret.append(Message(error=error, field=self.fields[field].label)) return ret - # {{{ Gather data + # Gather data entries, ok = [], True for line in self.cleaned_data['points'].split('\n'): @@ -357,7 +357,7 @@ def update_event(self, event): return ret # }}} - # {{{ If not a WCS event, clear all data + # If not a WCS event, clear all data if self.cleaned_data['year'] == 'None': WCSPoints.set_points(event, []) event.wcs_year = None @@ -369,7 +369,7 @@ def update_event(self, event): return ret # }}} - # {{{ If a WCS event, set all data + # If a WCS event, set all data entries.sort(key=lambda a: a['placement']) for i, e in enumerate(entries): e['placement'] = i @@ -386,7 +386,7 @@ def update_event(self, event): # }}} # }}} -# {{{ PrizepoolModForm: Form for changing prizepools. +# PrizepoolModForm: Form for changing prizepools. class PrizepoolModForm(forms.Form): sorted_curs = sorted(ccy.currencydb(), key=operator.itemgetter(0)) currencies = [(ccy.currency(c).code, ccy.currency(c).name) for c in sorted_curs] @@ -394,7 +394,7 @@ class PrizepoolModForm(forms.Form): ranked = forms.CharField(required=False, max_length=10000, label=_('Ranked')) unranked = forms.CharField(required=False, max_length=10000, label=_('Unranked')) - # {{{ Constructor + # Constructor def __init__(self, request=None, event=None): if request is not None: super(PrizepoolModForm, self).__init__(request.POST) @@ -414,7 +414,7 @@ def __init__(self, request=None, event=None): self.label_suffix = '' # }}} - # {{{ Function for parsing a single line + # Function for parsing a single line def line_to_data(self, line): ind = line.find(' ') prize = Decimal(line[:ind]) @@ -428,7 +428,7 @@ def line_to_data(self, line): return prize, queryset.first() # }}} - # {{{ update_event: Pushes changes to event object + # update_event: Pushes changes to event object def update_event(self, event): ret = [] @@ -439,7 +439,7 @@ def update_event(self, event): ret.append(Message(error=error, field=self.fields[field].label)) return ret - # {{{ Gather data + # Gather data ranked, unranked, ok = [], [], True for line in self.cleaned_data['ranked'].split('\n'): @@ -467,13 +467,13 @@ def update_event(self, event): return ret # }}} - # {{{ Fix placements of ranked prizes + # Fix placements of ranked prizes ranked.sort(key=lambda a: a['placement']) for i, e in enumerate(ranked): ranked[i]['placement'] = i # }}} - # {{{ Commit + # Commit try: Earnings.set_earnings(event, ranked, self.cleaned_data['currency'], True) Earnings.set_earnings(event, unranked, self.cleaned_data['currency'], False) @@ -489,13 +489,13 @@ def update_event(self, event): # }}} # }}} -# {{{ StoryModForm: Form for adding stories. +# StoryModForm: Form for adding stories. class StoryModForm(forms.Form): player = forms.ChoiceField(required=True, label=_('Player')) date = forms.DateField(required=True, label=_('Date')) text = StrippedCharField(max_length=200, required=True, label=_('Text')) - # {{{ Constructor + # Constructor def __init__(self, request=None, event=None): if request is not None: super(StoryModForm, self).__init__(request.POST) @@ -511,7 +511,7 @@ def __init__(self, request=None, event=None): self.existing_stories = Player.objects.filter(story__event=event) # }}} - # {{{ update_event: Pushes changes + # update_event: Pushes changes def update_event(self, event): ret = [] @@ -537,14 +537,14 @@ def update_event(self, event): # }}} # }}} -# {{{ AddForm: Form for adding subevents. +# AddForm: Form for adding subevents. class AddForm(forms.Form): name = StrippedCharField(max_length=100, required=True, label=_('Name')) type = forms.ChoiceField(choices=EVENT_TYPES, required=True, label=_('Type')) noprint = forms.BooleanField(required=False, label=_('No Print')) closed = forms.BooleanField(required=False, label=_('Closed')) - # {{{ Constructor + # Constructor def __init__(self, request=None, event=None): if request is not None: super(AddForm, self).__init__(request.POST) @@ -558,7 +558,7 @@ def __init__(self, request=None, event=None): self.label_suffix = '' # }}} - # {{{ update_event: Pushes changes + # update_event: Pushes changes def update_event(self, event): ret = [] @@ -582,11 +582,11 @@ def update_event(self, event): # }}} # }}} -# {{{ ReorderForm: Form for reordering events. +# ReorderForm: Form for reordering events. class ReorderForm(forms.Form): order = StrippedCharField(max_length=10000, required=True) - # {{{ Constructor + # Constructor def __init__(self, request=None, event=None): if request is not None: super(ReorderForm, self).__init__(request.POST) @@ -594,7 +594,7 @@ def __init__(self, request=None, event=None): super(ReorderForm, self).__init__() # }}} - # {{{ Custom validation + # Custom validation def clean_order(self): try: ids = [int(s) for s in self.cleaned_data['order'].split(',') if s.strip() != ''] @@ -605,7 +605,7 @@ def clean_order(self): return [events[i] for i in ids] # }}} - # {{{ update_event: Pushes changes + # update_event: Pushes changes def update_event(self, event): ret = [] @@ -636,7 +636,7 @@ def update_event(self, event): # }}} # }}} -# {{{ SearchForm: Form for searching. +# SearchForm: Form for searching. class SearchForm(forms.Form): after = forms.DateField(required=False, label=_('After'), initial=None) before = forms.DateField(required=False, label=_('Before'), initial=None) @@ -681,7 +681,7 @@ class SearchForm(forms.Form): game = forms.ChoiceField( choices=[('all',_('All'))]+GAMES, required=False, label=_('Game version'), initial='all') - # {{{ Constructor + # Constructor def __init__(self, request=None): if request is not None: super(SearchForm, self).__init__(request.GET) @@ -691,9 +691,9 @@ def __init__(self, request=None): self.label_suffix = '' # }}} - # {{{ search: Performs a search, returns a dict with results to be added to the rendering context + # search: Performs a search, returns a dict with results to be added to the rendering context def search(self, adm): - # {{{ Check validity (lol) + # Check validity (lol) if not self.is_valid(): msgs = [] msgs.append(Message(_('Entered data was invalid, no changes made.'), type=Message.ERROR)) @@ -709,7 +709,7 @@ def search(self, adm): .annotate(Count('eventobj__match')) ) - # {{{ All the easy filtering + # All the easy filtering if self.cleaned_data['after'] is not None: matches = matches.filter(date__gte=self.cleaned_data['after']) @@ -750,7 +750,7 @@ def search(self, adm): matches = matches.distinct() - # {{{ Filter by event + # Filter by event if self.cleaned_data['event'] != None: lex = shlex.shlex(self.cleaned_data['event'], posix=True) lex.wordchars += "'" @@ -777,7 +777,7 @@ def search(self, adm): ret = {'messages': []} - # {{{ Filter by players + # Filter by players lines = self.cleaned_data['players'].splitlines() lineno, ok, players = -1, True, [] for line in lines: @@ -814,7 +814,7 @@ def search(self, adm): matches = matches.filter(Q(pla__in=pls) | Q(plb__in=pls)) # }}} - # {{{ Collect data + # Collect data ret['count'] = matches.count() if ret['count'] > 1000: ret['messages'].append(Message( @@ -845,7 +845,7 @@ def search(self, adm): # }}} # }}} -# {{{ ResultsModForm: Form for modifying search results. +# ResultsModForm: Form for modifying search results. class ResultsModForm(forms.Form): event = forms.ChoiceField(required=True, label=_('Event')) date = forms.DateField(required=False, label=_('Date'), initial=None) @@ -858,7 +858,7 @@ class ResultsModForm(forms.Form): required=True, label=_('Game version'), initial='nochange' ) - # {{{ Constructor + # Constructor def __init__(self, request=None): if request is not None: super(ResultsModForm, self).__init__(request.POST) @@ -874,7 +874,7 @@ def __init__(self, request=None): ] # }}} - # {{{ modify: Commits modifications + # modify: Commits modifications def modify(self, ids): ret = [] @@ -910,7 +910,7 @@ def modify(self, ids): # }}} # }}} -# {{{ results view +# results view @cache_login_protect def results(request): base = base_ctx('Results', 'By Date', request) @@ -942,17 +942,17 @@ def results(request): return render_to_response('results.djhtml', base) # }}} -# {{{ events view +# events view @cache_login_protect def events(request, event_id=None): - # {{{ Get base context, redirect if necessary + # Get base context, redirect if necessary if 'goto' in request.GET: return redirect('/results/events/' + request.GET['goto']) base = base_ctx('Results', 'By Event', request) # }}} - # {{{ Display the main table if event ID is not given + # Display the main table if event ID is not given if event_id is None: root_events = ( Event.objects @@ -984,7 +984,7 @@ def events(request, event_id=None): return render_to_response('events.djhtml', base) # }}} - # {{{ Get object, generate messages, and ensure big is set. Find familial relationships. + # Get object, generate messages, and ensure big is set. Find familial relationships. event = get_object_or_404(Event, id=event_id) base['messages'] += generate_messages(event) @@ -1001,7 +1001,7 @@ def events(request, event_id=None): }) # }}} - # {{{ Make forms + # Make forms if base['adm']: def check_form(formname, cl, check): if request.method == 'POST' and check in request.POST: @@ -1026,7 +1026,7 @@ def check_form(formname, cl, check): base['messages'].append(Message(_('Sucessfully closed event.'), type=Message.SUCCESS)) # }}} - # {{{ Prizepool information for the public + # Prizepool information for the public total_earnings = Earnings.objects.filter(event__uplink__parent=event) local_earnings = Earnings.objects.filter(event=event) @@ -1059,7 +1059,7 @@ def check_form(formname, cl, check): }) # }}} - # {{{ Other easy statistics + # Other easy statistics add_links = request.user.is_authenticated() and request.user.is_staff @@ -1098,12 +1098,12 @@ def check_form(formname, cl, check): return render_to_response('eventres.djhtml', base) # }}} -# {{{ search view +# search view @cache_login_protect def search(request): base = base_ctx('Results', 'Search', request) - # {{{ Filtering and modifying + # Filtering and modifying if base['adm']: if request.method == 'POST': modform = ResultsModForm(request=request) diff --git a/aligulac/ratings/team_views.py b/aligulac/ratings/team_views.py index 6229daf..0941f6e 100644 --- a/aligulac/ratings/team_views.py +++ b/aligulac/ratings/team_views.py @@ -1,4 +1,4 @@ -# {{{ Imports +# Imports from datetime import date from django import forms @@ -42,7 +42,7 @@ ) # }}} -# {{{ TeamModForm: Form for modifying a team. +# TeamModForm: Form for modifying a team. class TeamModForm(forms.Form): name = StrippedCharField(max_length=100, required=True, label=_('Name')) akas = forms.CharField(max_length=200, required=False, label=_('AKAs')) @@ -50,7 +50,7 @@ class TeamModForm(forms.Form): homepage = StrippedCharField(max_length=200, required=False, label=_('Homepage')) lp_name = StrippedCharField(max_length=200, required=False, label=_('Liquipedia title')) - # {{{ Constructor + # Constructor def __init__(self, request=None, team=None): if request is not None: super(TeamModForm, self).__init__(request.POST) @@ -66,7 +66,7 @@ def __init__(self, request=None, team=None): self.label_suffix = '' # }}} - # {{{ update_player: Pushes updates to player, responds with messages + # update_player: Pushes updates to player, responds with messages def update_team(self, team): ret = [] @@ -94,7 +94,7 @@ def update(value, attr, setter, label): # }}} # }}} -# {{{ teams view +# teams view @cache_page def teams(request): base = base_ctx('Teams', 'Ranking', request) @@ -128,10 +128,10 @@ def teams(request): return render_to_response('teams.djhtml', base) # }}} -# {{{ team view +# team view @cache_login_protect def team(request, team_id): - # {{{ Get team object and base context, generate messages and make changes if needed + # Get team object and base context, generate messages and make changes if needed team = get_object_or_404(Group, id=team_id) base = base_ctx('Teams', None, request) @@ -148,7 +148,7 @@ def team(request, team_id): base['messages'] += generate_messages(team) # }}} - # {{{ Easy statistics + # Easy statistics players = team.groupmembership_set.filter(current=True, playing=True) player_ids = players.values('player') matches = Match.objects.filter(Q(pla__in=player_ids) | Q(plb__in=player_ids)) @@ -166,7 +166,7 @@ def team(request, team_id): }) # }}} - # {{{ Player lists + # Player lists all_members = total_ratings( Rating.objects.all().order_by('-rating').filter( player__groupmembership__group=team, @@ -196,12 +196,12 @@ def team(request, team_id): return render_to_response('team.djhtml', base) # }}} -# {{{ transfers view +# transfers view @cache_page def transfers(request): base = base_ctx('Teams', 'Transfers', request) - # {{{ Get relevant groupmembership objects + # Get relevant groupmembership objects trades = ( GroupMembership.objects .exclude(start__isnull=True, end__isnull=True) @@ -220,7 +220,7 @@ def transfers(request): ) # }}} - # {{{ Separate them into joins and leaves + # Separate them into joins and leaves pretrades = [] for t in trades: if t.start is not None and t.start <= date.today(): @@ -231,7 +231,7 @@ def transfers(request): pretrades.sort(key=lambda t: t['date'], reverse=True) # }}} - # {{{ Combine joins and leaves for the same player on the same date + # Combine joins and leaves for the same player on the same date ind = 0 while ind < len(pretrades) - 1: if pretrades[ind]['player'] == pretrades[ind+1]['player'] and\ diff --git a/aligulac/ratings/tools.py b/aligulac/ratings/tools.py index 55e60f7..affa68e 100644 --- a/aligulac/ratings/tools.py +++ b/aligulac/ratings/tools.py @@ -1,4 +1,4 @@ -# {{{ Imports +# Imports from numpy import ( arctanh, tanh, @@ -39,7 +39,7 @@ ) # }}} -# {{{ Patchlist +# Patchlist PATCHES = [ (date(year=2010, month=10, day=14), '1.1.2'), (date(year=2011, month=3, day=22), '1.3.0'), @@ -56,7 +56,7 @@ ] # }}} -# {{{ Currency names +# Currency names CURRENCIES = { 'EUR': _('Euro'), 'GBP': _('British Pound'), @@ -107,7 +107,7 @@ } # }}} -# {{{ find_player: Magic! +# find_player: Magic! def find_player(query=None, lst=None, make=False, soft=False, strict=False): queryset = Player.objects.all() @@ -119,7 +119,7 @@ def find_player(query=None, lst=None, make=False, soft=False, strict=False): tag, country, race = None, None, None - # {{{ Build filter + # Build filter for s in lst: # If numeric, assume a restriction on ID if s.isdigit(): @@ -195,9 +195,9 @@ def format_filter(**kwargs): queryset = queryset.filter(q) # }}} - # {{{ If no results, make player if allowed + # If no results, make player if allowed if not queryset.exists() and make: - # {{{ Raise exceptions if missing crucial data + # Raise exceptions if missing crucial data if tag == None: msg = _("Player '%s' was not found and cound not be made (missing player tag)") % ' '.join(lst) raise Exception(msg) @@ -216,22 +216,22 @@ def format_filter(**kwargs): return queryset.distinct() # }}} -# {{{ cdf: Cumulative distribution function +# cdf: Cumulative distribution function def cdf(x, loc=0.0, scale=1.0): return 0.5 + 0.5 * tanh(pi/2/sqrt(3) * (x-loc)/scale) # }}} -# {{{ pdf: Probability distribution function +# pdf: Probability distribution function def pdf(x, loc=0.0, scale=1.0): return pi/4/sqrt(3)/scale * (1 - tanh(pi/2/sqrt(3)*(x-loc)/scale)**2) # }}} -# {{{ icdf: Inverse cumulative distribution function +# icdf: Inverse cumulative distribution function def icdf(c, loc=0.0, scale=1.0): return loc + scale * 2*sqrt(3)/pi * arctanh(2*c - 1) # }}} -# {{{ get_latest_period: Returns the latest computed period, or None. +# get_latest_period: Returns the latest computed period, or None. def get_latest_period(): try: return Period.objects.filter(computed=True).latest('start') @@ -239,7 +239,7 @@ def get_latest_period(): return None # }}} -# {{{ filter_active: Filters a rating queryset by removing inactive ratings. +# filter_active: Filters a rating queryset by removing inactive ratings. def filter_active(queryset): return queryset.filter(decay__lt=INACTIVE_THRESHOLD) @@ -247,7 +247,7 @@ def filter_active_players(queryset): return queryset.filter(current_rating__decay__lt=INACTIVE_THRESHOLD) # }}} -# {{{ filter_inactive: Filters a rating queryset by removing active ratings. +# filter_inactive: Filters a rating queryset by removing active ratings. def filter_inactive(queryset): return queryset.exclude(decay__lt=INACTIVE_THRESHOLD) @@ -255,7 +255,7 @@ def filter_inactive_players(queryset): return queryset.exclude(current_rating__decay__lt=INACTIVE_THRESHOLD) # }}} -# {{{ total_ratings: Annotates a rating queryset by adding tot_vp, tot_vt and tot_vz. +# total_ratings: Annotates a rating queryset by adding tot_vp, tot_vt and tot_vz. def total_ratings(queryset): return queryset.extra(select={ 'tot_vp': 'rating+rating_vp', @@ -264,7 +264,7 @@ def total_ratings(queryset): }) # }}} -# {{{ populate_teams: Adds team information to rows in a queryset (ratings or players) by populating the +# populate_teams: Adds team information to rows in a queryset (ratings or players) by populating the # members team (short name), teamfull (full name) and teamid (team ID). def populate_teams(queryset, player_set=False): if player_set: @@ -292,7 +292,7 @@ def populate_teams(queryset, player_set=False): return q # }}} -# {{{ country_list: Creates a list of countries in the given queryset (of Players). +# country_list: Creates a list of countries in the given queryset (of Players). def country_list(queryset): countries = queryset.values('country').distinct() country_codes = {c['country'] for c in countries if c['country'] is not None} @@ -301,7 +301,7 @@ def country_list(queryset): return country_dict # }}} -# {{{ currency_list: Creates a list of currencies in the given queryset (of Earnings). +# currency_list: Creates a list of currencies in the given queryset (of Earnings). def currency_list(queryset): currencies = queryset.values('currency').distinct().order_by('currency') currency_dict = [ @@ -312,7 +312,7 @@ def currency_list(queryset): # }}} -# {{{ +# def currency_strip(value): """ Pretty prints the value using as few characters as possible @@ -327,7 +327,7 @@ def currency_strip(value): return str(value) # }}} -# {{{ filter_flags: Splits an integer representing bitwise or into a list of each flag. +# filter_flags: Splits an integer representing bitwise or into a list of each flag. def filter_flags(flags): power = 1 ret = [] @@ -340,12 +340,12 @@ def filter_flags(flags): return ret # }}} -# {{{ split_matchset: Splits a match queryset into two, where player is A and B respectively +# split_matchset: Splits a match queryset into two, where player is A and B respectively def split_matchset(queryset, player): return queryset.filter(pla=player), queryset.filter(plb=player) # }}} -# {{{ get_placements: Returns a dict mapping prizemoney to tuple (min,max) placements for a given event. +# get_placements: Returns a dict mapping prizemoney to tuple (min,max) placements for a given event. def get_placements(event): ret = {} for earning in event.earnings_set.exclude(placement=0).order_by('placement'): @@ -359,45 +359,45 @@ def get_placements(event): return ret # }}} -# {{{ ntz: Helper function with aggregation, sending None to 0, so that the sum of an empty list is 0. +# ntz: Helper function with aggregation, sending None to 0, so that the sum of an empty list is 0. # AS IT FUCKING SHOULD BE. ntz = lambda k: k if k is not None else 0 # }}} -# {{{ count_winloss_games: Counts wins and losses over a queryset relative to player A. +# count_winloss_games: Counts wins and losses over a queryset relative to player A. def count_winloss_games(queryset): agg = queryset.aggregate(Sum('sca'), Sum('scb')) return ntz(agg['sca__sum']), ntz(agg['scb__sum']) # }}} -# {{{ count_winloss_player(queryset, player): Counts wins and losses over a queryset for a given player. +# count_winloss_player(queryset, player): Counts wins and losses over a queryset for a given player. def count_winloss_player(queryset, player): wa, la = count_winloss_games(queryset.filter(pla=player)) lb, wb = count_winloss_games(queryset.filter(plb=player)) return wa+wb, la+lb # }}} -# {{{ count_matchup_games: Gets the matchup W-L data for a queryset. +# count_matchup_games: Gets the matchup W-L data for a queryset. def count_matchup_games(queryset, rca, rcb): wa, la = count_winloss_games(queryset.filter(rca=rca, rcb=rcb)) lb, wb = count_winloss_games(queryset.filter(rca=rcb, rcb=rca)) return wa+wb, la+lb # }}} -# {{{ count_matchup_player: Gets the matcup W-L data for a queryset for a given player. +# count_matchup_player: Gets the matcup W-L data for a queryset for a given player. def count_matchup_player(queryset, player, race): wa, la = count_winloss_games(queryset.filter(pla=player, rcb=race)) lb, wb = count_winloss_games(queryset.filter(plb=player, rca=race)) return wa+wb, la+lb # }}} -# {{{ count_mirror_games: Gets the number of mirror games for a queryset. +# count_mirror_games: Gets the number of mirror games for a queryset. def count_mirror_games(queryset, race): w, l = count_winloss_games(queryset.filter(rca=race, rcb=race)) return w + l # }}} -# {{{ add_counts: Add match and game counts to a rating queryset (should have prefetched prev__rt(a,b)). +# add_counts: Add match and game counts to a rating queryset (should have prefetched prev__rt(a,b)). # Will probably result in two queries being run. def add_counts(queryset): for r in queryset: @@ -416,7 +416,7 @@ def add_counts(queryset): return queryset # }}} -# {{{ display_matches: Prepare a match queryset for display. Works for both Match and PreMatch objects. +# display_matches: Prepare a match queryset for display. Works for both Match and PreMatch objects. # Optional arguments: # - date: True to display dates, false if not. # - fix_left: Set to a player object if you want that player to be always listed on the left. @@ -429,7 +429,7 @@ def display_matches(matches, date=True, fix_left=None, ratings=False, messages=T ret = [] for idx, m in enumerate(matches): - # {{{ Basic stuff + # Basic stuff r = { 'match': m, 'match_id': m.id, @@ -462,7 +462,7 @@ def display_matches(matches, date=True, fix_left=None, ratings=False, messages=T r['add_links'] = add_links and m.eventobj is not None and not m.eventobj.closed # }}} - # {{{ Add dates and messages if needed + # Add dates and messages if needed if date and isinstance(m, Match): r['date'] = m.date @@ -473,7 +473,7 @@ def display_matches(matches, date=True, fix_left=None, ratings=False, messages=T ] # }}} - # {{{ Check ratings if needed + # Check ratings if needed if ratings and isinstance(m, Match): r['pla'].update({ 'rating': m.rta.get_totalrating(m.rcb) if m.rta @@ -488,7 +488,7 @@ def display_matches(matches, date=True, fix_left=None, ratings=False, messages=T }) # }}} - # {{{ Switch roles of pla and plb if needed + # Switch roles of pla and plb if needed if fix_left is not None and fix_left.id == r['plb']['id']: r['pla'], r['plb'] = r['plb'], r['pla'] # }}} diff --git a/aligulac/reports.py b/aligulac/reports.py index 2e749ef..ebca81c 100755 --- a/aligulac/reports.py +++ b/aligulac/reports.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 -# {{{ Imports +# Imports import os os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'aligulac.settings') @@ -30,17 +30,16 @@ ntz, PATCHES, ) -# }}} def info(string): print("[{}] {}".format(datetime.now(), string)) -# {{{ Balance reports +# Balance reports def balance(): first = date(year=2010, month=7, day=1) last = date.today().replace(day=1) - relativedelta(months=1) - # {{{ Auxiliary functions for updating + # Auxiliary functions for updating def get_data_perf_single(matches, rca, rcb): res = ( matches.filter(rca=rca, rcb=rcb) @@ -71,9 +70,8 @@ def get_data_perf(matches, race): perfdiff = icdf(wa/(wa+wb), loc=0.0, scale=1.0) return perfdiff - diff/(wa+wb) - # }}} - # {{{ Update data + # Update data while first <= last: matches = Match.objects.filter(date__gte=first, date__lt=(first+relativedelta(months=1))) pvt_w, pvt_l = count_matchup_games(matches, 'P', 'T') @@ -110,8 +108,6 @@ def get_data_perf(matches, race): be.save() first = first + relativedelta(months=1) - # }}} -# }}} if __name__ == '__main__': balance() diff --git a/aligulac/smoothing.py b/aligulac/smoothing.py index 0006880..4dfccd1 100755 --- a/aligulac/smoothing.py +++ b/aligulac/smoothing.py @@ -23,7 +23,7 @@ print('[%s] Backwards smoothing' % str(datetime.now()), flush=True) -# {{{ Copy data for the last period +# Copy data for the last period last = Period.objects.filter(computed=True).latest('id') Rating.objects.filter(period=last).update( bf_rating=F('rating'), @@ -35,14 +35,13 @@ bf_dev_vt=F('dev_vt'), bf_dev_vz=F('dev_vz'), ) -# }}} cur = connection.cursor() for period_id in range(last.id-1, 0, -1): print('[%s] Smoothing period %i' % (str(datetime.now()), period_id), flush=True) - # {{{ Update RDs + # Update RDs with transaction.atomic(): cur.execute(''' UPDATE rating @@ -59,9 +58,8 @@ WHERE rating.id = i.id''' .format(dec=DECAY_DEV, pid=period_id+1, mid=period_id) ) - # }}} - # {{{ Update ratings + # Update ratings with transaction.atomic(): cur.execute(''' UPDATE rating @@ -82,9 +80,8 @@ WHERE rating.id = i.id''' .format(dec=DECAY_DEV, pid=period_id+1, mid=period_id) ) - # }}} - # {{{ Enforce RD between min and max (init) + # Enforce RD between min and max (init) with transaction.atomic(): cur.execute(''' UPDATE rating @@ -101,9 +98,8 @@ WHERE rating.id = i.id''' .format(min=MIN_DEV, init=INIT_DEV, mid=period_id) ) - # }}} - # {{{ Subtract mean to renormalize + # Subtract mean to renormalize with transaction.atomic(): cur.execute(''' UPDATE rating @@ -120,4 +116,3 @@ WHERE rating.id = i.id''' .format(mid=period_id) ) - # }}} diff --git a/aligulac/teamranks.py b/aligulac/teamranks.py index f30f349..7e632e9 100755 --- a/aligulac/teamranks.py +++ b/aligulac/teamranks.py @@ -28,7 +28,7 @@ nplayers_min = 6 if proleague else 1 Simulator = TeamPL if proleague else TeamAK -# {{{ Get a list of teams that can compete +# Get a list of teams that can compete curp = get_latest_period() allowed_teams = [] teams = Group.objects.filter(active=True, is_team=True) @@ -50,9 +50,8 @@ disallowed.update(scoreak=0.0) nteams = len(allowed_teams) -# }}} -# {{{ Simulate +# Simulate print( '[%s] Simulating %s for %i teams' % (str(datetime.now()), 'PL' if proleague else 'AK', nteams), @@ -92,9 +91,8 @@ else: scores[ta] += sim._tally[0][1]/(nteams-1) scores[tb] += sim._tally[1][1]/(nteams-1) -# }}} -# {{{ Save +# Save print( '[%s] Saving %s scores for %i teams' % (str(datetime.now()), 'PL' if proleague else 'AK', nteams), @@ -106,4 +104,3 @@ else: team.scoreak = scores[team] team.save() -# }}} diff --git a/aligulac/teamratings.py b/aligulac/teamratings.py index 6640120..052c7bf 100755 --- a/aligulac/teamratings.py +++ b/aligulac/teamratings.py @@ -24,7 +24,7 @@ print('[%s] Updating team ratings' % str(datetime.now()), flush=True) -# {{{ Update ratings +# Update ratings curp = get_latest_period() for team in Group.objects.filter(active=True, is_team=True): ratings = filter_active(Rating.objects.filter( @@ -39,4 +39,3 @@ else: team.meanrating = -10 team.save() -# }}}