Archives de catégorie : Recherche

Manipulation de fichier Excel : utilisez Python

Le besoin était simple, à partir d’un fichier de vente global à une société, il fallait proposer un fichier spécifique par commercial pour qu’il puisse saisir son prévisionnel propre à chacun de ses clients … puis proposer un outil permettant de réaliser la synthèse de ses documents particuliers.

La manipulation de fichier Excel via openpyxl

Les fonctions de base :

L’ouverture d’un fichier excel avec cette libraire se fait comme dans la vraie vie. Il faut ouvrir le fichier : load_workbook puis sélectionner l’onglet dans lequel on souhaite travailler . Les onglets sont stockés sous forme de dictionnaire, il suffit de donc le charger en utilisant comme clé le nom de l’onglet workbook[‘nomOnglet’].

Lire une valeur : Il suffit de repartir de l’objet utilisé pour récupérer l’onglet. Les cellules sont atteignables via le couple Ligne/colonne. Par exemple, pour récupérer la valeur en F13, il suffit de faire : val = onglet[‘F13’].value

def getValueNumerique(ong, key):    
   valT = 0    
   val  = ong[key].value    
   if (isinstance(val, Number)):
      valT =  val   
return valT

Enregistrer une valeur peut être réaliser en faisant une simple affectation : onglet[‘F13’] = val

Ajouter/dupliquer un onglet :         wb.copy_worksheet(wb[‘CC’])

Enregistrer le fichier final : wb.save(« nouveauNom »)

De un vers plusieurs : Python via Panda pour un éclatement rapide

La difficulté la plus grande est de trouver l’élément sur lequel vos filtres vont pouvoir s’appuyer. Dans mon contexte, chaque vente était relié à son représentant. La sélection des données fut donc de :

  • Filtrer sur la période de temps souhaité :         listeCommade38_2018 =   df_filtre_soc[( (df_filtre_soc[« MOIS_FACT »] >= 201800.) & (df_filtre_soc[« MOIS_FACT »] <= 201900.)  )]
  • Puis, après construit la liste des représentants, boucler dessus afin de ne traiter que les ventes du représentant en cours de traitement :     df_filtre = df[(df[« CODE_REPRESENTANT »] == representant_ref)]
  • Dans certain cas, nous n’avons pas besoin que d’une valeur, mais d’une combinaison de valeur. Dans ce cas, la fonction query facilite les regroupements d’information :   m2019 =   (liste_2019_cc_filtre.query(‘@pp.liste_ref in CODE_ART’))[« QTE_EXPE »]
  • On peut ensuite appliquer des fonctions sur le résultat obtenu : nbProd_2019 = m2019.sum()

De plusieurs vers un : une simple routine en Python

Tout aussi simple. Pour identifier l’ensemble des fichiers résultats, la commande glob.glob(path) permet de retrouver un ensemble de fichier correspondant à un dossier et possédant un pattern exploitable.

Ensuite, il suffit d’ouvrir chacun des fichiers, de retrouver l’onglet de synthèse, puis de lire les données calculée via macro. Attention, afin d’avoir la valeur et non la méthode de la macro, il faut passer des arguments à la fonction d’ouverture de document excel :     wb = load_workbook(fich, read_only=False, keep_vba=True,  data_only=True).

Dans mon cas, les données étant réparties en fonction d’un template fixe, j’ai préféré passer par un dictionnaire pour faciliter l’identification des données à consulter :

totaux ={
    'F7' : 0,
    'F8' : 0,
    'F9' : 0,
    'F13' : 0,
    'F14' : 0,
    'F15' : 0,
    'F16' : 0
}

Il suffit ensuite de boucler sur le dictionnaire, pour réaliser, en une boucle, la lecture de l’ensemble des données :

def rechercheOngletSynthese(wb, sommeTige):
    synth =  wb['Synthese']

    for key in totaux:
        val  = synth[key].value  

Une fois les valeurs obtenues, il n’y a plus qu’à construire le fichier résultat (basé une fois de plus sur un template excel.

wb = load_workbook(fichR, read_only=False, keep_vba=True,  data_only=True)

# On va dans l'onglet synthèse
synth =  wb['Synthese']
for key in totaux:
    synth[key] = totaux[key]

sauvegarde_finale('resultat2019.xls' , wb)

Au final, avec deux scripts, nous pouvons automatiser la génération des fichiers à faire remplir, puis la construction de la synthèse. Le temps de développement est relativement cours (le plus long fut la prise du résultat à produire). De plus, le résultat pouvant être produit à la demande, il est très simple de fournir des résultats intermédiaire … le temps que l’ensemble des fichiers reviennent après leur saisie.

Liste des imports utiles :

import csv
import pandas as pd
import produit 
import  re as Regex

#Pour le traitement des fichiers excels
from openpyxl import Workbook
from openpyxl import load_workbook
#Pour la vérification des nombres
from numbers import Number

# Pour les fichiers
import os.path
import glob
from pathlib import Path

import unicodedata

Url :

https://pypi.org/project/openpyxl/

https://pandas.pydata.org/

Qu’est-ce que la dette technique ?

La dette technique est une métaphore du développement logiciel inventée par Ward Cunningham. … Cette définition reste vague mais pose le principe d’un coût représenté par un logiciel ou un SI relativement à sa qualité, sa maintenance ou son cycle de vie.

Un métaphore souvent utilisée pour illustrer ce phénomène est celle de la grenouille plongée dans l’eau bouillante : si l’augmentation de la température est lente, les grenouilles resteront tranquillement à leur place jusqu’à se trouver complètement cuites lorsque l’eau sera bouillante. En revanche, si vous jetez une grenouille directement dans l’eau bouillante, celle-ci trouvera immédiatement la force de s’extraire de ce milieu hostile.

Quand produit-on de la dette ?

Les causes de production de la dette technique sont multiples. Mais le critère le plus important est sur le type de production. Cette production est-elle prise en connaissance de cause (suite à des contraintes temporelles ou techniques), ou est-elle produite de manière passive (quand le choix est basée sur des bases non maîtrisées ou suite à des évolutions techniques non suivie).

Dans tous les cas, et surtout dans le second, il faut prendre le temps de faire l’audit des solutions mises en œuvre pour identifier toutes les sources de production de cette dette. Cette dette, tel un produit financier, à un coût. Ne pas le gérer,risque, à très court terme de rendre la solution beaucoup moins rentable qu’escomptée.

Conséquence de la dette technique

Contrairement à une croyance, même avec des équipes au top, il n’est pas possible d’avoir un projet rapide, pas cher et de qualité.

Les conséquences sur les projets

  • L’explosion du coût de la maintenance :
    Ajouter de la dette sans la prendre en compte risque de souvent complexifier le code de votre solution (duplication de code, de schéma, suppression de test (ou non écriture).
  • La non évolutivité du produit :
    L’ajout de la petite modification penser comme un simple héritage d’un mode de fonctionnement proche revient à modifier plusieurs fonctions utilisées jusqu’à lors telle des boites noires … Attention danger
  • La notion de risque à chaque déploiement :
    Les tests sont souvent les premiers à sauter … et dans ce cas, c’est uniquement lors de la mise en production que l’on risque de s’apercevoir que la boite noire est utilisée dans un autre module … sans aucun rapport fonctionnel …

null

Les conséquences sur les développeurs

  • Le découragement, la démotivation :
    C’est un élément rarement pris en compte mais travailler sur un logiciel instable est vite usant. Perdre beaucoup de son temps car le développement n’est pas ce qu’il aurait du être … ou que la modification simple doit juste être refaite à 10 endroits suite à des duplications de code … supprime vite toute envie de travailler sur un logiciel.
  • La perte de créativité :
    A perdre son temps dans la maintenance, le développeur va limiter l’impact de son travail au strict minimum, c »est à dire la correction de bogue sans avoir l’envie de prendre du recul sur son travail …
  • l’érosion des compétences :
    le pire qu’il peut arriver, à partir d’un certain temps, le développeur risque de se faire une raison … et de perpétuer les mauvaises pratiques qui sont en place dans la solution qu’il est entrain de maintenir.

Comment s’en prémunir?

L’importance de la conception initiale : Laisser le KISS (Keep It Simple and Stupid) pour le poc

L’entretien du code

  • La mise en place d’un PAQL, le plan d’assurance qualité est le document qui va permettre à un développeur de travailler dans un univers cohérent. Il ne s’agit pas de brider la créativité des développeurs, mais simplement de poser un ensemble de règle qui vont permettre à un nouveau développeur de savoir comment s’intégrer dans la structure.
  • Et de son application : c’est le pendant de toute documentation,, après sa rédaction, il faut se donner les capacités de s’assurer de son application … sinon, rapidement, le respect du PAQL ne sera qu’un lointain souvenir.
  • La mise en place d’une revue de code : l’objectif est de discuter du code produit et en aucune façon de le critiquer. Cette revue peut être le moment de mettre à jour le PAQL et de voir comment les stratégies de développement peuvent évoluer.

L’importance de l’automatisation

  • Pour toutes les tâches répétitives : export, admin, …
  • Pour les tests : unitaire ou fonctionnel
  • Pour la qualité du code

Et surtout : L’intégration de la dette dans le backlog des projets … car toute dette se rembourse … sinon d’elle même, elle causera la ruine du projet.

Quelques références

Livre :
– The Pragmatic Programmer,
– Code Legacy

Blog

Power Bi, Open Data et listing des pharmacies

Voici un petit article présentant comment il est possible d’obtenir un listing dans Power BI présentant une grande majorité des pharmacies.

La première étape est de récupérer un fichier contenant l’ensemble des établissements de santé.
Le choix se fait sur le fichier Fichier Finess:

Le choix est déterminé par la certification du fichier et sa fréquence de sa mise à jour.

Ce dossier du site Open Data contient en fait plusieurs documents distincts dont le détail est visible dans l’aperçu précédent.

Pour ce premier article, nous n’aurons besoin que du fichier contenant les extractions Finess des établissements ainsi que la géolocalisation de ces établissements. En supplément, il est possible de consulter le 1er fichier permettant d’obtenir un descriptif des différentes informations contenus dans le dossier.

Le traitement dans Power Bi sera minimaliste. La première étape consiste à importer les différents fichiers CSV. Après import des fichiers, il faut faire attention au typage automatique des colonnes. En effet, pour se faire, Power BI fait un échantillonnage sur les premières colonnes du fichier. Dans le cas des départements, cela pose problème car le type numérique du début de fichier n’est pas conservé sur son intégralité (2A / 2B pour la corse par exemple). Il est donc recommandé de conserver le type alphanumérique pour toutes valeurs qui n’est pas un nombre exploitable. Ceci se fait très facilement en appliquant changeant le type.

Pour le fichier structure, les étapes sont les suivantes :

  1. Source : import initial
  2. Promoted Headers : permet de sélectionner la première ligne comme entête de la table
  3. Changed Type : permet de passer du type numérique à alphanumérique
  4. Merged Queries : permet de faire une jointure entre le référentiel des types de voie et la table structure.

Un autre point à mentionner est que, dans le fichier fournit, le type de voie est donné sous la forme d’un référentiel qui n’est pas fourni. Pour le construire relativement rapidement, il suffit d’utiliser un tableur et de sélectionner l’ensemble des valeurs distincte de la colonne typvoie. Une fois la sélection obtenue, il est possible de créer son propre référentiel après avoir complété l’ensemble des libellés associés.

 

Nous obtenons donc 3 fichiers qu’il est possible le lier par la suite dans l’écran de modélisation.

Un dernier point de détail concerne le widget utilisé pour la localisation des établissements. Celui fonctionne à l’aide des adresses postales. L’inconvénient est quand le fichier fourni, l’adresse est éclaté dans plusieurs champs. Un moyen simple pour contourner ce problème est d’ajouter une colonne calculée à notre table, regroupant l’ensemble des champs devant être joint. On peut voir dans cette formule l’utilisation du référentiel sur le type de voie et l’ajout, en dur, du pays. Le fichier étant localisé par nature, il ne contient pas la notion de pays.

En conclusion, nous obtenons l’ensemble des établissements de santé, géolocalisées, dans des listes filtrables.

Des sources de motivations

Voici quelques liens qui permettent de ne pas se laisser entraîner par la facilité technique de la routine.

Challenge algorithmique :
Nos neurones ont souvent l’envie de paresser et de croire que les algorithmes maîtrisés lors de nos études, le reste par la suite.
Rien de tel que des petits challenges pour relancer notre gymnastique intellectuel :

CodinGame Des concours, des puzzles, des challenges .. il y a toujours moyen de se divertir en enrichissant son agilité algorithmique.

Project Euler Dans le même esprit, mais précurseur, le côté mathématique est beaucoup plus mis en avant.

Histoire de côtoyer les challenges entrepreneurial, voici une triptyque à suivre :
humancoders, pragmaticentrepreneurs, voir codeur

Car nous avons toujours quelques choses à apprendre :
Mooc fun : un Mooc intéressant et de qualité dans la langue de molière.
Safari Une source semblant inépuisable de documentations, vidéos et tutoriels.

C’est connu et reconnu mais avec la libéralisation des données, avoir un référentiel géographique prêt à l’emploi et actualisé est maintenant très rapide.

Le site de l’INSEE met les données dispositions l’ensemble de ces référentiels en libre accès sous forme de fichier dbf ou txt. Le travail d’actualisation des données est pré-mâché (puisqu’une liste de données d’actualisation est disponible).
Il n’y a donc plus aucune excuse à fournir un outil ne permettant pas de faire des statistiques fines sur le positionnement de ces utilisateurs.

Lien sur les référentiels : http://www.insee.fr/fr/methodes/nomenclatures/cog/telechargement.asp

Bonne intégration

Installation de Retroshare sur Debian Sid

Quand des paquets sont disponibles pour d’anciennes versions ou pour d’autre distribution, il est souvent plus souvent de corriger la liste de dépendance d’un paquet plutôt que de le reconstruire de but en blanc.
Cette technique possède toutefois une contrainte importante, il est possible que les évolutions des dépendances aient des conséquences importantes sur les fonctionnalités de l’application. Néanmoins, pour des utilisations classiques, ou sous réserve de tests complémentaires, le gain de temps est très appréciable.

la démarche est la suivante :

En un, décompresser le paquet debian ainsi que sa liste de contrôle:


dpkg-deb -x retroshare_0.5.5-0.7068~wheezy_amd64.deb dir_tmp
dpkg-deb --control retroshare_0.5.5-0.7068~wheezy_amd64.deb dir_tmp/DEBIAN

Il faut ensuite mettre à jour les dépendances pouvant poser problèmes (nouvelle version disponible, renommage … )

Edition du fichier de contrôle :


vi dir_tmp/DEBIAN/control

Dans le cas de rétroshare,le problème se situe sur la dépendance suivante : libprotobuf7 qui n’est maintenant plus disponible en version testing.


Depends: libbz2-1.0, libc6 (>= 2.4), libgcc1 (>= 1:4.1.1), libglib2.0-0 (>= 2.12.0), libgnome-keyring0 (>= 2.22.2), libprotobuf9, libqt4-network (>= 4:4.5.3), libqt4-script (>= 4:4.5.3), libqt4-xml (>= 4:4.5.3), libqtcore4 (>= 4:4.8.0), libqtgui4 (>= 4:4.8.0), libssl1.0.0 (>= 1.0.0), libstdc++6 (>= 4.6), libupnp6 (>= 1:1.6.13), libx11-6, libxss1, zlib1g (>= 1:1.1.4), gnome-keyring

=> Remplacer le libprotobuf7 par libprotobuf9

Il suffit ensuite de reconstruire le paquet via la commande suivante pour avoir un paquet directement installable via les commandes classiques.

Reconstruction du paquet :


dpkg -b dir_tmp retroshare_0.5.5-0.7068~wheezy_amd64.deb

et il est maintenant possible de l’installer.

Ps : Ce post est une adaptation de Install Pencil on Debian qui traite du même problème pour une application différente.

Oracle : Update or Insert = MERGE

J’ai du répondre à une question simple de prime abord, comment mettre un jour un référentiel, non prévu pour être versionné, et ayant pu évoluer de manière différente sur chacun des différents sites de manière indépendante.

Après quelques recherches, le principal mot clé qui pouvait revenir était : MERGE

Un merge pour un développeur, c’est quelque chose de connu et ce n’est pas souvent envisager comme quelque chose de simple et de généralisable.
En théorie si, mais en pratique, c’est souvent durant cette étape que la livraison de son code prend un retard inattendu.

Alors avant d’envisager une telle pratique quand on utilise traditionnellement le SQL pour faire de simple CRUD … on cherche du simple … on envisage de se mettre au PL …. voir de faire une mini application faisant ce que l’on veut.

Et pourtant, le merge cela peut aussi être simple dans certain cas et cela peut rapidement être mis en place.

Comme dit en introduction, mon contexte était le suivant :
– Mise à jour de référentiel
– Pas d’assurance sur l’état du référentiel avant travaux
– Pas nécessairement le temps de s’assurer de la cohérence des données pour chacun des sites.

A priori, il existe plusieurs techniques, plus ou moins simple pouvant arriver à ce résultat.
Dans mon cas, il fallait que le génération du script se fasse dans un temps relativement court … et en ne demandant pas de devenir DBA au passage.

Le processus choisit pour l’actualisation de la table fut le suivant :

– Mise en place d’une date de fin pour l’ensemble des champs du référentiel utilisé en production (assurance de conserver les champs pour les données déjà saisies).
– Injection de la nouvelle table de référentiel
– merge proprement dit entre l’ancienne table et la nouvelle afin d’actualiser les champs utiles, quelques soit l’état de la table initialement.

En SQL, cela donne cela :


-- Généralisation de la date de fin à l'ensemble des occurrences de la table
update SOC_TYPE_DOMICILE set datefin= '01/11/14';

-- Injection de la table référentiel nouvelle version
CREATE TABLE "SOC_TYPE_DOMICILE_REF"
( "CODE" VARCHAR2(10 BYTE),
"CODEREGROUPEMENT" VARCHAR2(10 BYTE),
"DATEDEBUT" DATE,
"DATEFIN" DATE,
"LIBELLE" VARCHAR2(100 BYTE),
"RANGAFFICHAGE" NUMBER(3,0),
"ANCIENCODECSD" VARCHAR2(10 BYTE),
"CODEREGROUPEMENTTYPE" VARCHAR2(10 BYTE),
"ID_LIBELLE" NUMBER(7,0)
);

Insert into SOC_TYPE_DOMICILE_REF (CODE,CODEREGROUPEMENT,DATEDEBUT,DATEFIN,LIBELLE,RANGAFFICHAGE,ANCIENCODECSD,CODEREGROUPEMENTTYPE,ID_LIBELLE) values ('SIFO','SIT_LOC',to_date('01/01/07','DD/MM/RR'),to_date('01/11/14','DD/MM/RR'),'Sans information','1','0',null,null);
Insert into SOC_TYPE_DOMICILE_REF (CODE,CODEREGROUPEMENT,DATEDEBUT,DATEFIN,LIBELLE,RANGAFFICHAGE,ANCIENCODECSD,CODEREGROUPEMENTTYPE,ID_LIBELLE) values ('HEBST','SIT_LOC',to_date('01/01/07','DD/MM/RR'),to_date('01/11/14','DD/MM/RR'),'Hébergement stable','2','2',null,null);
Insert into SOC_TYPE_DOMICILE_REF (CODE,CODEREGROUPEMENT,DATEDEBUT,DATEFIN,LIBELLE,RANGAFFICHAGE,ANCIENCODECSD,CODEREGROUPEMENTTYPE,ID_LIBELLE) values ('HEBPR','SIT_LOC',to_date('01/01/07','DD/MM/RR'),to_date('01/11/14','DD/MM/RR'),'Hébergement précaire ou de durée incertaine','3','A',null,null);
Insert into SOC_TYPE_DOMICILE_REF (CODE,CODEREGROUPEMENT,DATEDEBUT,DATEFIN,LIBELLE,RANGAFFICHAGE,ANCIENCODECSD,CODEREGROUPEMENTTYPE,ID_LIBELLE) values ('HOP','SIT_LOC',to_date('01/01/07','DD/MM/RR'),to_date('01/11/14','DD/MM/RR'),'Hôpital sans perspective de logement à la sortie','4','B',null,null);
Insert into SOC_TYPE_DOMICILE_REF (CODE,CODEREGROUPEMENT,DATEDEBUT,DATEFIN,LIBELLE,RANGAFFICHAGE,ANCIENCODECSD,CODEREGROUPEMENTTYPE,ID_LIBELLE) values ('SAB','SIT_LOC',to_date('01/01/07','DD/MM/RR'),to_date('01/11/14','DD/MM/RR'),'Sans abri, absence totale d hébergement','5','1',null,null);

-- Merge
-- deux cas : la ligne existe : dans ce cas on modifie le libellé pour qu'il corresponde exactement avec le résultat attendu (les valeurs, même modifiées, ne changent pas de sens)
-- La ligne n'existe pas, on l'insère
MERGE INTO SOC_TYPE_DOMICILE S
USING SOC_TYPE_DOMICILE_REF R
ON ( S.CODE = R.CODE )
WHEN matched
THEN UPDATE SET S.DATEFIN = null, S.LIBELLE = R.LIBELLE, S.RANGAFFICHAGE = R.RANGAFFICHAGE, S.ANCIENCODECSD = R.ANCIENCODECSD
WHEN not MATCHED
THEN INSERT (CODE,CODEREGROUPEMENT,DATEDEBUT,DATEFIN,LIBELLE,RANGAFFICHAGE,ANCIENCODECSD,CODEREGROUPEMENTTYPE,ID_LIBELLE)
VALUES (R.CODE,R.CODEREGROUPEMENT,R.DATEDEBUT,R.DATEFIN,R.LIBELLE,R.RANGAFFICHAGE,R.ANCIENCODECSD,R.CODEREGROUPEMENTTYPE,R.ID_LIBELLE);

-- et c'est fini ...

Duplication de clé USB

des fois on se fait plaisir avec peu de ligne de commande ..

Duplication de la clé
dd if=/dev/sdc of=/dev/sdd bs=4096 conv=notrunc,noerror

Hors avec des clés de tailles différentes, on obtient :

fsck /dev/sde1
fsck from util-linux 2.20.1
e2fsck 1.42.8 (20-Jun-2013)
La taille du système de fichiers (selon le superbloc) est de 7793408 blocs
La taille physique du périphérique est de 7674624 blocs
Le superbloc ou la table des partitions est peut-être corrompue !

Un simple : resize2fs -f /dev/sde1 7674624

et tout est de nouveau opérationnel :

fsck /dev/sde1
fsck from util-linux 2.20.1
e2fsck 1.42.8 (20-Jun-2013)
/dev/sde1 : propre, 25468/1925120 fichiers, 303289/7674624 blocs

Je vais de nouveau mettre ma sd card classique dans le Eeepc et la microSD dans une nouvelle go-pro ^^

Cariatides est DMP Compatible

Cariatides est maintenant DMP Compatible pour sa version 6.8 pour les 3 profils du DMP (Dossier Médical Patient) :  Profil création, Profil alimentation et Profil consultation.

Au bout de 3 mois, on voit une sortie positive pour ce projet 😀
Maintenant, il ne reste plus qu’à faire qu’il soit utilisable par des utilisateurs lambdas … Ce n’est pas rien mais le plus important est fait.

Pour info : Cariatides est logiciel de suivit de patient pour les hôpitaux psychiatriques, concu et développé par le GIP Symaris (Rouffach) basé sur le WebObjects associé à une base Oracle.

[ad#Google Adsense]

Communauté : the Innovation Explorers

Depuis le milieu de ce printemps, je fais partie d’une communauté de chercheurs : the Innovation Explorers.

[ad#Google Adsense]

Cette communauté, créé de toute pièce par la maison d’édition Elsevier a pour but de permettre une promotion de la recherche et de ses outils au sein d’un panel de chercheurs selectionnés qui auront la charge par la suite de faire une promotion des outils proposés par Elsevier. Pour attirer des membres, Elsevier a choisi la voie pécunière, un bon d’achat lors de l’inscription, et d’autres en fonction de notre implication.

Au bout de quelques mois de participation, le premier bilan a faire est que la voie pécunière n’était pas le choix le plus judicieux. Comme tous site naissant, le contenu de qualité est encore léger, ce qui est logique. Mais au lieu d’avoir un site communautaire partiellement rempli, nous nous trouvons sur une plateforme pleine de bruit, avec des messages vides qui ont pour simple objectif de faire un « +1 » sur le compte de son auteur (dans l’objectif d’obtenir sa prime mensuelle) …

A voir comment cette communauté arrive à vivre par la suite … mais pour le moment, sa naissance se fait dans la douleur …

the Innovation Explorers :
Mon Id : marcSauget