quickinteg 2.5.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,34 @@
1
+ #! python3 # noqa: E265
2
+
3
+ """
4
+ Metadata bout the package to easily retrieve informations about it.
5
+ See: https://packaging.python.org/guides/single-sourcing-package-version/
6
+ """
7
+
8
+ from datetime import date
9
+
10
+ __all__ = [
11
+ "__author__",
12
+ "__copyright__",
13
+ "__email__",
14
+ "__license__",
15
+ "__summary__",
16
+ "__title__",
17
+ "__uri__",
18
+ "__version__",
19
+ ]
20
+
21
+ __author__ = "Valérian LEBERT"
22
+ __copyright__ = f"2019 - {date.today().year}, {__author__}"
23
+ __email__ = ""
24
+ __executable_name__ = ""
25
+ __license__ = "GPL"
26
+ __summary__ = "Scripts QGIS Processing pour l'intégration rapide des données."
27
+ __title__ = "QuickInteg"
28
+ __title_clean__ = "".join(e for e in __title__ if e.isalnum())
29
+ __uri__ = "https://gitlab.com/vlebert/quickinteg/"
30
+
31
+ __version__ = "2.5.0"
32
+ __version_info__ = tuple(
33
+ [int(num) if num.isdigit() else num for num in __version__.replace("-", ".", 1).split(".")]
34
+ )
quickinteg/__init__.py ADDED
File without changes
@@ -0,0 +1,104 @@
1
+ #! python3 # noqa: E265
2
+
3
+ ################################################################################
4
+ # This file is part of quickinteg.
5
+
6
+ # quickinteg is free software: you can redistribute it and/or modify
7
+ # it under the terms of the GNU General Public License as published by
8
+ # the Free Software Foundation, either version 3 of the License, or
9
+ # (at your option) any later version.
10
+ #
11
+ # quickinteg is distributed in the hope that it will be useful,
12
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ # GNU General Public License for more details.
15
+ #
16
+ # You should have received a copy of the GNU General Public License
17
+ # along with quickinteg. If not, see <https://www.gnu.org/licenses/>.
18
+ ################################################################################
19
+
20
+ # ############################################################################
21
+ # ########## Imports ###############
22
+ # ##################################
23
+ # standard library
24
+ import ast
25
+ import configparser
26
+ import logging
27
+ import os
28
+ from pathlib import Path
29
+
30
+ # package
31
+ from . import mcd_check, processing_logging, spatialiteio
32
+
33
+ # ############################################################################
34
+ # ########## Globals ###############
35
+ # ##################################
36
+
37
+ module_logger = logging.getLogger(__name__)
38
+ module_logger.setLevel(logging.DEBUG)
39
+
40
+
41
+ # ############################################################################
42
+ # ########## Functions #############
43
+ # ##################################
44
+
45
+
46
+ def log(message: str, logLevel="info"):
47
+ processing_logging.log(str(message), module_logger, logLevel)
48
+
49
+
50
+ def parse_config_file(config_file_path: str) -> dict:
51
+ raw_config = configparser.ConfigParser()
52
+ raw_config.read(config_file_path)
53
+
54
+ config = dict()
55
+ l_params = ["table_def", "mcd_check", "sql", "export_table"]
56
+ log("Lecture du fichier de configuration %s" % (config_file_path))
57
+ for param in l_params:
58
+ try:
59
+ config[param] = ast.literal_eval(raw_config["template"][param])
60
+ log("%s: %s" % (param, config[param]))
61
+ except KeyError:
62
+ log("Pas de valeur %s dans la config" % (param))
63
+ except ValueError: # si pas de syntaxe python (ex, guillements pour string)
64
+ config[param] = raw_config["template"][param]
65
+ except SyntaxError: # si pas de syntaxe python (ex, guillements pour string)
66
+ config[param] = raw_config["template"][param]
67
+
68
+ log("Configuration : \n%s" % (config))
69
+ return config
70
+
71
+
72
+ def create_template_from_cfg(config_file_path):
73
+ config = parse_config_file(config_file_path)
74
+ os.chdir(Path(config_file_path).parent)
75
+
76
+ sql_tables_def_folder = config["table_def"]
77
+
78
+ base_spl_filename = Path(sql_tables_def_folder).name
79
+ base_spl_path = Path(base_spl_filename + ".sqlite")
80
+ # On crée une base sqlite3 avec extension spatialite
81
+ if base_spl_path.exists():
82
+ raise ValueError("Le fichier %s existe déjà" % (base_spl_path))
83
+ else:
84
+ spatialiteio.create_spatialite_db(base_spl_path)
85
+
86
+ # On exécute les différents scripts SQL sur la base spatialite
87
+
88
+ # MCD CHECK
89
+ spatialiteio.execute_file_to_spl(sql_tables_def_folder, base_spl_path)
90
+
91
+ # Configuration de contrôle
92
+ if "mcd_check" in set(config.keys()):
93
+ catalog_file = str(Path(config["mcd_check"]["catalogue"]))
94
+ config_file = str(Path(config["mcd_check"]["config"]))
95
+ sql_code = mcd_check.translate_config_to_sql(catalog_file, config_file)
96
+ spatialiteio.execute_query_to_spl(sql_code, base_spl_path)
97
+
98
+ # SQL
99
+ if "sql" in set(config.keys()):
100
+ for sql in config["sql"]:
101
+ spatialiteio.execute_file_to_spl(str(Path(sql)), base_spl_path)
102
+
103
+ if "export_table" in set(config.keys()):
104
+ spatialiteio.check_preset_tables(base_spl_path, config["export_table"])
quickinteg/cli.py ADDED
@@ -0,0 +1,144 @@
1
+ #! python3 # noqa: E265
2
+
3
+ ################################################################################
4
+ # This file is part of quickinteg.
5
+
6
+ # quickinteg is free software: you can redistribute it and/or modify
7
+ # it under the terms of the GNU General Public License as published by
8
+ # the Free Software Foundation, either version 3 of the License, or
9
+ # (at your option) any later version.
10
+ #
11
+ # quickinteg is distributed in the hope that it will be useful,
12
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ # GNU General Public License for more details.
15
+ #
16
+ # You should have received a copy of the GNU General Public License
17
+ # along with quickinteg. If not, see <https://www.gnu.org/licenses/>.
18
+ ################################################################################
19
+
20
+
21
+ import argparse
22
+ import logging
23
+ from pathlib import Path
24
+
25
+ from . import cfg_reader, processing_logging, rop_grace, spatialiteio
26
+
27
+
28
+ def quickinteg_create():
29
+ """Permet de créer un alias CLI pour appeler cfg_reader.create_template_from_cfg.
30
+ Alias : qi-create
31
+ """
32
+ parser = argparse.ArgumentParser()
33
+ parser.add_argument("config_file", help="Chemin vers le fichier de configuration de template")
34
+ args = parser.parse_args()
35
+ processing_logging.add_console_handler(logging.getLogger(""))
36
+ cfg_reader.create_template_from_cfg(args.config_file)
37
+
38
+
39
+ def quickinteg_delete():
40
+ """Alias CLI pour faire un delete à partir du import_prefix"""
41
+ parser = argparse.ArgumentParser()
42
+ parser.add_argument("db", help="Base spatialite dans laquelle supprimer les lignes")
43
+ parser.add_argument("import_prefix", help="Valeur de l'import prefix")
44
+ args = parser.parse_args()
45
+ processing_logging.add_console_handler(logging.getLogger(""))
46
+ spatialiteio.delete_rows(args.db, args.import_prefix)
47
+
48
+
49
+ # TODO : add log to text
50
+ def quickinteg_import():
51
+ """Permet de créer un alias CLI pour appeler spatialiteio.import_folder_to_spl et
52
+ spatialiteio.export_preset_tables.
53
+ Alias : qi-import
54
+ """
55
+ parser = argparse.ArgumentParser()
56
+ parser.add_argument("source", help="Chemin vers le repertoir à intégrer")
57
+ parser.add_argument("-c", "--no-csv", help="Exclure les fichiers CSV", action="store_true")
58
+ parser.add_argument(
59
+ "-d",
60
+ "--destination",
61
+ help="Chemin vers une base de donnée existante (mode APPEND).",
62
+ default=None,
63
+ )
64
+ parser.add_argument(
65
+ "-p",
66
+ "--prefix",
67
+ help="Préfixe d'importation ajouté sur chaque table.",
68
+ default="",
69
+ )
70
+ parser.add_argument("-e", "--export", help="Exporter les vues de contrôle", action="store_true")
71
+ parser.add_argument(
72
+ "-r",
73
+ "--recursive",
74
+ help="Mode récursif (parcours les sous-dossiers).",
75
+ action="store_true",
76
+ )
77
+ args = parser.parse_args()
78
+ processing_logging.add_console_handler(logging.getLogger(""))
79
+
80
+ if args.destination:
81
+ log_file = Path(args.destination).parent / "log_integ.txt"
82
+ else:
83
+ log_file = Path(args.source) / "log_integ.txt"
84
+ processing_logging.add_file_handler(logging.getLogger(""), log_file, logging.DEBUG)
85
+
86
+ spatialiteio.import_folder_to_spl(
87
+ args.source,
88
+ ogr_target=args.destination,
89
+ prefix=args.prefix,
90
+ include_csv=(not args.no_csv),
91
+ ignore_grace_list=True,
92
+ recursive=args.recursive,
93
+ )
94
+ if args.export:
95
+ spatialiteio.export_preset_tables(args.destination)
96
+
97
+
98
+ def quickinteg_rop():
99
+ """Permet de créer un alias CLI générer les routes optiques.
100
+ Alias : qi-rop
101
+ """
102
+ parser = argparse.ArgumentParser()
103
+ parser.add_argument("db_file", help="Base de donnée Quickinteg")
104
+ parser.add_argument(
105
+ "-v", "--version", help="Version GRACE THD (2 ou 3, 3 par défaut)", default=3
106
+ )
107
+ parser.add_argument(
108
+ "-m",
109
+ "--mode",
110
+ help="Mode to use (table or view, table by default)",
111
+ default="table",
112
+ )
113
+ args = parser.parse_args()
114
+ processing_logging.add_console_handler(logging.getLogger(""))
115
+ if int(args.version) == 3:
116
+ rop_grace.param_st_id = "lc_codeext"
117
+ rop_grace.param_cb_id = "cb_codeext"
118
+ rop_grace.param_bp_id = "bp_codeext"
119
+ rop_grace.param_ti_id = "ti_codeext"
120
+ rop_grace.param_lg_cable = "cb_lgreel"
121
+ rop_grace.grace_version = 3
122
+ rop_grace.mode = args.mode
123
+ rop_grace.generate_ropt_full(args.db_file, n_iteration=15)
124
+ elif int(args.version) == 2:
125
+ rop_grace.param_st_id = "st_codeext"
126
+ rop_grace.param_cb_id = "cb_codeext"
127
+ rop_grace.param_bp_id = "bp_codeext"
128
+ rop_grace.param_ti_id = "ti_codeext"
129
+ rop_grace.param_lg_cable = "cb_lgreel"
130
+ rop_grace.grace_version = 2
131
+ rop_grace.mode = args.mode
132
+ rop_grace.generate_ropt_full(args.db_file, n_iteration=15)
133
+ else:
134
+ raise ValueError("Valeur incorrecte pour -v / --version")
135
+
136
+
137
+ def quickinteg_formatrop():
138
+ """Permet de créer un alias CLI formater les routes optique au format excel.
139
+ Alias : qi-formatrop
140
+ """
141
+ parser = argparse.ArgumentParser()
142
+ parser.add_argument("rop_file", help="Fichier de ROP")
143
+ args = parser.parse_args()
144
+ rop_grace.format_ropt(args.rop_file)
@@ -0,0 +1,163 @@
1
+ #! python3 # noqa: E265
2
+
3
+ ################################################################################
4
+ # This file is part of quickinteg.
5
+
6
+ # quickinteg is free software: you can redistribute it and/or modify
7
+ # it under the terms of the GNU General Public License as published by
8
+ # the Free Software Foundation, either version 3 of the License, or
9
+ # (at your option) any later version.
10
+ #
11
+ # quickinteg is distributed in the hope that it will be useful,
12
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ # GNU General Public License for more details.
15
+ #
16
+ # You should have received a copy of the GNU General Public License
17
+ # along with quickinteg. If not, see <https://www.gnu.org/licenses/>.
18
+ ################################################################################
19
+
20
+ # ############################################################################
21
+ # ########## Libraries #############
22
+ # ##################################
23
+
24
+ # standard library
25
+ import logging
26
+
27
+ # 3rd party - try embedded first (for QGIS), fallback to normal import (for CLI)
28
+ try:
29
+ from .external import openpyxl
30
+ except ImportError:
31
+ import openpyxl
32
+
33
+ # package
34
+ from . import processing_logging
35
+
36
+ # ############################################################################
37
+ # ########## Globals ###############
38
+ # ##################################
39
+
40
+ module_logger = logging.getLogger(__name__)
41
+ module_logger.setLevel(logging.DEBUG)
42
+
43
+
44
+ # ############################################################################
45
+ # ########## Functions #############
46
+ # ##################################
47
+
48
+
49
+ def log(message: str, logLevel: str = "info"):
50
+ """Map log message on different logging pipes. Mainly: QGIS Processing log system.
51
+
52
+ Args:
53
+ message (str): [description]
54
+ logLevel (str, optional): [description]. Defaults to "info".
55
+ """
56
+ processing_logging.log(message, module_logger, logLevel)
57
+
58
+
59
+ def read_sheet_to_dict(
60
+ excel_file_path, list_necessary_columns, primary_key=None, excel_sheet_name=None
61
+ ):
62
+ """
63
+ Lecture d'un fichier excel vert un dict de dict.
64
+ Chaque ligne est un dict avec comme clés les en-têtes de colones.
65
+ Le fichier est un dict de lignes avec comme clé la valeur \
66
+ dans la colonne "primary_key".
67
+ Si primary_key == None, on utilise le numéro de ligne
68
+ ex :
69
+
70
+ le tableau
71
+
72
+ Primary_key | colonne1 | colonne2
73
+ key1 | value1 | value2
74
+ key2 | value3 | value4
75
+
76
+ donnera en sortie un dict
77
+ {
78
+ key1 {
79
+ Primary_key : key1,
80
+ colonne1 : value1,
81
+ colonne2 : value2
82
+ },
83
+ key2 {
84
+ Primary_key : key2,
85
+ colonne1 : value3,
86
+ colonne2 : value4
87
+ }
88
+ }
89
+ """
90
+ wb = openpyxl.load_workbook(excel_file_path, data_only=True)
91
+ sheet = wb[excel_sheet_name] if excel_sheet_name else wb.active
92
+
93
+ rows = sheet.iter_rows(values_only=True)
94
+ headers = next(rows) # Get the first row with column names
95
+ header_set = set(headers)
96
+
97
+ necessary_columns_set = set(list_necessary_columns)
98
+ if not necessary_columns_set.issubset(header_set):
99
+ missing_columns = necessary_columns_set - header_set
100
+ raise ValueError(
101
+ f"The necessary columns {missing_columns} were not found in the Excel sheet"
102
+ )
103
+
104
+ header_index = {header: headers.index(header) for header in list_necessary_columns}
105
+
106
+ dict_output = {}
107
+ for i, row in enumerate(rows, start=1): # start=1 because Excel is 1-indexed
108
+ row_data = {header: row[header_index[header]] for header in list_necessary_columns}
109
+ key = row_data.get(primary_key) if primary_key else i
110
+ dict_output[key] = row_data
111
+
112
+ return dict_output
113
+
114
+
115
+ def read_all_sheet_to_dict(excel_file_path, list_necessary_columns, primary_key):
116
+ dict_output = dict()
117
+ wb = openpyxl.load_workbook(excel_file_path, data_only=True)
118
+ for sheet_name in wb.sheetnames:
119
+ dict_output.update(
120
+ read_sheet_to_dict(
121
+ excel_file_path,
122
+ list_necessary_columns,
123
+ primary_key,
124
+ excel_sheet_name=sheet_name,
125
+ )
126
+ )
127
+ return dict_output
128
+
129
+
130
+ def read_sheet_to_tab(excel_file_path, excel_sheet_name=None):
131
+ """Lecture d'un fichier excel et retour un dict de deux listes :
132
+ une liste header
133
+ une double liste data"""
134
+ # Ouverture du xlsx
135
+ wb = openpyxl.load_workbook(excel_file_path, data_only=True)
136
+
137
+ # Si pas de sheet_name passé en paramètre, on ouvre le premier onglet
138
+ if excel_sheet_name is None:
139
+ excel_sheet = wb[wb.sheetnames[0]]
140
+ # Sinon on ouvre l'onglet passé en paramètre
141
+ else:
142
+ excel_sheet = wb[excel_sheet_name]
143
+
144
+ # Stockage des valeurs dans un tableau
145
+ header = []
146
+ data = []
147
+ for i, row in enumerate(excel_sheet.iter_rows(values_only=True)):
148
+ if i == 0:
149
+ header.extend(row)
150
+ else:
151
+ data.append(list(row))
152
+ return {"header": header, "data": data}
153
+
154
+
155
+ # ############################################################################
156
+ # ########## Main ##################
157
+ # ##################################
158
+
159
+ # for compatibility after simplifying name
160
+ read_excel_sheet_to_dict = read_sheet_to_dict
161
+
162
+ # for compatibility after simplifying name
163
+ read_excel_sheet_to_tab = read_sheet_to_tab
File without changes