From 2eb984a95f2cc605967668ef4d0e6e1bf24265f8 Mon Sep 17 00:00:00 2001 From: Colin Maudry Date: Fri, 10 Oct 2025 17:44:16 +0200 Subject: [PATCH 1/4] =?UTF-8?q?Ne=20plus=20afficher=20de=20nulls=20dans=20?= =?UTF-8?q?les=20tableaux=20de=20donn=C3=A9es=20(tableau,=20titulaire,=20a?= =?UTF-8?q?cheteur)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/acheteur.py | 3 ++- src/pages/tableau.py | 9 ++++++--- src/pages/titulaire.py | 3 ++- src/utils.py | 2 +- 4 files changed, 11 insertions(+), 6 deletions(-) diff --git a/src/pages/acheteur.py b/src/pages/acheteur.py index 3da7e7a..80a258f 100644 --- a/src/pages/acheteur.py +++ b/src/pages/acheteur.py @@ -175,7 +175,6 @@ def get_acheteur_marches_data(url, acheteur_year: str) -> list[dict]: acheteur_siret = url.split("/")[-1] lff = df.lazy() lff = lff.filter(pl.col("acheteur_id") == acheteur_siret) - lff = lff.fill_null("") lff = lff.select( "id", "uid", @@ -204,6 +203,8 @@ def get_acheteur_marches_data(url, acheteur_year: str) -> list[dict]: ) def get_last_marches_table(data) -> html.Div: dff = pl.DataFrame(data) + dff = dff.cast(pl.String) + dff = dff.fill_null("") dff = format_montant(dff) columns, tooltip = setup_table_columns( dff, diff --git a/src/pages/tableau.py b/src/pages/tableau.py index cdef299..23de881 100644 --- a/src/pages/tableau.py +++ b/src/pages/tableau.py @@ -182,9 +182,6 @@ def update_table(page_current, page_size, filter_query, sort_by, data_timestamp) if len(sort_by) > 0: lff = sort_table_data(lff, sort_by) - # Remplace les strings null par "", mais pas les numeric null - lff = lff.fill_null("") - # Matérialisation des filtres dff: pl.DataFrame = lff.collect() @@ -196,6 +193,12 @@ def update_table(page_current, page_size, filter_query, sort_by, data_timestamp) # end_row = (page_current + 1) * page_size dff = dff.slice(start_row, page_size) + # Tout devient string + dff = dff.cast(pl.String) + + # Remplace les strings null par "", mais pas les numeric null + dff = dff.fill_null("") + # Ajout des liens vers l'annuaire des entreprises dff = add_links(dff) diff --git a/src/pages/titulaire.py b/src/pages/titulaire.py index bd38feb..07f07eb 100644 --- a/src/pages/titulaire.py +++ b/src/pages/titulaire.py @@ -180,7 +180,6 @@ def get_titulaire_marches_data(url, titulaire_year: str) -> list[dict]: (pl.col("titulaire_id") == titulaire_siret) & (pl.col("titulaire_typeIdentifiant") == "SIRET") ) - lff = lff.fill_null("") lff = lff.select( "id", "uid", @@ -218,6 +217,8 @@ def get_last_marches_table(data) -> html.Div: ] dff = pl.DataFrame(data) + dff = dff.cast(pl.String) + dff = dff.fill_null("") dff = format_montant(dff) columns, tooltip = setup_table_columns( dff, hideable=False, exclude=["acheteur_id", "id"] diff --git a/src/utils.py b/src/utils.py index 69daa28..f65c462 100644 --- a/src/utils.py +++ b/src/utils.py @@ -126,7 +126,7 @@ def format_number(number) -> str: def format_montant(dff: pl.DataFrame) -> pl.DataFrame: def format_function(expr, scale=None): # https://stackoverflow.com/a/78636786 - expr = expr.cast(pl.String).str.splitn(".", 2) + expr = expr.str.splitn(".", 2) num = expr.struct[0] frac = expr.struct[1] From 3270abb7f6e403e93d909f0d76e1cc6b69afea38 Mon Sep 17 00:00:00 2001 From: Colin Maudry Date: Fri, 10 Oct 2025 17:44:51 +0200 Subject: [PATCH 2/4] =?UTF-8?q?Refactor=20du=20filtre=20pour=20=C3=AAtre?= =?UTF-8?q?=20plus=20r=C3=A9silient=20(et=20fonctionner=20sur=20les=20mont?= =?UTF-8?q?ants)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/utils.py | 47 ++++++++++++++++++++++++++++------------------- 1 file changed, 28 insertions(+), 19 deletions(-) diff --git a/src/utils.py b/src/utils.py index f65c462..e200c91 100644 --- a/src/utils.py +++ b/src/utils.py @@ -211,21 +211,30 @@ def filter_table_data(lff: pl.LazyFrame, filter_query: str) -> pl.LazyFrame: filtering_expressions = filter_query.split(" && ") for filter_part in filtering_expressions: col_name, operator, filter_value = split_filter_part(filter_part) - col_type = str(schema[col_name]) if debug: print("filter_value:", filter_value) print("filter_value_type:", type(filter_value)) + print("operator:", operator) print("col_type:", col_type) - if col_type == "Date": - # Convertir la colonne en chaînes de caractères - lff = dates_to_strings(lff, col_name) + lff = lff.filter(pl.col(col_name).is_not_null()) - if operator in ("<", "<=", ">", ">="): - lff = lff.filter( - pl.col(col_name).is_not_null() & (pl.col(col_name) != pl.lit("")) - ) + if col_type == "Date": + # Convertir la colonne date en chaînes de caractères + lff = dates_to_strings(lff, col_name) + col_type = "String" + if col_type == "String": + lff = lff.filter(pl.col(col_name) != pl.lit("")) + + elif col_type.startswith("Int") or col_type.startswith("Float"): + try: + filter_value = int(filter_value) + except ValueError: + logger.error(f"Invalid numeric filter value: {filter_value}") + continue + + if operator in ("contains", "<", "<=", ">", ">="): if operator == "<": lff = lff.filter(pl.col(col_name) < filter_value) elif operator == ">": @@ -234,17 +243,17 @@ def filter_table_data(lff: pl.LazyFrame, filter_query: str) -> pl.LazyFrame: lff = lff.filter(pl.col(col_name) >= filter_value) elif operator == "<=": lff = lff.filter(pl.col(col_name) <= filter_value) - - elif col_type.startswith("Int") or col_type.startswith("Float"): - try: - filter_value = int(filter_value) - except ValueError: - logger.error(f"Invalid numeric filter value: {filter_value}") - continue - lff = lff.filter(pl.col(col_name) == filter_value) - - elif operator == "contains" and col_type in ["String", "Date"]: - lff = lff.filter(pl.col(col_name).str.contains("(?i)" + filter_value)) + elif operator == "contains": + if col_type in ["String", "Date"]: + lff = lff.filter( + pl.col(col_name).str.contains("(?i)" + filter_value) + ) + elif col_type.startswith("Int") or col_type.startswith("Float"): + lff = lff.filter(pl.col(col_name) == filter_value) + else: + logger.error(f"Invalid column type: {col_type}") + else: + logger.error(f"Invalid operator: {operator}") # elif operator == 'datestartswith': # lff = lff.filter(pl.col(col_name).str.startswith(filter_value)") From 7f3a0bcb21e13c8e15e37859f3177a02da135acf Mon Sep 17 00:00:00 2001 From: Colin Maudry Date: Fri, 10 Oct 2025 17:45:15 +0200 Subject: [PATCH 3/4] Renommage de la Github action d'auto release --- .github/workflows/tag-release.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/tag-release.yaml b/.github/workflows/tag-release.yaml index 8c8bc43..99349cf 100644 --- a/.github/workflows/tag-release.yaml +++ b/.github/workflows/tag-release.yaml @@ -4,11 +4,11 @@ on: tags: - 'v*' # Push events to matching v*, i.e. v1.0, v20.15.10 -name: Create Release +name: Auto-release d'un tag jobs: build: - name: Auto-release d'un tag + name: auto-release runs-on: ubuntu-latest steps: - name: Checkout code From 188383a88214a051cecdb889de9dc8eb5637bcd8 Mon Sep 17 00:00:00 2001 From: Colin Maudry Date: Fri, 10 Oct 2025 17:47:18 +0200 Subject: [PATCH 4/4] Changelog 2.1.5 --- README.md | 5 +++++ pyproject.toml | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 7384132..6c490a3 100644 --- a/README.md +++ b/README.md @@ -38,6 +38,11 @@ Ne pas oublier de mettre à jour les fichier .env. ## Notes de version +##### 2.1.5 (10 octobre 2025) + +- réparation des filtres (notamment < > sur les montants) +- remplacement des valeurs "null" dans les tableaux par des cellules vides + ##### 2.1.4 (8 octobre 2025) - possibilité de filtrer sur le champ "Source" diff --git a/pyproject.toml b/pyproject.toml index f70844b..a497672 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,7 +1,7 @@ [project] name = "decp.info" description = "Interface d'exploration et d'analyse des marchés publics français." -version = "2.1.4" +version = "2.1.5" requires-python = ">= 3.10" authors = [ { name = "Colin Maudry", email = "colin+decp@maudry.com" }