2024-06-08 17:10:19 +02:00
|
|
|
import json
|
2024-06-16 07:27:02 +02:00
|
|
|
from pathlib import Path
|
2024-06-08 17:10:19 +02:00
|
|
|
|
|
|
|
import requests
|
|
|
|
from sqlalchemy import Engine, select
|
|
|
|
from sqlalchemy.orm import Session
|
2024-06-14 23:58:36 +02:00
|
|
|
from tqdm import tqdm
|
2024-06-08 17:10:19 +02:00
|
|
|
|
2024-06-08 23:06:41 +02:00
|
|
|
from nupes.cache import get_file
|
2024-06-08 17:10:19 +02:00
|
|
|
from nupes.models.geographie import BureauVote, Circonscription, Commune, Departement, Region
|
|
|
|
|
|
|
|
|
2024-06-13 12:21:11 +02:00
|
|
|
def importer_regions(engine: Engine, verbose: bool = False) -> None:
|
2024-06-08 17:10:19 +02:00
|
|
|
etag = requests.get(
|
|
|
|
"https://public.opendatasoft.com/api/explore/v2.1/catalog/datasets"
|
|
|
|
"/georef-france-region?select=data_processed").json()['data_processed']
|
|
|
|
file = get_file("https://public.opendatasoft.com/api/explore/v2.1/catalog/datasets"
|
2024-06-13 11:22:23 +02:00
|
|
|
"/georef-france-region/exports/geojson?lang=fr&timezone=Europe%2FParis",
|
2024-06-08 19:38:59 +02:00
|
|
|
"georef-france-region.geojson", etag)
|
2024-06-08 17:10:19 +02:00
|
|
|
|
|
|
|
with file.open('r') as f:
|
|
|
|
features = json.load(f)['features']
|
|
|
|
|
|
|
|
with Session(engine) as session:
|
2024-06-14 23:58:36 +02:00
|
|
|
for feature in tqdm(features, desc="Régions", disable=not verbose):
|
2024-06-08 17:10:19 +02:00
|
|
|
region_dict = feature['properties']
|
|
|
|
code_region = region_dict['reg_code'][0]
|
|
|
|
nom_region = region_dict['reg_name'][0]
|
|
|
|
|
|
|
|
if region := session.execute(select(Region).filter_by(code_insee=code_region)).scalar_one_or_none():
|
|
|
|
region.libelle = nom_region
|
|
|
|
region.geometry = feature['geometry']
|
|
|
|
else:
|
|
|
|
region = Region(code_insee=code_region, libelle=nom_region, geometry=feature['geometry'])
|
|
|
|
session.add(region)
|
|
|
|
|
2024-06-15 19:54:49 +02:00
|
|
|
if reg := session.execute(select(Region).filter_by(code_insee="ZZ")).scalar_one_or_none():
|
|
|
|
reg.libelle = "Français⋅es de l'étranger"
|
|
|
|
else:
|
|
|
|
session.add(Region(code_insee="ZZ", libelle="Français⋅es de l'étranger", geometry={}))
|
|
|
|
|
2024-06-08 17:10:19 +02:00
|
|
|
session.commit()
|
|
|
|
|
|
|
|
|
2024-06-13 12:21:11 +02:00
|
|
|
def importer_departements(engine: Engine, verbose: bool = False) -> None:
|
2024-06-08 17:10:19 +02:00
|
|
|
etag = requests.get(
|
|
|
|
"https://public.opendatasoft.com/api/explore/v2.1/catalog/datasets"
|
|
|
|
"/georef-france-departement?select=data_processed").json()['data_processed']
|
|
|
|
file = get_file("https://public.opendatasoft.com/api/explore/v2.1/catalog/datasets"
|
2024-06-13 11:22:23 +02:00
|
|
|
"/georef-france-departement/exports/geojson?lang=fr&timezone=Europe%2FParis",
|
2024-06-08 19:38:59 +02:00
|
|
|
"georef-france-departement.geojson", etag)
|
2024-06-08 17:10:19 +02:00
|
|
|
|
|
|
|
with file.open('r') as f:
|
|
|
|
features = json.load(f)['features']
|
|
|
|
|
|
|
|
with Session(engine) as session:
|
2024-06-14 23:58:36 +02:00
|
|
|
for feature in tqdm(features, desc="Départements", disable=not verbose):
|
2024-06-08 17:10:19 +02:00
|
|
|
dpt_dict = feature['properties']
|
|
|
|
code_dpt = dpt_dict['dep_code'][0]
|
|
|
|
nom_dpt = dpt_dict['dep_name'][0]
|
|
|
|
|
|
|
|
if dpt := session.execute(select(Departement).filter_by(code_insee=code_dpt)).scalar_one_or_none():
|
|
|
|
dpt.libelle = nom_dpt
|
|
|
|
dpt.region_code = dpt_dict['reg_code'][0]
|
|
|
|
dpt.geometry = feature['geometry']
|
|
|
|
else:
|
|
|
|
dpt = Departement(code_insee=code_dpt, libelle=nom_dpt, region_code=dpt_dict['reg_code'][0],
|
|
|
|
geometry=feature['geometry'])
|
|
|
|
session.add(dpt)
|
|
|
|
|
2024-06-15 19:54:49 +02:00
|
|
|
reg_etranger = session.execute(select(Region).filter_by(code_insee="ZZ")).scalar_one_or_none()
|
|
|
|
if dpt := session.execute(select(Departement).filter_by(code_insee="ZZ")).scalar_one_or_none():
|
|
|
|
dpt.libelle = "Français⋅es de l'étranger"
|
|
|
|
dpt.region_code = reg_etranger.code_insee
|
|
|
|
else:
|
|
|
|
session.add(Departement(code_insee="ZZ", region_code=reg_etranger.code_insee,
|
|
|
|
libelle="Français⋅es de l'étranger", geometry={}))
|
|
|
|
|
2024-06-08 17:10:19 +02:00
|
|
|
session.commit()
|
|
|
|
|
|
|
|
|
2024-06-15 00:11:31 +02:00
|
|
|
def importer_circonscriptions(engine: Engine, verbose: bool = False) -> None:
|
|
|
|
file = get_file("https://www.data.gouv.fr/fr/datasets/r/67c0f382-dc8d-4d1f-8a76-1162c53b9dfe",
|
|
|
|
"circonscriptions-legislatives-p10.geojson")
|
|
|
|
|
|
|
|
with file.open('r') as f:
|
|
|
|
features = json.load(f)['features']
|
|
|
|
|
|
|
|
with Session(engine) as session:
|
|
|
|
for feature in tqdm(features, desc="Circonscriptions", disable=not verbose):
|
|
|
|
circo_dict = feature['properties']
|
|
|
|
code_circo = circo_dict['codeCirconscription']
|
|
|
|
code_dpt = circo_dict['codeDepartement']
|
|
|
|
|
|
|
|
match code_dpt:
|
|
|
|
case "ZA":
|
|
|
|
code_dpt = "971"
|
|
|
|
case "ZB":
|
|
|
|
code_dpt = "972"
|
|
|
|
case "ZC":
|
|
|
|
code_dpt = "973"
|
|
|
|
case "ZD":
|
|
|
|
code_dpt = "974"
|
|
|
|
case "ZS":
|
|
|
|
code_dpt = "975"
|
|
|
|
case "ZM":
|
|
|
|
code_dpt = "976"
|
|
|
|
|
|
|
|
numero_circo = int(code_circo[len(code_dpt):])
|
|
|
|
circo_id = f"{code_dpt}-{numero_circo:02d}"
|
|
|
|
|
|
|
|
if not session.execute(select(Departement).filter_by(code_insee=code_dpt)).scalar_one_or_none():
|
|
|
|
print("Département non trouvé avec le code", code_dpt)
|
|
|
|
continue
|
|
|
|
|
|
|
|
if circo := session.execute(select(Circonscription).filter_by(id=circo_id)).scalar_one_or_none():
|
|
|
|
circo.departement_code = code_dpt
|
|
|
|
circo.numero = numero_circo
|
|
|
|
circo.geometry = feature['geometry']
|
|
|
|
else:
|
|
|
|
circo = Circonscription(id=circo_id, departement_code=code_dpt, numero=numero_circo,
|
|
|
|
geometry=feature['geometry'])
|
|
|
|
session.add(circo)
|
|
|
|
|
2024-06-15 19:54:49 +02:00
|
|
|
circos_manquantes = [
|
2024-06-16 07:27:02 +02:00
|
|
|
{"id": "977-01", "dpt_id": "977", "numero": 1, "geometry": {}},
|
|
|
|
{"id": "986-01", "dpt_id": "986", "numero": 1, "geometry": {}},
|
|
|
|
{"id": "987-01", "dpt_id": "987", "numero": 1, "geometry": {}},
|
|
|
|
{"id": "987-02", "dpt_id": "987", "numero": 2, "geometry": {}},
|
|
|
|
{"id": "987-03", "dpt_id": "987", "numero": 3, "geometry": {}},
|
|
|
|
{"id": "988-01", "dpt_id": "988", "numero": 1, "geometry": {}},
|
|
|
|
{"id": "988-02", "dpt_id": "988", "numero": 2, "geometry": {}},
|
2024-06-15 19:54:49 +02:00
|
|
|
{"id": "ZZ-01", "dpt_id": "ZZ", "numero": 1, "geometry": {}},
|
|
|
|
{"id": "ZZ-02", "dpt_id": "ZZ", "numero": 2, "geometry": {}},
|
|
|
|
{"id": "ZZ-03", "dpt_id": "ZZ", "numero": 3, "geometry": {}},
|
|
|
|
{"id": "ZZ-04", "dpt_id": "ZZ", "numero": 4, "geometry": {}},
|
|
|
|
{"id": "ZZ-05", "dpt_id": "ZZ", "numero": 5, "geometry": {}},
|
|
|
|
{"id": "ZZ-06", "dpt_id": "ZZ", "numero": 6, "geometry": {}},
|
|
|
|
{"id": "ZZ-07", "dpt_id": "ZZ", "numero": 7, "geometry": {}},
|
|
|
|
{"id": "ZZ-08", "dpt_id": "ZZ", "numero": 8, "geometry": {}},
|
|
|
|
{"id": "ZZ-09", "dpt_id": "ZZ", "numero": 9, "geometry": {}},
|
|
|
|
{"id": "ZZ-10", "dpt_id": "ZZ", "numero": 10, "geometry": {}},
|
|
|
|
{"id": "ZZ-11", "dpt_id": "ZZ", "numero": 11, "geometry": {}},
|
|
|
|
]
|
|
|
|
for circo_dict in circos_manquantes:
|
2024-06-16 07:27:02 +02:00
|
|
|
circo_geometry_file = Path(__file__).parent.parent / "initial_data" \
|
|
|
|
/ f"geometry_circo_{circo_dict['id']}.json"
|
|
|
|
if circo_geometry_file.is_file():
|
|
|
|
with circo_geometry_file.open('r') as f:
|
|
|
|
circo_dict['geometry'] = json.load(f)
|
|
|
|
|
2024-06-15 19:54:49 +02:00
|
|
|
if not session.execute(select(Departement).filter_by(code_insee=circo_dict['dpt_id'])).scalar_one_or_none():
|
|
|
|
print("Département non trouvé avec le code", circo_dict['dpt_id'])
|
|
|
|
continue
|
|
|
|
|
|
|
|
if circo := session.execute(select(Circonscription).filter_by(id=circo_dict['id'])).scalar_one_or_none():
|
|
|
|
circo.departement_code = circo_dict['dpt_id']
|
|
|
|
circo.numero = circo_dict['numero']
|
|
|
|
circo.geometry = circo_dict['geometry']
|
|
|
|
else:
|
|
|
|
circo = Circonscription(id=circo_dict['id'], departement_code=circo_dict['dpt_id'],
|
|
|
|
numero=circo_dict['numero'], geometry=circo_dict['geometry'])
|
|
|
|
session.add(circo)
|
|
|
|
|
2024-06-15 00:11:31 +02:00
|
|
|
session.commit()
|
|
|
|
|
|
|
|
|
2024-06-13 12:21:11 +02:00
|
|
|
def importer_communes(engine: Engine, verbose: bool = False) -> None:
|
2024-06-08 17:10:19 +02:00
|
|
|
etag = requests.get(
|
|
|
|
"https://public.opendatasoft.com/api/explore/v2.1/catalog/datasets"
|
2024-06-13 11:22:23 +02:00
|
|
|
"/georef-france-commune-arrondissement-municipal?select=data_processed").json()['data_processed']
|
2024-06-08 17:10:19 +02:00
|
|
|
file = get_file("https://public.opendatasoft.com/api/explore/v2.1/catalog/datasets"
|
2024-06-13 11:22:23 +02:00
|
|
|
"/georef-france-commune-arrondissement-municipal/exports/geojson?lang=fr&timezone=Europe%2FParis",
|
|
|
|
"georef-france-commune-arrondissement-municipal.geojson", etag)
|
2024-06-08 17:10:19 +02:00
|
|
|
|
|
|
|
with file.open('r') as f:
|
|
|
|
features = json.load(f)['features']
|
|
|
|
|
|
|
|
with Session(engine) as session:
|
2024-06-14 23:58:36 +02:00
|
|
|
for feature in tqdm(features, desc="Communes", disable=not verbose):
|
2024-06-08 17:10:19 +02:00
|
|
|
commune_dict = feature['properties']
|
2024-06-13 11:31:23 +02:00
|
|
|
code_commune = commune_dict['com_arm_code'][0]
|
2024-06-08 17:10:19 +02:00
|
|
|
nom_commune = commune_dict['com_name'][0]
|
|
|
|
|
|
|
|
if commune := session.execute(select(Commune).filter_by(code_insee=code_commune)).scalar_one_or_none():
|
|
|
|
commune.libelle = nom_commune
|
|
|
|
commune.departement_code = commune_dict['dep_code'][0]
|
|
|
|
commune.geometry = feature['geometry']
|
|
|
|
else:
|
|
|
|
commune = Commune(code_insee=code_commune, libelle=nom_commune,
|
|
|
|
departement_code=commune_dict['dep_code'][0], geometry=feature['geometry'])
|
|
|
|
session.add(commune)
|
|
|
|
|
2024-06-16 07:27:02 +02:00
|
|
|
geometry_paris_file = Path(__file__).parent.parent / "initial_data" / "geometry_paris.json"
|
|
|
|
geometry_lyon_file = Path(__file__).parent.parent / "initial_data" / "geometry_lyon.json"
|
|
|
|
geometry_marseille_file = Path(__file__).parent.parent / "initial_data" / "geometry_marseille.json"
|
|
|
|
|
|
|
|
with geometry_paris_file.open('r') as f:
|
|
|
|
geometry_paris = json.load(f)
|
|
|
|
with geometry_lyon_file.open('r') as f:
|
|
|
|
geometry_lyon = json.load(f)
|
|
|
|
with geometry_marseille_file.open('r') as f:
|
|
|
|
geometry_marseille = json.load(f)
|
|
|
|
|
|
|
|
paris_lyon_marseille = [
|
|
|
|
{'code_insee': "75056", 'libelle': "Paris", 'departement_code': "75", 'geometry': geometry_paris},
|
|
|
|
{'code_insee': "69123", 'libelle': "Lyon", 'departement_code': "69", 'geometry': geometry_lyon},
|
|
|
|
{'code_insee': "13055", 'libelle': "Marseille", 'departement_code': "13", 'geometry': geometry_marseille},
|
|
|
|
]
|
|
|
|
|
|
|
|
for commune_dict in paris_lyon_marseille:
|
|
|
|
if not session.execute(select(Commune).filter_by(code_insee=commune_dict['code_insee'])) \
|
|
|
|
.scalar_one_or_none():
|
|
|
|
commune = Commune(code_insee=commune_dict['code_insee'], libelle=commune_dict['libelle'],
|
|
|
|
departement_code=commune_dict['departement_code'],
|
|
|
|
geometry=commune_dict['geometry'])
|
|
|
|
session.add(commune)
|
|
|
|
|
2024-06-08 17:10:19 +02:00
|
|
|
session.commit()
|
|
|
|
|
|
|
|
|
2024-06-13 12:21:11 +02:00
|
|
|
def importer_bureaux_vote(engine: Engine, verbose: bool = False) -> None:
|
2024-06-14 23:58:36 +02:00
|
|
|
file = get_file("https://files.data.gouv.fr/reu/contours-france-entiere-latest-v2.geojson",
|
|
|
|
"contours-france-entiere-latest-v2.geojson")
|
2024-06-08 17:10:19 +02:00
|
|
|
|
|
|
|
with file.open('r') as f:
|
|
|
|
features = json.load(f)['features']
|
|
|
|
|
|
|
|
with Session(engine) as session:
|
2024-06-14 23:58:36 +02:00
|
|
|
for feature in tqdm(features, desc="Bureaux de vote", disable=not verbose):
|
2024-06-08 17:10:19 +02:00
|
|
|
bv_dict = feature['properties']
|
2024-06-14 23:58:36 +02:00
|
|
|
code_commune = bv_dict['id_bv'].split('_')[0]
|
|
|
|
code_bv = bv_dict['numeroBureauVote']
|
|
|
|
dpt_code = bv_dict['codeDepartement']
|
2024-06-15 19:54:49 +02:00
|
|
|
|
|
|
|
match dpt_code:
|
|
|
|
case "ZA":
|
|
|
|
dpt_code = "971"
|
|
|
|
case "ZB":
|
|
|
|
dpt_code = "972"
|
|
|
|
case "ZC":
|
|
|
|
dpt_code = "973"
|
|
|
|
case "ZD":
|
|
|
|
dpt_code = "974"
|
|
|
|
case "ZS":
|
|
|
|
dpt_code = "975"
|
|
|
|
case "ZM":
|
|
|
|
dpt_code = "976"
|
|
|
|
|
2024-06-14 23:58:36 +02:00
|
|
|
numero_circo = int(bv_dict['codeCirconscription'][len(dpt_code):])
|
|
|
|
code_circo = f"{dpt_code}-{numero_circo:02d}"
|
|
|
|
bv_id = bv_dict['id_bv'].split()[0]
|
2024-06-18 23:29:44 +02:00
|
|
|
|
|
|
|
if code_commune == "57447":
|
|
|
|
# Petites erreurs sur la commune de Marly
|
|
|
|
code_bv = int(bv_id.split('_')[1])
|
|
|
|
elif bv_id == "59508_3":
|
|
|
|
# Petite erreur à Roncq
|
|
|
|
code_bv = 103
|
|
|
|
|
2024-06-16 15:12:13 +02:00
|
|
|
bv_libelle = f"Bureau {code_bv} de {bv_dict['nomCommune']}"
|
2024-06-13 11:54:56 +02:00
|
|
|
|
2024-06-13 13:40:47 +02:00
|
|
|
if not session.execute(select(Commune).filter_by(code_insee=code_commune)).scalar_one_or_none():
|
2024-06-14 23:58:36 +02:00
|
|
|
print("Commune non trouvée avec le code", code_commune, "et le nom", bv_dict['nomCommune'])
|
2024-06-13 13:40:47 +02:00
|
|
|
continue
|
|
|
|
|
2024-06-08 17:10:19 +02:00
|
|
|
if not session.execute(select(Circonscription).filter_by(id=code_circo)).scalar_one_or_none():
|
2024-06-13 11:50:18 +02:00
|
|
|
session.add(Circonscription(id=code_circo, departement_code=dpt_code, numero=numero_circo))
|
2024-06-08 17:10:19 +02:00
|
|
|
|
|
|
|
if bv := session.execute(select(BureauVote).filter_by(id=bv_id)).scalar_one_or_none():
|
|
|
|
bv.commune_code = code_commune
|
|
|
|
bv.code_bureau = code_bv
|
|
|
|
bv.circo_code = code_circo
|
|
|
|
bv.libelle = bv_libelle
|
2024-06-14 23:58:36 +02:00
|
|
|
bv.geometry = feature['geometry']
|
2024-06-08 17:10:19 +02:00
|
|
|
else:
|
|
|
|
bv = BureauVote(id=bv_id, commune_code=code_commune, code_bureau=code_bv, circo_code=code_circo,
|
2024-06-14 23:58:36 +02:00
|
|
|
libelle=bv_libelle, adresse="", geometry=feature['geometry'])
|
2024-06-08 17:10:19 +02:00
|
|
|
session.add(bv)
|
|
|
|
|
|
|
|
session.commit()
|
|
|
|
|
|
|
|
|
2024-06-13 12:21:11 +02:00
|
|
|
def run(engine: Engine, verbose: bool = False) -> None:
|
|
|
|
importer_regions(engine, verbose)
|
|
|
|
importer_departements(engine, verbose)
|
2024-06-15 00:11:31 +02:00
|
|
|
importer_circonscriptions(engine, verbose)
|
2024-06-13 12:21:11 +02:00
|
|
|
importer_communes(engine, verbose)
|
|
|
|
importer_bureaux_vote(engine, verbose)
|