#!/usr/bin/env python3 import html import json import sys import pywikiapi import mwparserfromhell OSMWIKI_ENDPOINT = 'https://wiki.openstreetmap.org/w/api.php' osmwiki = pywikiapi.Site(OSMWIKI_ENDPOINT) # https://wiki.openstreetmap.org/w/index.php?title=Template:Proposal_page&action=edit CATEGORIES = ( 'Category:Proposed features under way', 'Category:Active features', 'Category:Inactive features', ) def find_proposals(): for cat in CATEGORIES: yield from osmwiki.query_pages( generator='categorymembers', gcmtitle=cat, gcmlimit='max', prop='revisions', rvprop='content', rvslots='main', ) def get_template_val(tpl, name): param = tpl.get(name, None) if param: value = param.value.strip() if value: # turn empty strings into None return value proposals = [] for page in find_proposals(): text = page['revisions'][0]['slots']['main']['content'] doc = mwparserfromhell.parse(text) templates = doc.filter_templates(matches=lambda t: t.name.matches('Proposal Page')) if not templates: print('{{Proposal Page}} not found in ', page['title'], file=sys.stderr) continue for comment in doc.ifilter_comments(): # remove comments like doc.remove(comment) tpl = templates[0] page_title = page['title'] name = get_template_val(tpl, 'name') if name: name = html.unescape(name) status = get_template_val(tpl, 'status') if status: status = status.lower() draft_start = get_template_val(tpl, 'draftStartDate') if draft_start in ('*', '-'): draft_start = None rfc_start = get_template_val(tpl, 'rfcStartDate') if rfc_start in ('*', '-'): rfc_start = None vote_start = get_template_val(tpl, 'voteStartDate') if vote_start in ('*', '-'): vote_start = None definition = get_template_val(tpl, 'definition') users = get_template_val(tpl, 'users') or get_template_val(tpl, 'user') proposals.append( dict( page_title=page_title, name=name, status=status, definition=definition, draft_start=draft_start, rfc_start=rfc_start, vote_start=vote_start, authors=users, ) ) STATUSES = { 'voting': 0, 'proposed': 1, 'draft': 2, 'post-vote': 3, 'approved': 4, 'inactive': 5, 'rejected': 6, 'abandoned': 7, 'canceled': 8, 'obsoleted': 9, } def sort_key(proposal): status = proposal['status'] if status in ('voting', 'approved', 'rejected'): date = proposal['vote_start'] or '' elif status == 'proposed': date = proposal['rfc_start'] or '' else: date = proposal['draft_start'] or '' return (-STATUSES.get(proposal['status'], 10), date) proposals.sort(key=sort_key, reverse=True) json.dump(proposals, sys.stdout)