samedi 27 décembre 2014

Linux Mint: Démarrer un Script Python depuis de bureau

Cet article décrit les différentes étapes pour démarrer un script python à partir d'un lien sur le bureau de Linux Mint (dérivé d'Ubuntu).

Introduction
PrestaShop est un chouette e-commerce mais il traine malheureusement quelques lacunes parfois très handicapantes.
L'une de ses faiblesses se trouve dans le SAV... il est parfois impossible de localiser un nouveau message client lorsqu'il l'envoi sur un ancien ticket (nous avons +3000 ticket et +5000 messages. Argh!

Utiliser un script Python
Grâce à l'API PrestaShop et à Python, il est possible d'écrire un script qui lit les derniers messages reçu sur le WebShop... ce qui permet de localiser plus facilement un tel message et d'avoir les informations adéquate pour le localiser rapidement (l'ID du fil de discussion dans notre cas).

Les scripts Python et utilisateurs finaux
Si je suis à l'aise avec un terminal Linux, ce n'est pas le cas de tout le monde.
L'idéal, c'est quand même d'avoir une icon sur le Bureau qui permet de lancer le script et afficher les résultats attendu.
Même si l'affichage est en mode texte vilain et méchant, ce n'est pas un problème... par contre, le démarrage du script reste un point critique pour un utilisateur Lambda.
C'est là que les choses sont un poil plus compliquées...

Bloquer le script en fin d'exécution
C'est idiot mais il est important de bloquer le script en fin d'exécution. Dans le cas contraire, le script termine son travail... l’interpréteur Python aussi et la fenêtre disparait de l'écran.
Le but c'est de laisser à l'utilisateur le temps de lire le résultat qui s'affiche à l'écran!
Pour cela, n'oubliez pas de faire un import sys en début de script
        import sys

Puis de terminer votre script python par les lignes pour force l'utilisateur à encoder un caractère pour terminer l'exécution du script
    # read char on keyboard
    char = sys.stdin.read(1)
    return 0


Ce que nous avons fait dans notre script savtrack.py...

Créer un Shell Script
Avant toute chose, il est vivement recommandé de créer un shell script (.sh) pour démarrer le script Python.
Le but de ce dernier est:
1) mettre en place les éléments nécessaires à la bonne exécution du script python
2) lancer le script python... éventuellement dans un terminal plus convivial! 

Dans le cas de notre script savtrack.py, nous devons absolument nous trouver dans le sous répertoire PrestaConsole du répertoire utilisateur (le fameux ~/PrestaConsole).
Notre script python à besoin de lire les fichiers cachefile.pkl et config.ini... faut mieux se trouver dans le bon répertoire avant de démarrer le script!

allons y, créons notre script shell "savtrack.sh"... c'est lui qui sera démarré depuis notre bureau Linux.

#!/bin/bash

echo ==========================================
echo       listing SAV
echo ==========================================

cd /home/domeu/PrestaConsole
mate-terminal -e "/usr/bin/python /home/domeu/PrestaConsole/savtrack.py"

Comme vous pouvez le noter, nous faisons un cd (change directory) dans le bon répertoire avant de lancer le script python à l'aide de:
/usr/bin/python /home/domeu/PrestaConsole/savtrack.py

C'est quoi ce mate-terminal???
En fait, en lançant le script "savtrack.sh" depuis le bureau (voir plus loin), Linux Mint va utiliser le terminal xterm par défaut, terminal efficace mais très rudimentaire et peu convivial de prime abord.

Mon script crache un listing assez long (plus qu'un écran) et il est donc important d'avoir un terminal qui dispose d'une scrollbar permettant de naviguer dans le lonnngggg texte produit par notre script savtrack.py.
C'est pour cela que mate-terminal est utilisé pour démarrer le script python.
Résultat affiché dans mate-terminal
Rendre le script shell exécutable
Ce n'est pas tout d'avoir, un script savtrack.sh pour mettre la machine en branle, il faudrait également que ce dernier soit exécutable. Voici la commande qui rendra cela possible.

chmod +x savtrack.sh

n'hésitez pas a tester directement votre script shell depuis le terminal. Il suffit de taper la commande

./savtrack.sh

(le préfix ./ sert à informer le terminal, sans ambiguité possible, que nous voulons bien exécuter le script).

Installer xterm
Comme précisé, l'icone sur le bureau lancera savtrack.sh dans le terminal xterm (par défaut).
Pour une raison que j'ignore, xterm n'était pas installé sur mon système?!?! Pour y remédier, saisissez la commande suivante dans un terminal.

sudo apt-get install xterm

Création du lien (lanceur) sur le bureau

Faite un clique droit sur votre bureau... puis sélectionnez l'option "Créer un lanceur..." dans le menu contextuel.

Cela affiche une boite de dialogue suivante
Création d'un lanceur
La première chose à faire est de sélectionner le type de lanceur... "application dans un terminal"... c'est cette option qui permet de lancer un script shell. Le terminal utilisé sera xterm (par défaut).

Reste à compléter le restant des information... attention a bien sélectionner le script shell dans la commande (savtrack.sh dans notre cas).

Pressez OK et le raccourci est créé sur le bureau :-)
Voila!

Note pour les puristes:
Il est bien entendu possible de modifier le terminal à utiliser par le lanceur.
Il serait donc possible de remplacer directement xterm par mate-terminal.
Par contre, cela nous impose de se souvenir de la modification si nous voulons installer notre script sur un autre ordinateur....
A contrario, les choses sont "écrites" noir sur blanc dans notre shell script.

dimanche 7 décembre 2014

F3: tester des périphériques de stockage (SD ou USB) sous Linux

Lumière sur le projet F3 (oss.digirati.com.br/f3), ce dernier permet de tester des cartes SD/USB stick.
Le programme est relativement simple et se compose de deux utilitaires f3write (pour écrire des fichiers de tests) et f3read pour effectuer les tests de lecture.

Petite présentation par l'auteur

F3 - une alternative à h2testw
Ce projet à commencé lorsque Michel Machado de F3 à acheté une carte de 32GB microSDHC pour son Android (c'était en 2010). Il a remarqué que la carte présentait toujours des défaillances lorsqu'elle était remplie. En faisant quelques recherches sur Google, il est arrivé sur les blogs Fight Flash Fraud et SOSFakeFlash qui recommande tout deux l'usage du logiciel H2testw (voir ici ou ici) pour tester les mémoires flashs.
Michel à téléchargé H2testw et à été immédiatement confronté a deux problèmes:
  1. H2testw est logiciel Windows uniquement
  2. H2testw n'est pas un logiciel open-source.
Cependant, Harald Bögeholz (l'auteur de H2testw), est assez sympa pour inclure un fichier texte décrivant comment fonctionne son programme (ainsi que le générateur de nombre aléatoire).

Ainsi naquis F3 et sa page oss.digirati.com.br/f3 qui est l'implémentation GPLv3 de H2testw réalisé par Michel Machado. Version qui fonctionne sous Linux, Macs, Windows/Cygwin et FreeBSD.
Cette implémentation s'appelle F3, qui est le raccourci de "Fight Flash Fraud" ou "Fight Fake Flash".

Comment installer F3 sous Linux
Si vous diposez d'Ubuntu ou un de ses dérivé (ex: Linux Mint), un simple apt-get fera l'affaire :-)

sudo apt-get install f3

Utiliser f3
F3 se compose de deux programme f3write et f3read.
F3write est destiné à remplir votre périphérique avec des fichiers de données (attention, il rempli l'espace disponible). f3write remplit le système de fichier avec des fichiers de 1GB nommés N.h2w, où N est un numér.
F3read relit les fichiers et fait une validation du contenu, c'est ainsi que l'on détecte les corruptions.

Voici un exemple pratique (par l'auteur)
$ ./f3write /media/5EBD-5C80/
Free space: 28.83 GB
Creating file 1.h2w ... OK!
Creating file 2.h2w ... OK!
Creating file 3.h2w ... OK!
Creating file 4.h2w ... OK!
Creating file 5.h2w ... OK!
Creating file 6.h2w ... OK!
Creating file 7.h2w ... OK!
Creating file 8.h2w ... OK!
Creating file 9.h2w ... OK!
Creating file 10.h2w ... OK!
Creating file 11.h2w ... OK!
Creating file 12.h2w ... OK!
Creating file 13.h2w ... OK!
Creating file 14.h2w ... OK!
Creating file 15.h2w ... OK!
Creating file 16.h2w ... OK!
Creating file 17.h2w ... OK!
Creating file 18.h2w ... OK!
Creating file 19.h2w ... OK!
Creating file 20.h2w ... OK!
Creating file 21.h2w ... OK!
Creating file 22.h2w ... OK!
Creating file 23.h2w ... OK!
Creating file 24.h2w ... OK!
Creating file 25.h2w ... OK!
Creating file 26.h2w ... OK!
Creating file 27.h2w ... OK!
Creating file 28.h2w ... OK!
Creating file 29.h2w ... OK!
Free space: 0.00 Byte
Average Writing speed: 2.60 MB/s

$ ./f3read /media/5EBD-5C80/
                  SECTORS      ok/corrupted/changed/overwritten
Validating file 1.h2w ...       0/  2097152/      0/      0
Validating file 2.h2w ...       0/  2097152/      0/      0
Validating file 3.h2w ...       0/  2097152/      0/      0
Validating file 4.h2w ...       0/  2097152/      0/      0
Validating file 5.h2w ...       0/  2097152/      0/      0
Validating file 6.h2w ...       0/  2097152/      0/      0
Validating file 7.h2w ...       0/  2097152/      0/      0
Validating file 8.h2w ...       0/  2097152/      0/      0
Validating file 9.h2w ...       0/  2097152/      0/      0
Validating file 10.h2w ...       0/  2097152/      0/      0
Validating file 11.h2w ...       0/  2097152/      0/      0
Validating file 12.h2w ...       0/  2097152/      0/      0
Validating file 13.h2w ...       0/  2097152/      0/      0
Validating file 14.h2w ...       0/  2097152/      0/      0
Validating file 15.h2w ...       0/  2097152/      0/      0
Validating file 16.h2w ...       0/  2097152/      0/      0
Validating file 17.h2w ...       0/  2097152/      0/      0
Validating file 18.h2w ...       0/  2097152/      0/      0
Validating file 19.h2w ...       0/  2097152/      0/      0
Validating file 20.h2w ...       0/  2097152/      0/      0
Validating file 21.h2w ...       0/  2097152/      0/      0
Validating file 22.h2w ...       0/  2097152/      0/      0
Validating file 23.h2w ...       0/  2097152/      0/      0
Validating file 24.h2w ... 1916384/   180768/      0/      0
Validating file 25.h2w ...  186816/  1910336/      0/      0
Validating file 26.h2w ...       0/  2097152/      0/      0
Validating file 27.h2w ...       0/  2097152/      0/      0
Validating file 28.h2w ...       0/  2097152/      0/      0
Validating file 29.h2w ...   28224/  1705280/      0/      0

  Data OK: 1.02 GB (2131424 sectors)
Data LOST: 27.81 GB (58322336 sectors)
        Corrupted: 27.81 GB (58322336 sectors)
 Slightly changed: 0.00 Byte (0 sectors)
      Overwritten: 0.00 Byte (0 sectors)
Average Reading speed: 9.54 MB/s

L'exemple ci-dessus indique que la carte Flash est sacrément corrompue. Plus de 27Go de données sont corrompu.

Localiser le /media
Comme vous pouvez le constater dans l'exemple, la carte SD est montée dans le répertoire /media. Le périphérique est directement accessible via /media/5EBD-5C80/
La valeur 5EBD-5C80 change d'un périphérique Flash à l'autre....

Chez MCHobby, nous sommes plutôt accros à Linux Mint. Dans ce cas, la carte SD n'est pas montée dans /media/5EBD-5C80 mais dans /media/votre_login_utilisateur/5EBD-5C80

samedi 8 novembre 2014

GoJS - Du code javascript pour réaliser et manipuler des diagrammes en ligne

Je prenais quelques renseignements sur le Canvas HTML quand je suis tombé un peu par hasard sur GoJS.net.


GoJS permet de réaliser des diagrammes interactif pour le WEB. J'ai pris le temps de naviguer dans les exemples... et c'est franchement impressionnant (même exceptionnel!).
Un des nombreux exemples de GoJS
Ce que je trouve particulièrement intéressant de GoJS est la structure de donnée bien pensée permettant d'élaborer un tel graphique en ligne!!!
Structure descriptive des graphiques interactif GoJS
Les exemples
Prenez donc le temps d'aller jeter un oeil sur les exemples proposés par GoJS.
Prenez aussi une chaise, vous allez certainement en avoir besoin :-)


Un référence à retenir:
  • GoJs.net - Interactive Diagrams for the Web


vendredi 7 novembre 2014

Retrouver un environnement Linux sur Windows (console bash, GIT)

Si vous travaillez souvent avec Unix, vous savez à quel point l'interface en ligne commande (cmd.exe) de Windows peut être furstant!!!

A côté de cela, installer le package logiciel de Cygwin de 100Mb pour disposer de la commande "ls" revient à utiliser un canon pour tuer une mouche.

Au cours de quelques recherches, j'ai trouvé le très intéressant article
Où il semblerait bien que l'installation de msysgit offre l'environnement Git Bash à la fois léger et efficace pour l'utilisation de commandes Linux (avec le support Git en plus).
Interface de Git Bash où il est possible d'utiliser les commandes Linux


Sans se contenter de cet outil, l'auteur s'est penché sur le projet Console2 pour offrir une interface console encore plus en phase avec le standard visuel Linux.
Interface visuelle de Console2


Bref, une lecture fort intéressante... d'autant que l'auteur explique l'installation de façon assez détaillée (un plaisir).

A notez aussi qu'il existe une alternative GOW (Gnu On Window) qui est vénéré par certain et jugé de façon plus critique par d'autres.

samedi 2 août 2014

Conventions de nom en Python

Vous voulez savoir quels sont les conventions pour nommer des fonctions, des variables, des classes en Python?

Je vous propose la lecture de:
Une ressource vraiment importante et fiable issue des PEPs (Python Enhancement Proposal).

Nom des packages (paquets) et des modules
Les nom des modules doivent être court et uniquement en minuscule. Vous pouvez utiliser des soulignés (underscores) dans les noms des modules si cela améliore la lisibilité. Les packages (paquets) Python doivent également être court et uniquement minuscule. L'utilisation de souligné (underscore) est déconseillé dans le nom des paquets.

Etant donné que le nom du module correspond à un fichier sur le système d'exploitation -- et que certain système d'exploitation sont sensible à la case (ou tronque les noms) -- il est important de choisir un nom de module aussi court que possible.  Cela n'est pas un problème pour des systèmes Unix/Linux mais pourrait le devenir si vous portez votre code vers de vieux Mac, Windows, Dos.

Lorsqu'un module d'extension écrit en C ou C++ est accompagné d'un module Python offrant une interface d'accès de haut niveau (ex: via une interface orienté objet), ALORS le module C/C++ dispose d'un souligné (underscore) en entête (ex: _socket).

Nom des classes

Les noms de classes devrait utiliser la convention de noms des mots capitalisés (VoiciUnExempleDeNomDeClasseEnCapitalizedWord).

La convention de nom des fonctions devrait être utilisé dans les cas d'une interface documentée pour être utilisée comme "callable".

Nom des exceptions
La convention de nom des classes est utilisé pour les exceptions car une exception est aussi une classe.
Le sufixe Error doit être utilisé dans le nom de vos exception (pour distinguer les exceptions des classes... si l'exception est, bien entendu, une erreur).


Nom des variables globales
(en supposant que les variables sont destinées uniquement à l'usage interne du module.) La convention à utiliser est similaire à celle des fonctions.

Pour les modules qui sont conçu pour utiliser via from M import * devraient utiliser le mécanisme __all__ pour éviter l'exportation des variables globales ou utiliser une ancienne convention qui consiste à préfixer de telles variables globales à l'aide d'un souligné (underscore, ce qui permet d'indiquer que ces variables globales ne sont pas publique au niveau du module (hors du module).
 
Nom des Fonctions
Les noms de fonction devraient être en minuscule, avec des soulignés (_) insérés pour améliorer la lisibilité (en fonction des besoins).

L'utilisation du "mixedCase" est toléré si c'est un style déjà prédominant  (ex. threading.py), ce qui permet de préserver la retro-compatibilité.

Les arguments des fonctions et des méthodes
Toujours utiliser self comme premier argument d'une méthode.

Toujours utiliser cls pour le premier argument d'une méthode de classe.

Nom des méthodes et variables d'instance
Use Utiliser la convention de nom des fonctions:Les noms de fonction devraient être en minuscule, avec des soulignés (_) insérés pour améliorer la lisibilité (en fonction des besoins).

Utiliser un souligné (underscore) pour débuter le nomdes des méthodes non publique et les variables d'instance.

Pour éviter une colision de nom avec les sous-classes, il est possible de préfixer le nom avec un double souligné (underscore) pour forcer Python à limiter la portée du nom.

Lorsque vous avez un double souligné (underscore), en interne, Python préfixe ce nom ave le nom de la classe. Si la classe Foo à un attribut nommé __a, cet attribut ne peut pas être accessible via Foo.__a. (Un utilisateur insistant devrait utiliser Foo._Foo__a.)
En général, le double souligné devrait être utilisé pour éviter un conflit de nom avec un attribut d'une classe destinée à être une sous-classe.

Note: il y a quelques contreverses concernant l'usage des __noms.

Constantes
Les constantes sont généralement définit au niveau du module, écrit avec des lettres capitales et utilisant des soulignés (underscore) pour séparer les mots. Exemples: MAX_OVERFLOW et TOTAL.

lundi 28 juillet 2014

ClamAV - Un anti-virus pour mon Linux

Hé oui, ce n'est pas parce que Linux est plus sécurisé qu'il n'est pas totalement immunisé.

En cas de doute, sachez qu'il existe aussi des anti-virus pour Linux

jeudi 24 juillet 2014

Ecrire un script Python pour Gimp

En plein traitement d'image pour standardiser les images introduites dans notre base d'information (en vue de constituer un catalogue), il y a un certain nombre d'opération identiques que je réalise systématiquement.

Au bout de 1700 images traitée (et encore autant à faire), certaines routines de traitement se dégagent clairement. Gimp disposant de bon raccourcis claviers, les opérations sont assez rapide... mais il y a encore moyen de faire mieux à l'aide d'un script.

Sur base des informations trouvées dans l'article "Python-Fu #2 - Yout first Python-Fu plugin" écrit par Frédéric Jaume, je me suis lancé dans le test et la réalisation d'un script pour automatiser le cadrage final de nos image.

Un log pour Python-Fu sous Gimp
Le plus compliqué ne fut pas de créer le script (un peu d'expérience Python cela aide), mais d'avoir un système de log suffisamment efficace pour tracer le script.
La méthode la plus simple est de rediriger  stdout et stderr dans un fichier (écrasé à chaque exécution du script)
#!/usr/bin/env python
# -*- coding: utf-8 -*-

# GIMP Python plug-in template.

from gimpfu import *
import sys

__DEBUG = True

# Redirect the print statement to file (usefull for debugging)
if __DEBUG:
  sys.stderr = open( 'c:\\temp\\gimpstderr.txt', 'w')
  sys.stdout = open( 'c:\\temp\\gimpstdout.txt', 'w')

def gimp_log( sMsg ):
  """ Log to StdOut (or nothing) depending on the __DEGUG flag """
  if __DEBUG:
    print( sMsg )
  else:
    pass


Script final
Voici la version finale du script gg_crop_resize.py, qu'il faut placer dans le répertoire plug-ins.


#!/usr/bin/env python
# -*- coding: utf-8 -*-

# GIMP Python plug-in template.

from gimpfu import *
import sys

__DEBUG = True

# Redirect the print statement to file (usefull for debugging)
if __DEBUG:
  sys.stderr = open( 'c:\\temp\\gimpstderr.txt', 'w')
  sys.stdout = open( 'c:\\temp\\gimpstdout.txt', 'w')

def gimp_log( sMsg ):
  """ Log to StdOut (or nothing) depending on the __DEGUG flag """
  if __DEBUG:
    print( sMsg )
  else:
    pass
    
# Display a message in the status bar
#    pdb.gimp_message("test")

# Some functions about progress 
#
#    pdb.gimp_progress_init( 'Test2', None )
#    pdb.gimp_progress_set_text('This goes to the status bar')
#    pdb.gimp_progress_pulse()
#    pdb.python_fu_console()
#    pdb.gimp_progress_end()

def do_gg_crop_resize():
    """ Crop image to selection THEN scale image to fit properly a 2848 x 2848 
        picture THEN resize Canvas to fit photo format 4282 x 2848 (image 
        centered)"""

    # Diplay message in the bottom of the console
    pdb.gimp_message("GG Crop Resize...")
  
    # Print to the standard output (which is a file)    
    gimp_log( "do_gg_crop_resize:")
     
    # Set up an undo group, so the operation will be undone in one step.
    #pdb.gimp_undo_push_group_start(img)

    # NB: The last opened file is always at index 0, previous opened file 
    #     at index 1 and so on.
    count = len( gimp.image_list() )
    img = gimp.image_list()[count-1]
    sel = pdb.gimp_selection_bounds(img)
    if sel[0] == 0:
      pdb.gimp_message("GG Crop Resize Stopped - No selection!")
      gimp_log( "Stopped! No selection" )
      return
      
    # Crop the image 
    pdb.gimp_image_crop( img, sel[3]-sel[1], sel[4]-sel[2], sel[1], sel[2] )
    gimp_log( "Current Size (width,height)=(%i,%i)" % (img.width,img.height) )
    
    # Calculate Image Ratio
    ratio = img.height / float(img.width)
    gimp_log( "Current Ratio Height/width = %f" % (ratio) )
    
    if img.width > img.height:
      gimp_log( "Image is Larger THEN scale width " )
      pdb.gimp_image_scale( img, 2848, 2848 * ratio ) # New Width, New Height
      pdb.gimp_image_resize( img, 4282, 2848, (4282-img.width)/2, (2848-img.height)/2 )
      
      
    else:
      gimp_log( "Image is Higher THEN scale height ")
      pdb.gimp_image_scale( img, 2848 / ratio, 2848 )
      pdb.gimp_image_resize( img, 4282, 2848, (4282-img.width)/2, (2848-img.height)/2 )
      
    pdb.gimp_message( "GG Crop Resize completed" ) 
    gimp_log( "Treatment complete" )
    # Close the undo group.
    #pdb.gimp_undo_push_group_end(img)

register(
    "gg_crop_resize",
    "Crop and resize to photo",
    "Crop to selection, resize and center to Photo dimensions",
    "Meurisse D.",
    "Guy Gerard SPRL",
    "2014",
    "GG Crop Resize", # Menu item Name
    "*",      # Alternately use RGB, RGB*, GRAY*, INDEXED etc.
    [],
    [],
    do_gg_crop_resize, 
    menu="<Image>/GG"  # Host menu for the MenuItem
    
)

main()

Une fois Gimp redémarré, le point de menu apparait dans le menu principal de gimp (version 2.8 dans mon cas)

mardi 3 juin 2014

Clipper: Envoi d'email via SMTP - L'entête/header email

En tant que développeur des années 2010-2015, vous avez probablement accès à des bibliothèques, outils ou API vous permettant d'envoyer facilement des email. Ce genre d'outils qui prend en charge tout le travail... mais aussi qui vous éloigne du savoir de base.
Ces outils, c'est magnifique tant que cela fonctionne... mais Quid si vous n'avez qu'une bibliothèque rudimentaire capable de faire un envoi STMP?
Encore une fois, ce seront les connaissances les plus anciennes (et les plus basique) qui seront les plus utiles... à savoir la constitution d'un header/entête d'émail. Vous trouverez d'ailleurs une excellente référence de documentation en fin d'article ;-)

C'est dans les vieilles casseroles que l'on fait les meilleurs soupes
Je trafficote toujours avec Harbour Project (Compilateur Clipper Open-Source).... et je me demandais s'il était possible d'envoyer directement des e-mails depuis notre logiciel de gestion.
Limiter le nombre de couches logiciels et ne pas devoir s'appuyer sur un programme externe est plutôt intéressant dans notre cas... inutile de perdre de longues heures à essayer de comprendre ce qui ne fonctionne pas... il suffit de gratter dans le programme.
SMTP est toujours d'actualité et nous offre les services dont nous avons besoin... pourquoi se compliquer la vie avec MAPI qui n'arrête pas de demander des autorisations à l'utilisateur pour l'email.

Harbour Project - TIPTest
Dans les contributions du compilateur Harbour, vous trouverez le répertoire hbtip pour "HarBour Tools IP".
HBTIP contient par ailleurs un objet TIpClientSmtp() permettant d'envoyer des e-mais directement via un serveur ou un relay SMTP
C'est génial, il est possible d'envoyer un e-mail directement sur le Net depuis un programme écrit en Clipper :-)

Pour résumer les éléments clés de l'envoi d'émail dans TipTest.prg.
J'ai encodé en dur la valeur de cURL dans le programme, juste avant la ligne tURL():New( cURL ), parce que nous avons un petit problème de conversion DOS <-> Windows.

   && Domeu test - TipTest.PRG
   &&   override cUrl because of translation issue between Windows and
   &&   dos around the & character

   &&  smtp://Adresse_Email_Emetteur@serveur_smtp/Adresse_Email_destinataire
   &&  A noter: l'adresse_Email_Emetteur DOIT UTILISER &at; à la place du @!!!
   cUrl := 'smtp://stock&at;mydomain.be@relay.our_provider.be/dominique@customer_domain.be'
   && cFile est le fichier contenant l'mail à envoyer... 

   &&    attention, ce fichier doit contenir le header du mail!
   && C'est là que le site de DAN intervient
   cFile := "+c:\tipmail.txt"
   oUrl := tURL():New( cUrl )


Plus loin dans le code, l'on retrouve l'envoi du contenu du mail

IF oClient:nAccessMode == TIP_WO .OR. ( oClient:nAccessMode == TIP_RW .AND. bWrite )
         oClient:exGauge := { | done, size| ShowGauge( done, size ) }

         IF oClient:WriteFromFile( cFile )
            @7, 5 SAY "Data sucessfully sent"
         ELSE
            @7, 5 SAY "ERROR: Data not sent " + oClient:lastErrorMessage()
         ENDIF
      ELSE

      ...

Le corps du mail
Comme précisé, le corps du mail est un fichier qui doit impérativement contenir le header du mail.
Qui sait encore comment constituer un tel header (il n'aura fallu quelques recherches pour y arriver)

Voici un exemple de corps d'émail avec son header

Return-Path: <noreply@our_domain.be>
From: Stock Program <noreply@our_domainbe>
To: Dominique MachinChose <dominique@customer_domain.be>
Subject: Notification de Changement de Prix - OUR_DOMAIN SPRL
MIME-Version: 1.0
Content-Type: text/plain;
    charset="iso-8859-1"
Cher client,

*** LE CONTENU DE CET EMAIL EST GENERE AUTOMATIQUEMENT ***
*** NE PAS REPONDRE A CE MESSAGE ***

Nous avons le plaisir de vous informer des modifications de prix suivantes:

xxx
xxx
xxx

Cordialement
L'équipe de OUR_DOMAIN SPRL.

En cas de problème, veuillez contacter celui_la@our_domain.be


Comme vous pouvez le constater, il y a un header relativement sommaire... ce dernier était pourtant nécessaire pour le bon acheminement du mail.
Chaque fournisseur de service à ses propres exigences concernant le contenu minimum du header

Résultat du test
Réceptions des messages sur un client mail
Contenu du message
Comment constituer le Header/Entete d'un Mail?
Vous n'imaginez pas combien il est difficile de trouver un bon site de documentation (abordable) à propos des Header de mail. Il y aura forcement les spécifications de notoriété publique mais si ces dernières sont complètes, elles sont souvent impossible à utiliser comme premier document d'apprentissage :-/

Je vous recommande chaudement le site de Dan, une perle dans le domaine

jeudi 8 mai 2014

Attaquer le port série en PowerShell

J'ai justement l'intention de mettre au point une petite interface machine -> homme avec un Arduino.
L'avantage d'Arduino, c'est qu'il est reconnu comme un port série lorsqu'il il est branché sur le PC.

Je peux donc informer mon petit Arduino d'une tâche à réaliser depuis notre programme en m'adressant à lui directement via le port série :-)

Pour mon grand malheur notre programme date de l'age de pierre (code Clipper compilé en 32bit avec Harbor-project, DB en PostgreSql).
Du coup, j'ai régulièrement l'occasion de déléguer certaines tâches directement à des scripts PowerShell... un bon compromis pour interagir avec le système... la où la fonctionnalité n'est pas accessible via Clipper.

Du coup, je me demandais s'il était possible d'adresser facilement le port série depuis un script PowerShell.
La réponse est oui:
Ecriture sur le port-série:
PS> [System.IO.Ports.SerialPort]::getportnames()
COM3
PS> $port= new-Object System.IO.Ports.SerialPort COM3,9600,None,8,one
PS> $port.open()
PS> $port.WriteLine("Hello world")
PS> $port.Close()

Lecture sur le port série
PS> $port= new-Object System.IO.Ports.SerialPort COM3,9600,None,8,one
PS> $port.Open()
PS> $port.ReadLine()

Souce: Cet article de MSDN


mercredi 7 mai 2014

Application console en Python sous Windows

Introduction
C'est un peu par hasard que je suis tombé sur le dépôt Console-2010... une bibliothèque Python qui vise à faciliter les développements de type console sous Windows.

Comme déjà précisé, si Python est un langage extrêmement puissant, réaliser des interfaces n'est pas son point fort.
Vous réaliserez vite que réaliser un programme console avec une ligne d'invitation (pour l'encodage de données) ne coule pas forcément de source :-/

J’accueille donc un tel projet les bras grand ouverts


Informations produite par l'auteur
==================
The console module
==================

This kit contains a simple console interface for Windows 9X/NT/2K/XP.
It provides a cursor-addressable text display, plus support for
keyboard and mouse input.

The console interface also comes with a command editing and history
implementation (readline) for Windows platforms.

Enjoy /F

fredrik@pythonware.com
http://www.pythonware.com
....
----------------------------------------
_wincon.c   the low-level driver for Win32

Console.py   high-level interface

readline.py   (experimental) command history and editing for Windows.
    to enable this module, just put it on the Python path.

setup.py   build/installation script

*.html            documentation

demo*.py   various demo and test scripts (the latter are in varying
tests/*.py        shape)


Plus d'information

Introduction à TkInter - Interface graphique en Python

Si Python est extrêmement puissant pour les tâches d'automatisation, force est de reconnaître qu'il lui manque quelque-chose si l'on veut développer des interfaces graphiques.

A vrai dire, Python est resté ouvert... sans volonté de s'attacher à une interface. En gros, c'est a vous de choisir et à la mettre en oeuvre.
Il existe de nombreuses solutions disponible mais je viens justement de tomber sur une chouette documentation d'introduction à TkInter (un interface graphique pour Pyhton).


Lecture a conseiller donc:
Mais à voir aussi

vendredi 2 mai 2014

Sublime Text: Un éditeur de code sympa pour code Python

Vous codez assez régulièrement en Python (ou autre langage) et vous cherchez un éditeur de texte open-source?

Vous pouvez vous pencher sur Geany déjà abordé dans un précédent article.
Si ce dernier ne remplit pas vos attentes, vous pouvez aussi vous pencher sur Sublime Text qui est vraiment pas mal.

Sublime Text - Simple et efficace... avec de nombreuses fonctionnalités
Disponible pour Mac, Windows et Linux.
Pour plus d'information, voir le site officiel de Sublime Text

Merci à Xavier D. pour cette information intéressante.

jeudi 17 avril 2014

pgScript - un langage de scripting pour PostgreSql

PostgreSql supporte bien entendu les procédures stockées, trigger, fonction et toutes les fonctionnalités attendue et souhaitée.

Par contre, utilisé des procédures stockées pour faire des tests de faisabilités ou études d'information en vue d'un développement future, ce n'est pas franchement pratique.

Je m'intéresse de plus près à la "couverture de stock" en vue d'une implémentation dans le soft maison.
Avant de me lancer dans l'analyse et développement, je voudrais faire différentes études et corrélations sur les données... que nous avons en grande quantité.
Se lancer dans le développement d'une stored proc de test ne me paraît pas être l'approche la plus appropriée.

Après quelques recherches, j'ai trouvé une excellent référence sur PGScript (aussi appelé PGS) qui permet justement de faire du scripting rapidos... histoire de faire différents vérifications ou traitements.


Un excellent article, pas trop long, assez complet et structuré... à lire:

mardi 1 avril 2014

Interroger le suivit d'un Colis GLS en Python

Prenons l'exemple du site de GLS qui propose une page de tracking pour ses colis

https://gls-group.eu/BE/en/home

 En utilisant la fenêtre à l'aide de la barre d'outil de développement de FireFox, ont apprend ceci

  1. Le <form> utilise la méthode GET sur track-trace
  2. La zone de saisie <input> se nomme tnav-tracking
Nous allons donc pouvoir interroger le site et obtenir une réponse.
Pour nous aider dans cette tâche, nous allons utiliser la bibliothèque httplib2 que vous aurez peut-être besoin d'installer.

Voici le petit bout de code en Python qui permet d'interroger le site de tracking:

from httplib2 import Http
from urllib import urlencode

# Important de désactiver la verif des certificat
#
h = Http(disable_ssl_certificate_validation=True)

# Créer un dictionnaire avec les données du formulaire
# Le numéro de colis a été modifié (ce n'est plus un vrai)!
#
data = { 'tnav-tracking':'716323112233' }
resp, content = h.request( "http://gls-group.eu/BE/en/track-trace", "GET", urlencode(data) )

print( resp )

La dernière ligne affiche le résultat de la requête (voir ci-dessous) contenu dans resp qui affiche un status 200 (donc OK) J'ai bien entendu maquillé les informations dans les cookies

{'status': '200', 'content-location': 'https://gls-group.eu/BE/en/track-trace',
'content-language': 'en-US', 'transfer-encoding': 'chunked', 'set-cookie': 'BIGi
pServerp_portal2_prod=xxxxx; path=/, TSc80417=xxxxx; Path=/, TSc80417_31=xxxxx; Path=/', 
'date': 'Tue, 01 Apr 2014 08:27:30 GMT', 'content-type': 'text/html; charset=UTF-8'
}

La variable content contient, quant a elle, la page html (format brute) retourné par le serveur de GLS.
Cette dernière faisant 42Ko, je ne vais pas la joindre à cet article.


installer PIP sous windows

Pip est un utilitaire bien pratique pour installer des bibliothèques Python.

Cet utilitaire est très bien supporté sous Linux et Mac... mais son installation sous Windows diffère un peu.
Même si je préfère mes système *NIX, au travail je n'ai pas vraiment le choix de ma plateforme... il faut donc des solutions

Heureusement, il y a PIP for Windows :-)


C'est agréable de ne pas devoir tourner en rond pour trouver une solution

Ressource

jeudi 27 février 2014

Executer des processus et commandes Shell ou DOS depuis PowerShell

Besoin d'exécuter une commande DOS avec de nombreux paramètre depuis PowerShell?

Hé bien moi aussi... et je dois avouer qu'il y a de quoi s'arracher les cheveux... sauf si l'on sait quel article lire (car il y a quand même de nombreuses méthodes pour y arriver)

  1. Direct - Using the environment path or local folder
  2. Invoke-Expression (IEX)
  3. Invoke-Command (ICM)
  4. Invoke-Item (II)
  5. The Call Operator &
  6. cmd /c - Using the old cmd shell
  7. Start-Process (start/saps)
  8. [Diagnostics.Process] Start()
  9. WMI Win32_Process Create() Method
  10. Stop-Parsing Symbol --%



Toutes ces méthodes sont décrites dans l'article "PowerShell: Running Executables" paru sur le TechNet de MicroSoft.

A consulter attentivement... au risque de tourner en rond pendant longtemps!


Pour moi, la solution fut celle de l'opérateur &

& "C:\Program Files (x86)\PlotSoft\PDFill\PDFill.exe" HeadFoot "c:\stock\Output\PubPdf\AX.pdf" "c:\stock\Output\PubPdf\AX-step1.pdf" 0 0 18 20 18 20 "Ch. orange: Smurf" -align 2 -fontEncode "Occidental" -fontName "Calibri" -fontSize 10.0 -rgbFontColor "0 0 0"

lundi 13 janvier 2014

Petit Rappel sur l'archivage Linux tar.gz

Source: http://www.linux-kheops.com/doc/dupoux/compress/

Introduction
Nous allons voir comment compresser et décompresser des fichiers sous Linux (comme avec Winzip sous Windows). Nous n'étudierons que les outils en ligne de commande, car ils sont standards, fonctionneront sur toutes les distributions de Linux, et il n'est pas nécessaire de disposer de XWindow.
La compression est un élément indispensable. Dès qu'on récupère un programme sur Internet, il est compressé. La plupart du temps, le format utilisé est le format .TAR.GZ (tar.gzip), qui est standard, et que tout le monde peut décompacter sans problème. Mais il existe aussi un format plus récent: le BZ2 (bzip2) qui est moins répandu, mais plus efficace. Il faut avoir l'utilitaire Bzip2 pour pouvoir utiliser les données. Ce dernier format est d'ailleurs utilisé pour compresser le noyau 2.2 de Linux: avec ce format (BZ2), il n'occupe que 10 Mo, contre 13 Mo en .TAR.GZ.

Le format .tar.gz
L'extension .TAR.GZ (ou parfois TGZ) indique que le fichier est avant tout une archive TAR, qui a été ensuite compressée avec Gzip (GZ). Le rôle de l'utilitaire TAR est de créer une archive, donc de regrouper plusieurs fichiers, comme par exemple tout un dossier, en un unique fichier d'extension .TAR. Et ensuite, gzip compresse cette archive. La compression et la décompression s'effectuent donc en deux étapes. Mais on peut demander à TAR de faire appel à Gzip avec l'option z, donc dans ce cas, une seule opération suffit à créer ou utiliser un fichier .TAR.GZ. 

Compression d'une Archive

Syntaxe:
tar <options> <fichier .tar.gz à créer> <fichiers à ajouter>

Dans les options, on doit mettre c pour créer une archive et non la décompresser, f pour indiquer qu'il s'agit d'un fichier, on peut mettre z pour compresser avec Gzip, et v si on désire avoir la liste des fichiers compressés qui défile.

Exemple:
tar cfvz kfilecoder.tar.gz /root/projects/kfilecoder

Dans cet exemple, on crée un fichier kfilecoder.tar.gz compressé avec Gzip, dans lequel on met tous les fichiers contenus dans le dossier /root/projects/kfilecoder



Extraction d'une archive .TAR.GZ

Syntaxe: 

tar <options> <fichier .tar.gz à extraire>

Dans les options, on doit mettre x pour extraire l'archive indiquée, f pour indiquer qu'il s'agit d'un fichier, on peut mettre z pour décompresser avec Gzip, et v si on désire avoir la liste des fichiers compressés qui défile.

Exemple: 
tar xfvz kfilecoder.tar.gz

Dans cet exemple, on extrait l'archive kfilecoder.tar.gz, en la décompressant avec Gzip, tous les fichiers sont copiés dans le dossier courant.
Remarque: attention à la casse. Par exemple l'option z (minuscule) pour compresser au format Gzip ne doit pas être confondue avec l'option Z (majuscule) qui compresse au format Compress, qui est totalement différent.