diff --git a/.travis.yml b/.travis.yml index 4810af8a9e412377fafa6b09ca5998b6c6bc1e6a..1bce27eafaa09288cd8bb708c30167038d4ca52e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,6 +14,9 @@ script: - django-admin migrate - flake8 representatives_votes/ --exclude migrations --ignore E128 - py.test +- cat representatives_votes/contrib/francedata/tests/dossiers_input.json | francedata_import_dossiers +- cat representatives_votes/contrib/francedata/tests/scrutins_input.json | francedata_import_scrutins +- cat representatives_votes/contrib/francedata/tests/votes_input.json | francedata_import_votes - cat representatives_votes/contrib/parltrack/tests/dossiers_fixture.json | parltrack_import_dossiers - cat representatives_votes/contrib/parltrack/tests/votes_fixture.json | parltrack_import_votes after_success: diff --git a/representatives_votes/contrib/francedata/__init__.py b/representatives_votes/contrib/francedata/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/representatives_votes/contrib/francedata/import_dossiers.py b/representatives_votes/contrib/francedata/import_dossiers.py new file mode 100644 index 0000000000000000000000000000000000000000..fad680b0480c1614dc15451101d947aef67eb751 --- /dev/null +++ b/representatives_votes/contrib/francedata/import_dossiers.py @@ -0,0 +1,48 @@ +# coding: utf-8 + +import sys +import ijson +import logging + +import django +from django.apps import apps + +from representatives_votes.models import Dossier + +logger = logging.getLogger(__name__) + + +def parse_dossier_data(data): + changed = False + ref = data['uri'] + + try: + dossier = Dossier.objects.get(reference=ref) + except Dossier.DoesNotExist: + dossier = Dossier(reference=ref) + logger.debug('Created dossier %s' % ref) + changed = True + + title = data['titre'] + if dossier.title != title: + logger.debug('Changed dossier title to %s' % title) + dossier.title = title + changed = True + + source = data['url'] + if dossier.link != source: + logger.debug('Changed dossier link to %s' % source) + dossier.link = source + changed = True + + if changed: + logger.debug('Saved dossier %s' % ref) + dossier.save() + + +def main(stream=None): + if not apps.ready: + django.setup() + + for data in ijson.items(stream or sys.stdin, 'item'): + parse_dossier_data(data) diff --git a/representatives_votes/contrib/francedata/import_scrutins.py b/representatives_votes/contrib/francedata/import_scrutins.py new file mode 100644 index 0000000000000000000000000000000000000000..111de784d0a404d2d138871565005fc7372e1c37 --- /dev/null +++ b/representatives_votes/contrib/francedata/import_scrutins.py @@ -0,0 +1,109 @@ +# coding: utf-8 + +from datetime import datetime +import ijson +import logging +from pytz import timezone as date_timezone +import sys + +import django +from django.apps import apps +from django.utils.timezone import make_aware as date_make_aware + +from representatives_votes.models import Dossier, Proposal + +logger = logging.getLogger(__name__) + + +def _parse_date(date_str): + return date_make_aware( + datetime.strptime(date_str, "%Y-%m-%d"), + date_timezone('Europe/Paris') + ) + + +def _get_unique_title(proposal_pk, candidate): + title = candidate + + try: + exists = Proposal.objects.get(title=title) + except Proposal.DoesNotExist: + exists = None + + if exists and exists.pk != proposal_pk: + num = 1 + while exists and exists.pk != proposal_pk: + title = '%s (%d)' % (candidate, num) + + try: + exists = Proposal.objects.get(title=title) + except Proposal.DoesNotExist: + exists = None + + num = num + 1 + + logger.debug('Made unique title %s' % title) + + return title + + +class ScrutinImporter: + dossiers = None + + def get_dossier(self, ref): + if self.dossiers is None: + self.dossiers = { + d[0]: d[1] for d in Dossier.objects.values_list('reference', + 'pk') + } + + return self.dossiers.get(ref, None) + + def parse_scrutin_data(self, data): + ref = data['uri'] + + if 'dossier_uri' not in data: + logger.debug('Cannot create proposal without dossier') + return + + dossier = self.get_dossier(data['dossier_uri']) + if dossier is None: + logger.debug('Cannot create proposal for unknown dossier %s' + % data['dossier_uri']) + return + + changed = False + try: + proposal = Proposal.objects.get(reference=ref) + except Proposal.DoesNotExist: + proposal = Proposal(reference=ref, total_for=0, total_against=0, + total_abstain=0) + logger.debug('Created proposal %s' % ref) + changed = True + + values = dict( + title=_get_unique_title(proposal.pk, data["objet"]), + datetime=_parse_date(data["date"]), + dossier_id=self.get_dossier(data['dossier_uri']), + kind='dossier' + ) + + for key, value in values.items(): + if value != getattr(proposal, key, None): + logger.debug('Changed proposal %s to %s' % (key, value)) + setattr(proposal, key, value) + changed = True + + if changed: + logger.debug('Updated proposal %s' % ref) + proposal.save() + + +def main(stream=None): + if not apps.ready: + django.setup() + + importer = ScrutinImporter() + + for data in ijson.items(stream or sys.stdin, 'item'): + importer.parse_scrutin_data(data) diff --git a/representatives_votes/contrib/francedata/import_votes.py b/representatives_votes/contrib/francedata/import_votes.py new file mode 100644 index 0000000000000000000000000000000000000000..c0796e71af8a3b3fe1eaf0e9b2c22bc5e918da4e --- /dev/null +++ b/representatives_votes/contrib/francedata/import_votes.py @@ -0,0 +1,114 @@ +# coding: utf-8 + +import ijson +import logging +import sys + +import django +from django.apps import apps +from django.utils.text import slugify + +from representatives_votes.models import Proposal, Representative, Vote + +logger = logging.getLogger(__name__) + + +class VotesImporter: + deputes = None + scrutins = None + touched = [] + + positions = dict( + pour="for", + contre="against", + abstention="abstain" + ) + + def get_depute(self, prenom, nom): + if self.deputes is None: + self.deputes = { + slugify(r[0]): r[1] for r in + Representative.objects.values_list('full_name', 'pk') + } + + full = (u'%s %s' % (prenom, nom)).replace(u'Â ', ' ') + return self.deputes.get(slugify(full), None) + + def get_scrutin(self, ref): + if self.scrutins is None: + self.scrutins = { + s[0]: s[1] for s in Proposal.objects.values_list('reference', + 'pk') + } + + return self.scrutins.get(ref, None) + + def parse_vote_data(self, data): + scrutin = self.get_scrutin(data['scrutin_uri']) + if scrutin is None: + logger.debug('Cannot import vote for unknown scrutin %s' + % data['scrutin_uri']) + return + + depute = self.get_depute(data['prenom'], data['nom']) + if depute is None: + logger.debug('Cannot import vote by unknown rep %s %s' + % (data['prenom'], data['nom'])) + return + + if not data['division'].lower() in self.positions: + logger.debug('Cannot import vote for invalid position %s' + % data['division']) + return + position = self.positions[data['division'].lower()] + + changed = False + try: + vote = Vote.objects.get(representative_id=depute, + proposal_id=scrutin) + except Vote.DoesNotExist: + vote = Vote(representative_id=depute, proposal_id=scrutin) + logger.debug('Created vote for rep %s on %s' % (depute, scrutin)) + changed = True + + if vote.position != position: + logger.debug('Changed vote position to %s' % position) + changed = True + vote.position = position + + if changed: + logger.debug('Updated vote for rep %s on %s' % (depute, scrutin)) + self.touched.append(scrutin) + vote.save() + + def update_totals(self): + proposals = [Proposal.objects.get(pk=pk) for pk in self.touched] + + for proposal in proposals: + changed = False + + for pos in self.positions.values(): + count = Vote.objects.filter(proposal_id=proposal.pk, + position=pos).count() + + if getattr(proposal, 'total_%s' % pos, None) != count: + logger.debug('Changed %s count for proposal %s to %s' % ( + pos, proposal.pk, count)) + setattr(proposal, 'total_%s' % pos, count) + changed = True + + if changed: + logger.debug('Updated proposal %s' % proposal.pk) + proposal.save() + + +def main(stream=None): + if not apps.ready: + django.setup() + + importer = VotesImporter() + + for data in ijson.items(stream or sys.stdin, 'item'): + importer.parse_vote_data(data) + + importer.update_totals() diff --git a/representatives_votes/contrib/francedata/tests/dossiers_expected.json b/representatives_votes/contrib/francedata/tests/dossiers_expected.json new file mode 100644 index 0000000000000000000000000000000000000000..463f4979794966dc7b43696a4db50618ba4c2be1 --- /dev/null +++ b/representatives_votes/contrib/francedata/tests/dossiers_expected.json @@ -0,0 +1,28 @@ +[ +{ + "fields": { + "updated": "2016-02-14T13:16:31.417Z", + "reference": "/14/dossiers/liberte_maires_rythmes_scolaires_premier_degre.asp", + "title": "Education : libre choix des maires concernant les rythmes scolaires dans le premier degr\u00e9", + "text": "", + "created": "2016-02-14T13:16:31.417Z", + "link": "http://www.assemblee-nationale.fr/14/dossiers/liberte_maires_rythmes_scolaires_premier_degre.asp", + "fingerprint": "5d1707e6663bb28d0308cdb36e9e91c5f235f8a1" + }, + "model": "representatives_votes.dossier", + "pk": 1 +}, +{ + "fields": { + "updated": "2016-02-14T13:16:31.428Z", + "reference": "/14/dossiers/action_publique_territoriale_metropoles.asp", + "title": "Collectivit\u00e9s territoriales : action publique territoriale et m\u00e9tropoles", + "text": "", + "created": "2016-02-14T13:16:31.428Z", + "link": "http://www.assemblee-nationale.fr/14/dossiers/action_publique_territoriale_metropoles.asp", + "fingerprint": "c03f5e32f66e5f03ebe0a5d100f2f4ade941accc" + }, + "model": "representatives_votes.dossier", + "pk": 2 +} +] diff --git a/representatives_votes/contrib/francedata/tests/dossiers_input.json b/representatives_votes/contrib/francedata/tests/dossiers_input.json new file mode 100644 index 0000000000000000000000000000000000000000..e0214ed33a79c52301e248771cbb3acd09895b5f --- /dev/null +++ b/representatives_votes/contrib/francedata/tests/dossiers_input.json @@ -0,0 +1,12 @@ +[ + { + "url": "http://www.assemblee-nationale.fr/14/dossiers/liberte_maires_rythmes_scolaires_premier_degre.asp", + "titre": "Education : libre choix des maires concernant les rythmes scolaires dans le premier degr\u00e9", + "uri": "/14/dossiers/liberte_maires_rythmes_scolaires_premier_degre.asp" + }, + { + "url": "http://www.assemblee-nationale.fr/14/dossiers/action_publique_territoriale_metropoles.asp", + "titre": "Collectivit\u00e9s territoriales : action publique territoriale et m\u00e9tropoles", + "uri": "/14/dossiers/action_publique_territoriale_metropoles.asp" + } +] \ No newline at end of file diff --git a/representatives_votes/contrib/francedata/tests/rep_fixture.json b/representatives_votes/contrib/francedata/tests/rep_fixture.json new file mode 100644 index 0000000000000000000000000000000000000000..027e8fb93b49d3a8d08089a5bca0d14ce5bca732 --- /dev/null +++ b/representatives_votes/contrib/francedata/tests/rep_fixture.json @@ -0,0 +1,22 @@ +[ +{ + "fields": { + "updated": "2016-02-14T14:01:37.343Z", + "last_name": "", + "photo": "http://www.nosdeputes.fr/depute/photo/bernard-roman", + "created": "2016-02-14T14:01:37.343Z", + "gender": 2, + "remote_id": "2611", + "first_name": "", + "cv": "", + "active": true, + "birth_place": "Lille (Nord)", + "full_name": "Bernard Roman", + "fingerprint": "e28b45cced3c89ad3835fbdf261367ebea91b180", + "birth_date": "1952-07-15", + "slug": "bernard-roman" + }, + "model": "representatives.representative", + "pk": 1 +} +] diff --git a/representatives_votes/contrib/francedata/tests/scrutins_expected.json b/representatives_votes/contrib/francedata/tests/scrutins_expected.json new file mode 100644 index 0000000000000000000000000000000000000000..2326efc68d5be382cfdeecf5ac65a8930b33cd22 --- /dev/null +++ b/representatives_votes/contrib/francedata/tests/scrutins_expected.json @@ -0,0 +1,74 @@ +[ +{ + "fields": { + "updated": "2016-02-14T13:44:37.550Z", + "total_for": 0, + "description": "", + "reference": "/scrutins/detail/(legislature)/14/(num)/740", + "title": "La motion de rejet pr\u00e9alable, pr\u00e9sent\u00e9e par m. le roux, de la proposition de loi permettant le libre choix des maires concernant les rythmes scolaires dans l'enseignement du premier degr\u00e9.", + "dossier": 1, + "created": "2016-02-14T13:44:37.550Z", + "kind": "dossier", + "datetime": "2013-12-04T23:00:00Z", + "total_against": 0, + "fingerprint": "40bb927c36b00bb688c1d7e7f4be5b9a1aae4af3", + "total_abstain": 0 + }, + "model": "representatives_votes.proposal", + "pk": 1 +}, +{ + "fields": { + "updated": "2016-02-14T13:44:37.578Z", + "total_for": 0, + "description": "", + "reference": "/scrutins/detail/(legislature)/14/(num)/740-2", + "title": "La motion de rejet pr\u00e9alable, pr\u00e9sent\u00e9e par m. le roux, de la proposition de loi permettant le libre choix des maires concernant les rythmes scolaires dans l'enseignement du premier degr\u00e9. (1)", + "dossier": 1, + "created": "2016-02-14T13:44:37.578Z", + "kind": "dossier", + "datetime": "2013-12-05T23:00:00Z", + "total_against": 0, + "fingerprint": "a8709fb12e8e6e4a5f46931d855bf70453dd7fd2", + "total_abstain": 0 + }, + "model": "representatives_votes.proposal", + "pk": 2 +}, +{ + "fields": { + "updated": "2016-02-14T13:44:37.587Z", + "total_for": 0, + "description": "", + "reference": "/scrutins/detail/(legislature)/14/(num)/748", + "title": "L'amendement n\u00b0 381 de m. dolez \u00e0 l'article 2 du projet de loi de modernisation de l'action publique territoriale et d'affirmation des m\u00e9tropoles.", + "dossier": 2, + "created": "2016-02-14T13:44:37.587Z", + "kind": "dossier", + "datetime": "2013-12-10T23:00:00Z", + "total_against": 0, + "fingerprint": "abf1dbdff878fa750f6ffb33fb362cb734e553e3", + "total_abstain": 0 + }, + "model": "representatives_votes.proposal", + "pk": 3 +}, +{ + "fields": { + "updated": "2016-02-14T13:44:37.596Z", + "total_for": 0, + "description": "", + "reference": "/scrutins/detail/(legislature)/14/(num)/747", + "title": "L'amendement n\u00b0 379 de m. dolez \u00e0 l'article 1er a du projet de loi de modernisation de l'action publique territoriale et d'affirmation des m\u00e9tropoles.", + "dossier": 2, + "created": "2016-02-14T13:44:37.596Z", + "kind": "dossier", + "datetime": "2013-12-10T23:00:00Z", + "total_against": 0, + "fingerprint": "3b75e49e1be0c8efc3706b9896cc1cb1f76dd9a7", + "total_abstain": 0 + }, + "model": "representatives_votes.proposal", + "pk": 4 +} +] diff --git a/representatives_votes/contrib/francedata/tests/scrutins_input.json b/representatives_votes/contrib/francedata/tests/scrutins_input.json new file mode 100644 index 0000000000000000000000000000000000000000..5207b97b3583aacf06eefbda6608322758dda308 --- /dev/null +++ b/representatives_votes/contrib/francedata/tests/scrutins_input.json @@ -0,0 +1,47 @@ +[ + { + "objet": "La motion de rejet pr\u00e9alable, pr\u00e9sent\u00e9e par m. le roux, de la proposition de loi permettant le libre choix des maires concernant les rythmes scolaires dans l'enseignement du premier degr\u00e9.", + "url": "http://www2.assemblee-nationale.fr/scrutins/detail/(legislature)/14/(num)/740", + "uri": "/scrutins/detail/(legislature)/14/(num)/740", + "numero": "740", + "dossier_uri": "/14/dossiers/liberte_maires_rythmes_scolaires_premier_degre.asp", + "dossier_url": "http://www2.assemblee-nationale.fr/14/dossiers/liberte_maires_rythmes_scolaires_premier_degre.asp", + "date": "2013-12-05" + }, + { + "objet": "La motion de rejet pr\u00e9alable, pr\u00e9sent\u00e9e par m. le roux, de la proposition de loi permettant le libre choix des maires concernant les rythmes scolaires dans l'enseignement du premier degr\u00e9.", + "url": "http://www2.assemblee-nationale.fr/scrutins/detail/(legislature)/14/(num)/740-2", + "uri": "/scrutins/detail/(legislature)/14/(num)/740-2", + "numero": "740-2", + "dossier_uri": "/14/dossiers/liberte_maires_rythmes_scolaires_premier_degre.asp", + "dossier_url": "http://www2.assemblee-nationale.fr/14/dossiers/liberte_maires_rythmes_scolaires_premier_degre.asp", + "date": "2013-12-06" + }, + { + "objet": "L'amendement n\u00b0 381 de m. dolez \u00e0 l'article 2 du projet de loi de modernisation de l'action publique territoriale et d'affirmation des m\u00e9tropoles.", + "url": "http://www2.assemblee-nationale.fr/scrutins/detail/(legislature)/14/(num)/748", + "uri": "/scrutins/detail/(legislature)/14/(num)/748", + "numero": "748", + "dossier_uri": "/14/dossiers/action_publique_territoriale_metropoles.asp", + "dossier_url": "http://www2.assemblee-nationale.fr/14/dossiers/action_publique_territoriale_metropoles.asp", + "date": "2013-12-11" + }, + { + "objet": "L'amendement n\u00b0 379 de m. dolez \u00e0 l'article 1er a du projet de loi de modernisation de l'action publique territoriale et d'affirmation des m\u00e9tropoles.", + "url": "http://www2.assemblee-nationale.fr/scrutins/detail/(legislature)/14/(num)/747", + "uri": "/scrutins/detail/(legislature)/14/(num)/747", + "numero": "747", + "dossier_uri": "/14/dossiers/action_publique_territoriale_metropoles.asp", + "dossier_url": "http://www2.assemblee-nationale.fr/14/dossiers/action_publique_territoriale_metropoles.asp", + "date": "2013-12-11" + }, + { + "objet": "Dossier inexistant.", + "url": "http://www2.assemblee-nationale.fr/404", + "uri": "/scrutins/404", + "numero": "000", + "dossier_uri": "/14/dossiers/inexistant", + "dossier_url": "http://www2.assemblee-nationale.fr/14/dossiers/inexistant", + "date": "2099-12-11" + } +] \ No newline at end of file diff --git a/representatives_votes/contrib/francedata/tests/test_francedata_import.py b/representatives_votes/contrib/francedata/tests/test_francedata_import.py new file mode 100644 index 0000000000000000000000000000000000000000..3f38d6c5b96602cb480f2d9527cb540d4e0b3ca7 --- /dev/null +++ b/representatives_votes/contrib/francedata/tests/test_francedata_import.py @@ -0,0 +1,70 @@ +import copy +import os +import pytest + +from django.core.serializers.json import Deserializer +from django.core.management import call_command + +from representatives.models import Representative +from representatives_votes.contrib.francedata import import_dossiers +from representatives_votes.contrib.francedata import import_scrutins +from representatives_votes.contrib.francedata import import_votes +from representatives_votes.models import Dossier, Proposal, Vote + + +def _get_testdata(filename): + return os.path.join(os.path.dirname(__file__), filename) + + +def _test_import(fixtures, scenario, callback): + for model in (Representative, Dossier, Proposal, Vote): + model.objects.all().delete() + + for fix in fixtures: + call_command('loaddata', fix) + + inputfile = _get_testdata('%s_input.json' % scenario) + expected = _get_testdata('%s_expected.json' % scenario) + + # Disable django auto fields + exclude = ('id', '_state', 'created', 'updated', 'fingerprint') + + with open(inputfile, 'r') as f: + callback(f) + + with open(expected, 'r') as f: + for obj in Deserializer(f.read()): + compare = copy.copy(obj.object.__dict__) + + for f in exclude: + if f in compare: + compare.pop(f) + + type(obj.object).objects.get(**compare) + + +@pytest.mark.django_db +def test_francedata_import_dossiers(): + fixtures = [] + + _test_import(fixtures, 'dossiers', import_dossiers.main) + + +@pytest.mark.django_db +def test_francedata_import_scrutins(): + fixtures = [ + _get_testdata('dossiers_expected.json') + ] + + _test_import(fixtures, 'scrutins', import_scrutins.main) + + +@pytest.mark.django_db +def test_francedata_import_votes(): + fixtures = [ + _get_testdata('dossiers_expected.json'), + _get_testdata('scrutins_expected.json'), + _get_testdata('rep_fixture.json') + ] + + _test_import(fixtures, 'votes', import_votes.main) diff --git a/representatives_votes/contrib/francedata/tests/votes_expected.json b/representatives_votes/contrib/francedata/tests/votes_expected.json new file mode 100644 index 0000000000000000000000000000000000000000..45af92116a81f51dacb9ad7eec1c86864e53afea --- /dev/null +++ b/representatives_votes/contrib/francedata/tests/votes_expected.json @@ -0,0 +1,104 @@ +[ +{ + "fields": { + "updated": "2016-02-14T13:58:46.991Z", + "total_for": 1, + "description": "", + "reference": "/scrutins/detail/(legislature)/14/(num)/740", + "title": "La motion de rejet pr\u00e9alable, pr\u00e9sent\u00e9e par m. le roux, de la proposition de loi permettant le libre choix des maires concernant les rythmes scolaires dans l'enseignement du premier degr\u00e9.", + "dossier": 1, + "created": "2016-02-14T13:58:00.536Z", + "kind": "dossier", + "datetime": "2013-12-04T23:00:00Z", + "total_against": 0, + "fingerprint": "73ca11e690cc6db1d806f927538d05b49eb6fd9d", + "total_abstain": 0 + }, + "model": "representatives_votes.proposal", + "pk": 1 +}, +{ + "fields": { + "updated": "2016-02-14T13:58:47.003Z", + "total_for": 0, + "description": "", + "reference": "/scrutins/detail/(legislature)/14/(num)/740-2", + "title": "La motion de rejet pr\u00e9alable, pr\u00e9sent\u00e9e par m. le roux, de la proposition de loi permettant le libre choix des maires concernant les rythmes scolaires dans l'enseignement du premier degr\u00e9. (1)", + "dossier": 1, + "created": "2016-02-14T13:58:00.551Z", + "kind": "dossier", + "datetime": "2013-12-05T23:00:00Z", + "total_against": 1, + "fingerprint": "92ece2396838f1612ada0d896cbdce8fe5deaf13", + "total_abstain": 0 + }, + "model": "representatives_votes.proposal", + "pk": 2 +}, +{ + "fields": { + "updated": "2016-02-14T13:58:47.016Z", + "total_for": 0, + "description": "", + "reference": "/scrutins/detail/(legislature)/14/(num)/748", + "title": "L'amendement n\u00b0 381 de m. dolez \u00e0 l'article 2 du projet de loi de modernisation de l'action publique territoriale et d'affirmation des m\u00e9tropoles.", + "dossier": 2, + "created": "2016-02-14T13:58:00.561Z", + "kind": "dossier", + "datetime": "2013-12-10T23:00:00Z", + "total_against": 0, + "fingerprint": "4379d073c5ffd05ecbf9a0d7e69c4e519050a90a", + "total_abstain": 1 + }, + "model": "representatives_votes.proposal", + "pk": 3 +}, +{ + "fields": { + "updated": "2016-02-14T13:58:00.571Z", + "total_for": 0, + "description": "", + "reference": "/scrutins/detail/(legislature)/14/(num)/747", + "title": "L'amendement n\u00b0 379 de m. dolez \u00e0 l'article 1er a du projet de loi de modernisation de l'action publique territoriale et d'affirmation des m\u00e9tropoles.", + "dossier": 2, + "created": "2016-02-14T13:58:00.571Z", + "kind": "dossier", + "datetime": "2013-12-10T23:00:00Z", + "total_against": 0, + "fingerprint": "3b75e49e1be0c8efc3706b9896cc1cb1f76dd9a7", + "total_abstain": 0 + }, + "model": "representatives_votes.proposal", + "pk": 4 +}, +{ + "fields": { + "representative_name": "", + "position": "for", + "proposal": 1, + "representative": 1 + }, + "model": "representatives_votes.vote", + "pk": 1 +}, +{ + "fields": { + "representative_name": "", + "position": "against", + "proposal": 2, + "representative": 1 + }, + "model": "representatives_votes.vote", + "pk": 2 +}, +{ + "fields": { + "representative_name": "", + "position": "abstain", + "proposal": 3, + "representative": 1 + }, + "model": "representatives_votes.vote", + "pk": 3 +} +] diff --git a/representatives_votes/contrib/francedata/tests/votes_input.json b/representatives_votes/contrib/francedata/tests/votes_input.json new file mode 100644 index 0000000000000000000000000000000000000000..21de9503e5f7180134ce5893e88a962fb3f619e2 --- /dev/null +++ b/representatives_votes/contrib/francedata/tests/votes_input.json @@ -0,0 +1,44 @@ +[ + { + "groupe": "Whatever", + "division": "Pour", + "scrutin_uri": "/scrutins/detail/(legislature)/14/(num)/740", + "prenom": "Bernard", + "nom": "Roman" + }, + { + "groupe": "Whatever", + "division": "Contre", + "scrutin_uri": "/scrutins/detail/(legislature)/14/(num)/740-2", + "prenom": "Bernard", + "nom": "Roman" + }, + { + "groupe": "Whatever", + "division": "Abstention", + "scrutin_uri": "/scrutins/detail/(legislature)/14/(num)/748", + "prenom": "Bernard", + "nom": "Roman" + }, + { + "groupe": "Whatever", + "division": "Invalide", + "scrutin_uri": "/scrutins/detail/(legislature)/14/(num)/747", + "prenom": "Bernard", + "nom": "Roman" + }, + { + "groupe": "Whatever", + "division": "Pour", + "scrutin_uri": "/scrutins/detail/(legislature)/14/(num)/nonexisting", + "prenom": "Bernard", + "nom": "Roman" + }, + { + "groupe": "Whatever", + "division": "Pour", + "scrutin_uri": "/scrutins/detail/(legislature)/14/(num)/747", + "prenom": "Non", + "nom": "Existing" + } +] \ No newline at end of file diff --git a/representatives_votes/contrib/parltrack/tests/test_import.py b/representatives_votes/contrib/parltrack/tests/test_parltrack_import.py similarity index 100% rename from representatives_votes/contrib/parltrack/tests/test_import.py rename to representatives_votes/contrib/parltrack/tests/test_parltrack_import.py diff --git a/setup.py b/setup.py index f5e5ea22a08ce2045533d669b8ece8d73a67d8b0..04490fc7da417bbd8f057970bc064925a24bc092 100644 --- a/setup.py +++ b/setup.py @@ -12,7 +12,7 @@ setup( license='GPLv3', keywords='django government parliament votes', install_requires=[ - 'django-representatives>=0.0.13', + 'django-representatives>=0.0.15', 'py-dateutil', 'pytz', 'ijson', @@ -27,6 +27,9 @@ setup( 'console_scripts': [ 'parltrack_import_dossiers = representatives_votes.contrib.parltrack.import_dossiers:main', 'parltrack_import_votes = representatives_votes.contrib.parltrack.import_votes:main', + 'francedata_import_dossiers = representatives_votes.contrib.francedata.import_dossiers:main', + 'francedata_import_scrutins = representatives_votes.contrib.francedata.import_scrutins:main', + 'francedata_import_votes = representatives_votes.contrib.francedata.import_votes:main', ] }, classifiers=[