22 Commits

Author SHA1 Message Date
0921a41c76 Update dependency Wand to v0.6.13 2024-02-17 05:04:55 +00:00
2b3e935f39 Merge pull request 'Update dependency Send2Trash to v1.8.2' (#15) from renovate/send2trash-1.x into main
Reviewed-on: #15
2024-02-17 04:56:16 +00:00
ef63f22d44 Merge pull request 'Update dependency MarkupSafe to v2.1.3' (#14) from renovate/markupsafe-2.x into main
Reviewed-on: #14
2024-02-17 04:55:55 +00:00
1020ef9257 Update dependency Send2Trash to v1.8.2 2024-01-10 11:04:32 +00:00
39084ceebd Update dependency MarkupSafe to v2.1.3 2024-01-10 11:04:30 +00:00
7de6c8dd9c clean renovate.json 2024-01-10 10:46:45 +00:00
da3815eea6 activate renovate 2024-01-09 06:53:09 +00:00
45d343d810 Feat: add raise error when src does not exists 2024-01-02 22:22:58 +01:00
806227f202 Feat: add logging in join 2023-12-30 17:45:15 +01:00
7bf0c38883 Feat: add option for debugging 2023-12-30 17:25:40 +01:00
b15b059e2a Add debug 2023-12-27 19:58:12 +01:00
48e75358ac Fix: remove index in excel outputs 2023-10-05 15:22:14 +02:00
132e37267b Feat: logging and option about overwritting 2023-10-05 15:19:16 +02:00
f2bcf6241a Fix: rebuild join_excel 2023-10-05 15:10:39 +02:00
ec9cc19be5 fix: remove when 2023-09-20 09:37:50 +02:00
0040dccd9a Feat: Handle get_lot when RECAPITULATIF is nan 2023-09-20 09:28:57 +02:00
b0333cddd8 fix: raise a warning when a page is not recognized 2023-09-20 09:27:40 +02:00
406b89fea1 Feat: publish tag on Matrix 2023-07-08 09:08:09 +02:00
812d392720 feat: publish to matrix
All checks were successful
continuous-integration/drone/push Build is passing
2023-07-08 09:06:25 +02:00
6b77980e6c Fix 7: change the default FOURNISSEUR 2023-07-07 21:26:00 +02:00
90c2d3689b Fix I4: drop row with "" on locataire ans Période 2023-07-05 18:13:41 +02:00
f9be31c090 Fix #3: replace empty string with np.nan 2023-07-05 17:49:25 +02:00
9 changed files with 117 additions and 41 deletions

View File

@@ -22,10 +22,18 @@ steps:
PYPI_TOKEN:
from_secret: pypi_token
when:
event:
include:
- tag
- name: Notify on matrix
image: plugins/matrix
environment:
MATRIX_ROOMID:
from_secret: MATRIX_ROOMID
MATRIX_ACCESSTOKEN:
from_secret: MATRIX_ACCESSTOKEN
MATRIX_USERID:
from_secret: MATRIX_USERID
settings:
homeserver: https://matrix.poneyworld.net
template: "Une nouvelle version (${DRONE_TAG}) de pdf-oralia est publiée!"
# Déclencheur de la pipeline
trigger:

View File

@@ -45,7 +45,7 @@ def from_pdf(pdf):
charge_tables = []
patrimoie_tables = []
for page in pdf.pages:
for page_number, page in enumerate(pdf.pages):
page_text = page.extract_text()
date = extract_date(page_text)
additionnal_fields = {
@@ -76,7 +76,7 @@ def from_pdf(pdf):
pass
else:
raise ValueError("Page non reconnu")
logging.warning(f"Page {page_number+1} non reconnu. Page ignorée.")
df_charge = charge.table2df(recapitulatif_tables + charge_tables)
df_loc = locataire.table2df(loc_tables)

29
pdf_oralia/join.py Normal file
View File

@@ -0,0 +1,29 @@
import glob
import logging
import pandas as pd
def join_excel(src, dest, file_pattern):
"""Join every excel file in arc respecting file_pattern into on unique file in dist"""
filenames = list_files(src, file_pattern)
logging.debug(f"Concatenate {filenames}")
dfs = extract_dfs(filenames)
joined_df = pd.concat(dfs)
logging.debug(f"Writing joined excel to {dest}")
joined_df.to_excel(dest, index=False)
logging.debug(f"with {len(joined_df)} rows")
def list_files(src, file_glob):
return list(glob.iglob(f"{src}/{file_glob}"))
def extract_dfs(filenames):
dfs = []
for filename in filenames:
logging.debug(f"Extracting {filename}")
df = pd.read_excel(filename)
logging.debug(f"Found {len(df)} rows")
dfs.append(df)
return dfs

View File

@@ -17,6 +17,7 @@ DF_TYPES = {
"annee": str,
"lot": str,
}
DEFAULT_FOURNISSEUR = "ROSIER MODICA MOTTEROZ SA"
def is_it(page_text):
@@ -31,7 +32,10 @@ def is_it(page_text):
def get_lot(txt):
"""Return lot number from "RECAPITULATIF DES OPERATIONS" """
regex = r"[BSM](\d+)(?=\s*-)"
result = re.findall(regex, txt)
try:
result = re.findall(regex, txt)
except TypeError:
return "*"
if result:
return "{:02d}".format(int(result[0]))
return "*"
@@ -62,8 +66,8 @@ def extract(table, additionnal_fields: dict = {}):
for k, v in additionnal_fields.items():
r[k] = v
if "honoraire" in row[RECAPITULATIF_DES_OPERATIONS]:
r["Fournisseur"] = "IMI GERANCE"
if "honoraire" in row[RECAPITULATIF_DES_OPERATIONS].lower():
r["Fournisseur"] = DEFAULT_FOURNISSEUR
extracted.append(r)
@@ -83,6 +87,5 @@ def table2df(tables):
df = pd.concat(dfs)
df["immeuble"] = df["immeuble"].apply(lambda x: x[0].capitalize())
print(df.columns)
df["lot"] = df["RECAPITULATIF DES OPERATIONS"].apply(get_lot)
return df.astype(DF_TYPES, errors="ignore")
return df.astype(DF_TYPES)

View File

@@ -1,3 +1,4 @@
import numpy as np
import pandas as pd
DF_TYPES = {
@@ -33,7 +34,7 @@ def is_drop(row):
def extract(table, additionnal_fields: dict = {}):
"""Turn table to dictionary with additionnal fields"""
"""Turn table to dictionary with additional fields"""
extracted = []
header = table[0]
for row in table[1:]:
@@ -138,8 +139,6 @@ def join_row(table):
}
)
joined.append(row)
else:
pass
return joined
@@ -159,4 +158,9 @@ def table2df(tables):
df["immeuble"] = df["immeuble"].apply(lambda x: x[0].capitalize())
df["Type"] = df["Type"].apply(clean_type)
return df.astype(DF_TYPES, errors="ignore")
numeric_cols = [k for k, v in DF_TYPES.items() if v == float]
df[numeric_cols] = df[numeric_cols].replace("", np.nan)
df = df.drop(df[(df["Locataires"] == "") & (df["Période"] == "")].index)
return df.astype(DF_TYPES)

View File

@@ -5,29 +5,33 @@ from pathlib import Path
import click
from .extract import extract_save
logging_config = dict(
version=1,
formatters={"f": {"format": "%(levelname)-8s %(name)-12s %(message)s"}},
handlers={
"h": {
"class": "logging.StreamHandler",
"formatter": "f",
"level": logging.DEBUG,
}
},
root={
"handlers": ["h"],
"level": logging.DEBUG,
},
)
dictConfig(logging_config)
from .join import join_excel
@click.group()
def main():
pass
@click.option("--debug/--no-debug", default=False)
def main(debug):
if debug:
logging_level = logging.DEBUG
else:
logging_level = logging.INFO
logging_config = dict(
version=1,
formatters={"f": {"format": "%(levelname)-8s %(name)-12s %(message)s"}},
handlers={
"h": {
"class": "logging.StreamHandler",
"formatter": "f",
"level": logging_level,
}
},
root={
"handlers": ["h"],
"level": logging_level,
},
)
dictConfig(logging_config)
@main.group()
@@ -64,5 +68,31 @@ def all(src, dest):
@main.command()
@click.option("--src", help="Tous les fichiers dans src", default="./")
@click.option("--dest", help="Où mettre les fichiers produits", default="")
def join(src, dest):
join_excel(src, dest, df_names=["charge", "locataire"])
@click.option(
"--force",
help="Ecraser si le ficher destination existe.",
default=False,
is_flag=True,
)
def join(src, dest, force):
"""Join tous les fichiers excel charge (resp locataire) de src dans un seul fichier charge.xlsx dans dist.
Exemple:
pdf-oralia join --src <dossier_source> --dest <dossier_destination>
"""
dest_charge = f"{dest}/charge.xlsx"
if not force and Path(dest_charge).exists():
raise ValueError(f"The file {dest_charge} already exists")
dest_locataire = f"{dest}/locataire.xlsx"
if not force and Path(dest_locataire).exists():
raise ValueError(f"The file {dest_locataire} already exists")
if not Path(src).exists():
raise ValueError(f"The source directory ({src}) does not exists.")
join_excel(src, dest_charge, "*_charge.xlsx")
logging.info(f"Les données charges ont été concaténées dans {dest_charge}")
join_excel(src, dest_locataire, "*_locataire.xlsx")
logging.info(f"Les données locataires ont été concaténées dans {dest_locataire}")

View File

@@ -1,6 +1,6 @@
[tool.poetry]
name = "pdf-oralia"
version = "dev"
version = "0"
description = ""
authors = ["Bertrand Benjamin <benjamin.bertrand@opytex.org>"]
readme = "README.md"

2
renovate.json Normal file
View File

@@ -0,0 +1,2 @@
{
}

View File

@@ -29,7 +29,7 @@ jupyter_client==7.3.5
jupyterlab-pygments==0.2.2
jupyterlab-widgets==3.0.3
lxml==4.9.1
MarkupSafe==2.1.1
MarkupSafe==2.1.3
matplotlib-inline==0.1.6
mistune==2.0.4
nbclient==0.6.8
@@ -62,7 +62,7 @@ pytz==2022.2.1
pyzmq==24.0.1
qtconsole==5.3.2
QtPy==2.2.0
Send2Trash==1.8.0
Send2Trash==1.8.2
six==1.16.0
soupsieve==2.3.2.post1
stack-data==0.5.1
@@ -70,7 +70,7 @@ terminado==0.15.0
tinycss2==1.1.1
tornado==6.2
traitlets==5.4.0
Wand==0.6.10
Wand==0.6.13
wcwidth==0.2.5
webencodings==0.5.1
widgetsnbextension==4.0.3