Infographie de répartition des votes par groupe

Signed-off-by: Emmy D'Anello <ynerant@crans.org>
This commit is contained in:
Emmy D'Anello 2022-10-01 23:42:33 +02:00
parent 9ec881a756
commit eeec6fd46f
1 changed files with 107 additions and 10 deletions

View File

@ -1,3 +1,4 @@
from collections import OrderedDict
import datetime import datetime
import hashlib import hashlib
from io import BytesIO from io import BytesIO
@ -8,14 +9,32 @@ import requests
import subprocess import subprocess
from zipfile import ZipFile from zipfile import ZipFile
from bs4 import BeautifulSoup
from tweepy import API, Client, OAuth1UserHandler from tweepy import API, Client, OAuth1UserHandler
from . import config from . import config
LEG = 16
BASE_PATH = os.path.dirname(os.path.dirname(__file__)) BASE_PATH = os.path.dirname(os.path.dirname(__file__))
LEG = 16
DEPUTES = {}
GROUPES_ID = [
"PO800490",
"PO800502",
"PO800526",
"PO800496",
"PO800538",
"PO800484",
"PO800514",
"PO800532",
"PO800508",
"PO800520",
"PO793087",
]
GROUPES = OrderedDict(**{k: None for k in GROUPES_ID})
def update_scrutins(): def update_scrutins():
url = f"https://data.assemblee-nationale.fr/static/openData/repository/{LEG}/loi/scrutins/Scrutins.json.zip" url = f"https://data.assemblee-nationale.fr/static/openData/repository/{LEG}/loi/scrutins/Scrutins.json.zip"
md5 = requests.get(f"{url}.md5").content.decode().strip() md5 = requests.get(f"{url}.md5").content.decode().strip()
@ -100,28 +119,85 @@ def publish_amendement(obj, api, client):
print(date, delta) print(date, delta)
syn = scrutin['syntheseVote'] syn = scrutin['syntheseVote']
for g in scrutin['ventilationVotes']['organe']['groupes']['groupe']:
print(g['organeRef'])
print(scrutin['ventilationVotes']['organe']['groupes']['groupe'][-1])
print(sum(len((g['vote']['decompteNominatif']['pours'] or {'votant': []})['votant']) + len((g['vote']['decompteNominatif']['contres'] or {'votant': []})['votant']) for g in scrutin['ventilationVotes']['organe']['groupes']['groupe']))
with open('/tmp/img.html', 'w') as f: with open('/tmp/img.html', 'w') as f:
f.write(content) f.write(content)
subprocess.run(['wkhtmltoimage', '/tmp/img.html', '/tmp/img.jpg']) subprocess.run(['wkhtmltoimage', '/tmp/img.html', '/tmp/img.jpg'])
text_media = api.media_upload("/tmp/img.jpg") text_media = api.media_upload("/tmp/img.jpg")
api.create_media_metadata(text_media.media_id, content[:1000]) api.create_media_metadata(text_media.media_id, BeautifulSoup(content.replace('</p>', '</p>\n\n'), features="lxml").get_text()[:1000])
vote_groupes = OrderedDict(**{k: None for k in GROUPES_ID})
for g in scrutin['ventilationVotes']['organe']['groupes']['groupe']:
vote_groupes[g['organeRef']] = g['vote']
# FIXME Faites mieux # FIXME Faites mieux
syn_text = f"<p><strong>Pour :</strong> {syn['decompte']['pour']}</p>\n" + \ syn_html = '<html lang="fr">\n<head>\n<meta http-equiv="content-type" content="text/html; charset=UTF-8" />\n</head>\n<body>\n'
f"<p><strong>Contre :</strong> {syn['decompte']['contre']}</p>\n" + \ syn_html += '<table style="border: 1px solid black;">\n<thead>\n'
f"<p><strong>Abstentions :</strong> {syn['decompte']['abstentions']}</p>\n" + \ syn_html += f"<tr><th colspan=\"4\"><h2>{scrutin['titre']}</h2></th></tr>\n"
f"<p><strong>Exprim&eacute;s :</strong> {syn['suffragesExprimes']}" syn_html += '</thead>\n<tbody>\n'
for i, (gid, voix) in enumerate(vote_groupes.items()):
if i % 4 == 0:
if i != 0:
syn_html += "</tr>\n"
syn_html += "<tr>\n"
syn_html += f"<td style=\"width: 25%; margin: 5px; padding: 1px; border: 2px solid {GROUPES[gid]['couleurAssociee']};\">\n"
syn_html += f"<strong>{GROUPES[gid]['libelleAbrege']}</strong><br>\n"
syn_html += "<span style=\"color: green;\">"
syn_html += int(voix['decompteVoix']['pour']) * " &#9679;"
syn_html += "</span>"
syn_html += "<span style=\"color: red;\">"
syn_html += int(voix['decompteVoix']['contre']) * " &#9679;"
syn_html += "</span>"
syn_html += "<span style=\"color: orange;\">"
syn_html += int(voix['decompteVoix']['abstentions']) * " &#9679;"
syn_html += "</span>"
syn_html += "<span style=\"color: gray;\">"
syn_html += (len(GROUPES[gid]['deputes']) - int(voix['decompteVoix']['pour']) - int(voix['decompteVoix']['contre']) - int(voix['decompteVoix']['abstentions'])) * " &#9679;"
syn_html += "</span>\n<hr>\n"
syn_html += f"Pour : {voix['decompteVoix']['pour']}<br>Contre : {voix['decompteVoix']['contre']}<br>Abstentions : {voix['decompteVoix']['abstentions']}\n"
syn_html += "</td>\n"
syn_html += "<td style=\"width: 25%; margin: 8px; padding: 2px; border: 2px solid black;\">\n"
syn_html += "<strong>Total</strong>\n"
syn_html += "<hr>\n"
syn_html += f"Pour : {syn['decompte']['pour']}<br>\n"
syn_html += f"Contre : {syn['decompte']['contre']}<br>\n"
syn_html += f"Abstentions : {syn['decompte']['abstentions']}<br>\n"
if scrutin['sort']['code'] == 'rejeté':
syn_html += "<span style=\"color: red;\">"
else:
syn_html += "<span style=\"color: green;\">"
syn_html += scrutin['sort']['libelle']
syn_html += "</span>\n"
syn_html += "</td>\n"
syn_html += "</tr>\n"
syn_html += "</tbody>\n"
syn_html += f"<tfoot>\n<tr>\n<th colspan=\"4\">\nScrutin n°{scrutin['numero']}, réalisé le {datetime.date.fromisoformat(scrutin['dateScrutin']):%d/%m/%Y}</th>\n</tr>\n</tfoot>\n"
syn_html += "</table>\n</body>\n</html>"
with open('/tmp/img.html', 'w') as f: with open('/tmp/img.html', 'w') as f:
f.write(syn_text) f.write(syn_html)
alt_text = "Tableau présentant les votes de l'amendement\n\n" + \
f"Exprimés : {syn['suffragesExprimes']}\n" + \
f"Pour : {syn['decompte']['pour']}\n" + \
f"Contre : {syn['decompte']['contre']}\n" + \
f"Abstentions : {syn['decompte']['abstentions']}\n\n" + \
scrutin['sort']['libelle']
subprocess.run(['wkhtmltoimage', '/tmp/img.html', '/tmp/img.jpg']) subprocess.run(['wkhtmltoimage', '/tmp/img.html', '/tmp/img.jpg'])
result_media = api.media_upload("/tmp/img.jpg") result_media = api.media_upload("/tmp/img.jpg")
api.create_media_metadata(result_media.media_id, syn_text[:1000]) api.create_media_metadata(result_media.media_id, alt_text)
message = obj['message'].format(date=date, nb_jours=delta) message = obj['message'].format(date=date, nb_jours=delta)
client.create_tweet(text=message, media_ids=[result_media.media_id, text_media.media_id])) client.create_tweet(text=message, media_ids=[result_media.media_id, text_media.media_id])
def main(): def main():
@ -147,5 +223,26 @@ def main():
with open(os.path.join(BASE_PATH, 'data', 'votes.json')) as f: with open(os.path.join(BASE_PATH, 'data', 'votes.json')) as f:
data = json.load(f) data = json.load(f)
for groupe_id in GROUPES_ID:
with open(os.path.join(BASE_PATH, 'data', str(LEG), 'Organes', f"{groupe_id}.json")) as f:
groupe = json.load(f)['organe']
groupe['deputes'] = set()
GROUPES[groupe_id] = groupe
for filename in os.listdir(os.path.join(BASE_PATH, 'data', str(LEG), 'Acteurs')):
with open(os.path.join(os.path.join(BASE_PATH, 'data', str(LEG), 'Acteurs', filename))) as f:
acteur = json.load(f)['acteur']
for mandat in acteur['mandats']['mandat']:
organes = mandat['organes']['organeRef']
if not isinstance(organes, list):
organes = [organes]
for organe in organes:
if organe in GROUPES:
groupe = GROUPES[organe]
groupe['deputes'].add(acteur['uid']['#text'])
for g in GROUPES.values():
print(g['libelle'], len(g['deputes']))
obj = random.choice(data) obj = random.choice(data)
publish_amendement(obj, api, client) publish_amendement(obj, api, client)