Commit a72883f4 authored by Lionel's avatar Lionel
Browse files

Ajout id_departement et id_region pour epci, Ajout dockerfile et gitlab-ci...

Ajout id_departement et id_region pour epci, Ajout dockerfile et gitlab-ci pour lancer les tests avec gitlab
parent e24f6f77
image: "python:3.8"
before_script:
- python --version
- pip install -r requirements.txt
stages:
- tests
tests-unitaire:
stage: tests
script:
- python -m unittest
FROM python:3.8
RUN mkdir -p /crater-data
WORKDIR /crater-data
#RUN apt-get update && apt-get install -y libspatialindex-dev python-rtree
ADD . .
RUN pip install --no-cache-dir -r requirements.txt
ENTRYPOINT [ "python", "-m", "unittest"]
\ No newline at end of file
......@@ -237,6 +237,22 @@ def generer_fichiers_resultats_crater():
)
def lancer_generation_territoires():
calculer_territoires(
CHEMIN_SOURCE_COMMUNES_ET_ARRONDISSEMENTS,
CHEMIN_SOURCE_MOUVEMENTS_COMMUNES,
CHEMIN_SOURCE_EPCIS,
CHEMIN_SOURCE_DEPARTEMENTS,
CHEMIN_SOURCE_REGIONS,
CHEMIN_SOURCE_CODES_POSTAUX,
CHEMIN_SOURCE_POPULATION_TOTALE,
CHEMIN_SOURCE_POPULATION_TOTALE_HISTORIQUE,
CHEMIN_PRECALCUL_SAU,
CHEMIN_CRATER_DATA_SOURCES / DOSSIER_PARCEL / 'correspondance_territoires_parcel_crater.csv',
CHEMIN_OUTPUT_DATA / DOSSIER_TERRITOIRES
)
def lancer_calcul_politique_fonciere():
referentiel_territoires = charger_referentiel_territoires(
CHEMIN_OUTPUT_DATA / DOSSIER_TERRITOIRES
......@@ -316,6 +332,7 @@ if __name__ == '__main__':
+ "\tparcel-besoins-assiette-25p\t\tgénérer le fichier des besoins en SAU à partir de l'api PARCEL, pour une assiette avec -25 pourcent de produit de l'élevage\n"
+ "\tparcel-besoins-assiette-50p\t\tgénérer le fichier des besoins en SAU à partir de l'api PARCEL, pour une assiette avec -50 poucent de produit de l'élevage\n"
+ "\tcrater\t\t\t\t\tgénérer l'ensemble des fichiers résultat crater-data, à partir des fichiers sources et des fichiers générés lors des autres étapes\n"
+ "\tterritoires\t\t\tgénérer les fichiers résultat crater-data, pour les territoires\n"
+ "\tpolitique-fonciere\t\t\tgénérer les fichiers résultat crater-data, pour l'axe politique foncière\n"
+ "\tpratiques-agricoles\t\t\tgénérer les fichiers résultat crater-data, pour l'axe pratiques agricoles\n"
+ "\tproduction-besoins\t\t\tgénérer les fichiers résultat crater-data, pour l'axe production-besoins\n"
......@@ -326,6 +343,7 @@ if __name__ == '__main__':
'parcel-besoins-assiette-25p',
'parcel-besoins-assiette-50p',
'crater',
'territoires',
'pratiques-agricoles',
'politique-fonciere',
'production-besoins'
......@@ -362,6 +380,9 @@ if __name__ == '__main__':
elif (args.ETAPE == 'crater'):
print("Génération des fichiers résultats CRATER")
generer_fichiers_resultats_crater()
elif (args.ETAPE == 'territoires'):
print("Génération des fichiers résultats CRATER pour les territoires")
lancer_generation_territoires()
elif (args.ETAPE == 'production-besoins'):
print("Génération des fichiers résultats CRATER pour l'axe production/besoins")
lancer_calcul_production_besoins()
......
......@@ -40,7 +40,7 @@ def _calculer_besoins_par_culture_et_par_assiette(fichier_besoins_parcel,
fichier_produits_hors_elevage_vers_cultures_besoins_humains,
nom_colonne_besoins, territoires):
df_besoins = _initialiser_df_avec_liste_territoires(territoires)
df_besoins = _ajouter_colonne_region_appartenance_principale(df_besoins, territoires)
df_besoins = _ajouter_colonne_region_appartenance_principale(df_besoins)
df_besoins = _ajouter_colonnes_donnees_besoins_parcel(df_besoins, fichier_besoins_parcel)
df_besoins = _ajouter_colonnes_cultures_besoins_humains(df_besoins,
fichier_produits_hors_elevage_vers_cultures_besoins_humains)
......@@ -72,39 +72,42 @@ def _initialiser_df_avec_liste_territoires(territoires):
['id_territoire', 'categorie_territoire', 'nom_territoire', 'id_region']]
def _ajouter_colonne_region_appartenance_principale(donnees_besoins, territoires):
donnees_besoins = _ajouter_colonne_region_appartenance_pour_epcis(donnees_besoins, territoires)
def _ajouter_colonne_region_appartenance_principale(donnees_besoins):
# Plus utile car déjà calculé au niveau du référentiel territoire
# donnees_besoins = _ajouter_colonne_region_appartenance_pour_epcis(donnees_besoins, territoires)
# pour le niveau region et pays, on donne la valeur "id_territoire" (soit l'id_region, soit P-FR pour le pays)
donnees_besoins['id_region'].fillna(donnees_besoins['id_territoire'], inplace=True)
donnees_besoins = donnees_besoins.iloc[:, :-3]
return donnees_besoins
def _ajouter_colonne_region_appartenance_pour_epcis(donnees_besoins, territoires):
nb_communes_par_epci_et_region = (territoires['communes']
.groupby(['id_epci', 'id_region']).size()
.reset_index()
.rename(
columns={0: "nb_communes_par_epci_et_region", "id_region": "id_region_pour_epci"})
)
index_lignes_avec_max_nb_communes = (nb_communes_par_epci_et_region
.reset_index()
.groupby(['id_epci'])
['nb_communes_par_epci_et_region']
.idxmax())
region_appartenance_epci = nb_communes_par_epci_et_region.loc[index_lignes_avec_max_nb_communes]
donnees_besoins = donnees_besoins.merge(region_appartenance_epci,
how='left',
left_on='id_territoire',
right_on='id_epci')
donnees_besoins.loc[(donnees_besoins['categorie_territoire'] == 'EPCI'), ['id_region']] = \
donnees_besoins[donnees_besoins['categorie_territoire'] == 'EPCI']['id_region_pour_epci']
return donnees_besoins
# Plus utilisé car calculé au niveau du calcul référentiel territoire => a supprimer
# def _ajouter_colonne_region_appartenance_pour_epcis(donnees_besoins, territoires):
# nb_communes_par_epci_et_region = (territoires['communes']
# .groupby(['id_epci', 'id_region']).size()
# .reset_index()
# .rename(
# columns={0: "nb_communes_par_epci_et_region", "id_region": "id_region_pour_epci"})
# )
# index_lignes_avec_max_nb_communes = (nb_communes_par_epci_et_region
# .reset_index()
# .groupby(['id_epci'])
# ['nb_communes_par_epci_et_region']
# .idxmax())
#
# region_appartenance_epci = nb_communes_par_epci_et_region.loc[index_lignes_avec_max_nb_communes]
#
# donnees_besoins = donnees_besoins.merge(region_appartenance_epci,
# how='left',
# left_on='id_territoire',
# right_on='id_epci')
#
# donnees_besoins.loc[(donnees_besoins['categorie_territoire'] == 'EPCI'), ['id_region']] = \
# donnees_besoins[donnees_besoins['categorie_territoire'] == 'EPCI']['id_region_pour_epci']
#
# donnees_besoins = donnees_besoins.iloc[:, :-3]
#
# return donnees_besoins
def _ajouter_colonnes_donnees_besoins_parcel(donnees_besoins, fichier_besoins_parcel):
......
......@@ -32,7 +32,10 @@ def _generer_referentiel_territoires(sources: DictTerritoires) -> DictTerritoire
pays
)
_ajouter_id_departement_et_region_aux_epcis(territoires)
_ajouter_id_pays_aux_territoires(territoires)
_ajouter_codes_postaux(
territoires,
sources['arrondissements'],
......@@ -120,6 +123,25 @@ def _exporter_referentiel_territoires(
chemin_dossier_output / "donnees.csv"
)
territoires_assembles = (outils_territoires
.assembler_dict_territoires_en_df_territoires(territoires)
.loc[:,
['id_territoire', 'nom_territoire', 'categorie_territoire', 'codes_postaux', 'id_epci', 'id_departement', 'id_region', 'id_pays']
]
.rename(columns={'codes_postaux': 'codes_postaux_commune'})
)
# temporaire : pour fixer le bug d'affichage pycharm => affichage KO avec float avec NA de pandas...alors que ca marche avec NaN de numpy
# territoires_assembles.annee_dernier_mouvement = territoires_assembles.annee_dernier_mouvement.fillna(0)
territoires_assembles.to_csv(
chemin_dossier_output / "territoires.csv",
sep=";",
encoding="utf-8",
index=False,
float_format='%.2f'
)
def _creer_base_de_donnees_pays() -> DataFrame:
pays = pd.DataFrame(
......@@ -134,6 +156,31 @@ def _ajouter_id_pays_aux_territoires(territoires: DictTerritoires) -> None:
territoires[t]['id_pays'] = outils_territoires.ID_FRANCE
def _ajouter_id_departement_et_region_aux_epcis(territoires: DictTerritoires) -> None:
nb_communes_par_epci_et_departement = (territoires['communes']
.groupby(['id_epci', 'id_departement']).size()
.reset_index()
.rename(
columns={0: "nb_communes_par_epci_et_departement", "id_departement": "id_departement_pour_epci"})
)
index_lignes_avec_max_nb_communes = (nb_communes_par_epci_et_departement
.reset_index()
.groupby(['id_epci'])
['nb_communes_par_epci_et_departement']
.idxmax())
departement_appartenance_epci = (nb_communes_par_epci_et_departement
.loc[index_lignes_avec_max_nb_communes]
.rename(columns={'id_departement_pour_epci' : 'id_departement'} )
)
departement_appartenance_epci = (departement_appartenance_epci
.merge(territoires['departements'], how='left', on='id_departement')
.loc[:, ['id_epci', 'id_departement', 'id_region']])
territoires['epcis'] = territoires['epcis'].merge(departement_appartenance_epci, how='left',
on=['id_epci'])
def _ajouter_codes_postaux(territoires: DictTerritoires, arrondissements: DataFrame, codes_postaux: DataFrame) -> None:
# les codes postaux sont donnés par arrondissements ou communes quand celle-ci n'a pas d'arrondissements
# on doit donc remplacer l'id arrondissement par l'id de sa commune le cas échéant
......
......@@ -565,61 +565,13 @@ def exporter_fichier_unique(territoires: outils.DictTerritoires, fichier_output:
def assembler_dict_territoires_en_df_territoires(territoires):
territoires_a_assembler = copy.deepcopy(territoires)
territoires_a_assembler['communes'].rename(
{'id_commune': 'id_territoire', 'nom_commune': 'nom_territoire'},
axis=1,
inplace=True,
errors='raise'
)
territoires_a_assembler['epcis'].rename(
{'id_epci': 'id_territoire', 'nom_epci': 'nom_territoire'},
axis=1,
inplace=True,
errors='raise'
)
territoires_a_assembler['departements'].rename(
{'id_departement': 'id_territoire', 'nom_departement': 'nom_territoire'},
axis=1,
inplace=True,
errors='raise'
)
territoires_a_assembler['regions'].rename(
{'id_region': 'id_territoire', 'nom_region': 'nom_territoire'},
axis=1,
inplace=True,
errors='raise'
)
territoires_a_assembler['pays'].rename(
{'id_pays': 'id_territoire', 'nom_pays': 'nom_territoire'},
axis=1,
inplace=True,
errors='raise'
)
territoires_a_assembler['communes'].insert(
loc=2,
column='categorie_territoire',
value="COMMUNE"
)
territoires_a_assembler['epcis'].insert(
loc=2,
column='categorie_territoire',
value="EPCI"
)
territoires_a_assembler['departements'].insert(
loc=2,
column='categorie_territoire',
value="DEPARTEMENT"
)
territoires_a_assembler['regions'].insert(
loc=2,
column='categorie_territoire',
value="REGION"
)
territoires_a_assembler['pays'].insert(
loc=2,
column='categorie_territoire',
value="PAYS"
)
_normaliser_df_dict_territoire(territoires_a_assembler['communes'], 'id_commune', 'nom_commune', 'COMMUNE')
_normaliser_df_dict_territoire(territoires_a_assembler['epcis'], 'id_epci', 'nom_epci', "EPCI")
_normaliser_df_dict_territoire(territoires_a_assembler['departements'], 'id_departement', 'nom_departement',
"DEPARTEMENT")
_normaliser_df_dict_territoire(territoires_a_assembler['regions'], 'id_region', 'nom_region', "REGION")
_normaliser_df_dict_territoire(territoires_a_assembler['pays'], 'id_pays', 'nom_pays', "PAYS")
assemblage_territoires = pd.concat(
[territoires_a_assembler['pays'],
territoires_a_assembler['regions'],
......@@ -631,6 +583,20 @@ def assembler_dict_territoires_en_df_territoires(territoires):
return assemblage_territoires
def _normaliser_df_dict_territoire(df_territoires, colonne_id, colonne_nom, categorie):
df_territoires.rename(
{colonne_id: 'id_territoire', colonne_nom: 'nom_territoire'},
axis=1,
inplace=True,
errors='raise'
)
df_territoires.insert(
loc=2,
column='categorie_territoire',
value=categorie
)
def exporter_fichiers_multiples(
territoires: DictTerritoires,
dossier_output: Path
......
import os
import sys
# add current dir to python path to allow python to find the packages
# in import when tests are executed from the command line
sys.path.insert(0, os.getcwd())
# Change the working directory to the test directory
# Usefull when tests are ran from the project root folder with 'python -m unittest'
# Allow to find the test data folder which is defined relatively to the test folder (done this way in order to run tests in pycharm without additional config)
if not os.getcwd().endswith('tests'):
os.chdir("./tests")
\ No newline at end of file
code_insee;nom;categorie;id_pays
E-C;CA Concarneau Cornouaille Agglomération;COMMUNAUTE_AGGLOMERATION;P-FR
E-T;Toulouse Métropole;METROPOLE;P-FR
E-L;CU Lorient;COMMUNAUTE_URBAINE;P-FR
E-PA;Paris;METROPOLE;P-FR
code_insee;nom;categorie;id_departement;id_region;id_pays
E-C;CA Concarneau Cornouaille Agglomération;COMMUNAUTE_AGGLOMERATION;D-29;R-53;P-FR
E-T;Toulouse Métropole;METROPOLE;D-31;R-76;P-FR
E-L;CU Lorient;COMMUNAUTE_URBAINE;D-56;R-53;P-FR
E-PA;Paris;METROPOLE;D-75;R-11;P-FR
code_insee;nom;code_insee_region
D-32;Gers;R-76
D-40;Landes;R-75
D-75;Paris;R-11
code_insee;nom;code_insee_region;id_pays
D-32;Gers;R-76;P-FR
D-40;Landes;R-75;P-FR
D-75;Paris;R-11;P-FR
id_territoire;nom_territoire;categorie_territoire;sau_ha;population_totale_2017;population_totale_2010;population_totale_1990
P-FR;France;PAYS;3415.67;243346;26494;8421
R-11;Île-de-France;REGION;;237015;20000;2000
R-75;Nouvelle-Aquitaine;REGION;3265.67;6285;6445;6370
R-76;Occitanie;REGION;150.00;46;49;51
D-32;Gers;DEPARTEMENT;150.00;46;49;51
D-40;Landes;DEPARTEMENT;3265.67;6285;6445;6370
D-75;Paris;DEPARTEMENT;;237015;20000;2000
E-200030435;CC d'Aire-sur-l'Adour;EPCI;3415.67;6331;6494;6421
E-200054781;Métropole du Grand Paris;EPCI;;237015;20000;2000
C-32145;Gée-Rivière;COMMUNE;150.00;46;49;51
C-40001;Aire-sur-l'Adour;COMMUNE;2894.00;6129;6279;6205
C-40146;Latrille;COMMUNE;371.67;156;166;165
C-75056;Paris;COMMUNE;;237015;20000;2000
id_territoire;nom_territoire;categorie_territoire;sau_ha;population_totale_2017;population_totale_2010;population_totale_1990;id_territoire_parcel
P-FR;France;PAYS;363.60;243346;26494;8421;1
R-11;Île-de-France;REGION;;237015;20000;2000;2
R-75;Nouvelle-Aquitaine;REGION;282.80;6285;6445;6370;
R-76;Occitanie;REGION;80.80;46;49;51;
D-32;Gers;DEPARTEMENT;80.80;46;49;51;
D-40;Landes;DEPARTEMENT;282.80;6285;6445;6370;
D-75;Paris;DEPARTEMENT;;237015;20000;2000;
E-200030435;CC d'Aire-sur-l'Adour;EPCI;363.60;6331;6494;6421;
E-200054781;Métropole du Grand Paris;EPCI;;237015;20000;2000;
C-32145;Gée-Rivière;COMMUNE;80.80;46;49;51;
C-40001;Aire-sur-l'Adour;COMMUNE;131.30;6129;6279;6205;
C-40146;Latrille;COMMUNE;151.50;156;166;165;
C-75056;Paris;COMMUNE;;237015;20000;2000;
code_insee;nom;categorie
E-200030435;CC d'Aire-sur-l'Adour;COMMUNAUTE_COMMUNES
E-200054781;Métropole du Grand Paris;METROPOLE
code_insee;nom;categorie;id_departement;id_region;id_pays
E-200030435;CC d'Aire-sur-l'Adour;COMMUNAUTE_COMMUNES;D-40;R-75;P-FR
E-200054781;Métropole du Grand Paris;METROPOLE;D-75;R-11;P-FR
code_insee;nom
R-11;Île-de-France
R-75;Nouvelle-Aquitaine
R-76;Occitanie
code_insee;nom;id_pays
R-11;Île-de-France;P-FR
R-75;Nouvelle-Aquitaine;P-FR
R-76;Occitanie;P-FR
id_territoire;nom_territoire;categorie_territoire;codes_postaux_commune;id_epci;id_departement;id_region;id_pays
P-FR;France;PAYS;;;;;
R-11;Île-de-France;REGION;;;;;P-FR
R-75;Nouvelle-Aquitaine;REGION;;;;;P-FR
R-76;Occitanie;REGION;;;;;P-FR
D-32;Gers;DEPARTEMENT;;;;R-76;P-FR
D-40;Landes;DEPARTEMENT;;;;R-75;P-FR
D-75;Paris;DEPARTEMENT;;;;R-11;P-FR
E-200030435;CC d'Aire-sur-l'Adour;EPCI;;;D-40;R-75;P-FR
E-200054781;Métropole du Grand Paris;EPCI;;;D-75;R-11;P-FR
C-32145;Gée-Rivière;COMMUNE;32720;E-200030435;D-32;R-76;P-FR
C-40001;Aire-sur-l'Adour;COMMUNE;40800;E-200030435;D-40;R-75;P-FR
C-40146;Latrille;COMMUNE;40800;E-200030435;D-40;R-75;P-FR
C-75056;Paris;COMMUNE;75010|75011;E-200054781;D-75;R-11;P-FR
......@@ -28,6 +28,8 @@ class TestApiParcel(unittest.TestCase):
CHEMIN_OUTPUT_DATA / DOSSIER_PARCEL / 'reponse_api_parcel_id_territoires.csv'
)
@unittest.skip(
"Ce test dépend des données PARCEL - permet de voir si elles ont changé ou pas. Pas lancé de manière automatique")
def test_collecter_reponse_api_parcel_besoins_sau_par_produits(self):
collecteur_besoins_api_parcel.collecter_donnees_besoins_parcel(
ID_ASSIETTE_MOINS_50_POURCENT,
......
......@@ -5,7 +5,7 @@ from crater.reglages import DOSSIER_TERRITOIRES, DOSSIER_SAU, DOSSIER_PARCEL
from crater.territoires import calculateur
from tests.test_outils import assert_list_of_csv_files_are_equals, \
CHEMIN_INPUT_DATA, CHEMIN_OUTPUT_DATA, CHEMIN_EXPECTED_DATA, \
DOSSIER_CAS_NOMINAL, assert_dict_are_equals
DOSSIER_CAS_NOMINAL, assert_dict_are_equals, DOSSIER_CAS_TESTS_BESOINS
class TestTerritoires(unittest.TestCase):
......@@ -35,6 +35,33 @@ class TestTerritoires(unittest.TestCase):
dataframes_territoires_charges)
def test_generation_referentiel_territoires_csv_a_partir_sources(self):
calculateur.calculer_territoires(
CHEMIN_INPUT_DATA / DOSSIER_TERRITOIRES / DOSSIER_CAS_TESTS_BESOINS / 'communes_et_arrondissements.xlsx',
CHEMIN_INPUT_DATA / DOSSIER_TERRITOIRES / DOSSIER_CAS_TESTS_BESOINS / 'table_passage_communes.xlsx',
CHEMIN_INPUT_DATA / DOSSIER_TERRITOIRES / DOSSIER_CAS_TESTS_BESOINS / 'epcis.xlsx',
CHEMIN_INPUT_DATA / DOSSIER_TERRITOIRES / DOSSIER_CAS_TESTS_BESOINS / 'departements.csv',
CHEMIN_INPUT_DATA / DOSSIER_TERRITOIRES / DOSSIER_CAS_TESTS_BESOINS / 'regions.csv',
CHEMIN_INPUT_DATA / DOSSIER_TERRITOIRES / DOSSIER_CAS_TESTS_BESOINS / 'codes_postaux.csv',
CHEMIN_INPUT_DATA / DOSSIER_TERRITOIRES / DOSSIER_CAS_TESTS_BESOINS / 'population_totale_2017.csv',
CHEMIN_INPUT_DATA / DOSSIER_TERRITOIRES / DOSSIER_CAS_TESTS_BESOINS / 'population_totale_historique_2015.xlsx',
CHEMIN_INPUT_DATA / DOSSIER_SAU / DOSSIER_CAS_TESTS_BESOINS / 'sau-communes.csv',
CHEMIN_INPUT_DATA / DOSSIER_PARCEL / 'correspondance_territoires_parcel_crater.csv',
CHEMIN_OUTPUT_DATA / DOSSIER_TERRITOIRES
)
assert_list_of_csv_files_are_equals(
CHEMIN_EXPECTED_DATA / DOSSIER_TERRITOIRES / DOSSIER_CAS_TESTS_BESOINS,
CHEMIN_OUTPUT_DATA / DOSSIER_TERRITOIRES,
['communes.csv',
'epcis.csv',
'departements.csv',
'regions.csv',
'pays.csv',
'donnees.csv',
'territoires.csv']
)
def test_generation_referentiel_territoires_csv_a_partir_sources_a_supprimer(self):
calculateur.calculer_territoires(
CHEMIN_INPUT_DATA / DOSSIER_TERRITOIRES / DOSSIER_CAS_NOMINAL / 'communes_et_arrondissements.xlsx',
CHEMIN_INPUT_DATA / DOSSIER_TERRITOIRES / DOSSIER_CAS_NOMINAL / 'table_passage_communes.xlsx',
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment