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.
- quickinteg/__about__.py +34 -0
- quickinteg/__init__.py +0 -0
- quickinteg/cfg_reader.py +104 -0
- quickinteg/cli.py +144 -0
- quickinteg/excel_shortcut.py +163 -0
- quickinteg/external/__init__.py +0 -0
- quickinteg/mcd_check.py +368 -0
- quickinteg/processing_logging.py +107 -0
- quickinteg/rop_grace.py +585 -0
- quickinteg/spatialiteio.py +646 -0
- quickinteg-2.5.0.dist-info/METADATA +75 -0
- quickinteg-2.5.0.dist-info/RECORD +16 -0
- quickinteg-2.5.0.dist-info/WHEEL +5 -0
- quickinteg-2.5.0.dist-info/entry_points.txt +6 -0
- quickinteg-2.5.0.dist-info/licenses/LICENSE +674 -0
- quickinteg-2.5.0.dist-info/top_level.txt +1 -0
quickinteg/__about__.py
ADDED
|
@@ -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
|
quickinteg/cfg_reader.py
ADDED
|
@@ -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
|