Nouveau fichier de start up Python 10


Régulièrement je passe un coup de dépoussiérage sur mes outils, et aujourd’hui c’est le tour du script de start up.

Pour ceux qui ne se souviennent pas, on peut utiliser la variable d’environnement PYTHONSTARTUP pour choisir un script de démarrage pour le shell.

Ca attend un chemin absolu vers un fichier Python, et donc sous Mac et Linux, on met dans son .bashrc ou équivalent :

export PYTHONSTARTUP=/chemin/vers/son/script.py

Sous Windows, on ouvre une console et on fait :

SETX PYTHONSTARTUP c:\chemin\vers\son\script.py

Et dedans on peut mettre tout le code Python qu’on veut, ça sera lancé automatiquement quand on démarre le shell, mais PAS quand on lance un script Python.

Le script est exécuté dans l’espace de nom du shell, donc tous les imports du script sont mis à la disposition du shell. Du coup, pour moi il contient :

# -*- coding: utf-8 -*-
 
# faut que ça marche pareil en P2 et P3
from __future__ import unicode_literals, print_function, absolute_import
 
# Les imports des modules de la libs standars que j'utilise le plus
# car à force çe me gave de les réimporter moi-même à chaque session
import sys
import os
import re
import json
import csv
import random
import hashlib
import tempfile
import random
import shelve
import atexit
import subprocess
from glob import glob
from uuid import uuid4
from pprint import pprint
 
# on shadow le open() builtin histoire d'avoir toujours le
# paramètre encoding
from codecs import open
 
from itertools import *
from collections import *
from datetime import datetime, timedelta
 
# imports d'outils tierces parties que j'utilise souvent mais qui pourraient ne
# pas être installés
try:
    import arrow
except ImportError:
    pass
 
try:
    import requests
except ImportError:
    pass
 
try:
    from path import path
except ImportError:
    pass
 
try:
    from minibelt import *
except ImportError:
    pass
 
# activation d'autocompletion si ce n'est pas déjà le cas, notamment sous
# des vieux shell Python ordinnaire
try:
    import rlcompleter
    import readline
    readline.parse_and_bind("tab: complete")
except ImportError:
    pass
 
# si on est dans un virtual env
env = os.environ.get('VIRTUAL_ENV')
if env:
 
    # afficher le nom de l'env dans le prompt (marche pas dans ipython qui
    # a sa propre config pour ça)
    env_name = os.path.basename(env)
    sys.ps1 = '(%s) %s ' % (env_name, getattr(sys, 'ps1', '>>>'))
 
    # affichage une fois des modules installés avec pip pour qu'on sache
    # ce qu'on a a dispo dans cet env
    print("\nVirtualenv '{}' contains:\n".format(env_name))
    cmd = subprocess.check_output([env + "/bin/pip", "freeze"],
                                  stderr=subprocess.STDOUT)
    try:
        cmd = cmd.decode('utf8')
    except:
        pass
 
    cmd = cmd.strip().split("\n")
    p = re.compile(r'(^.*\:\s)|((#|@).*$)|(==.*$)')
    print("'" + "', '".join(sorted(set(os.path.basename(p.sub('', f)) for f in cmd))) + "'\n")
 
 
# alias pour printer rapidement
p = print
pp = pprint
 
# avoir toujours un dossier temporaire près à l'usage
TEMP_DIR = os.path.join(tempfile.gettempdir(), 'pythontemp')
try:
    os.makedirs(TEMP_DIR)
    TEMP_DIR = path(TEMP_DIR) # si possible un objet path
except Exception as e:
    pass
 
# avoir un dico persistant pour garder des objets entre deux sessions. Pratique quand
# on a un gros array numpy qu'on n'a pas envie de se faire chier à se recréer
class Store(object):
    def __init__(self, filename):
        object.__setattr__(self, 'DICT', shelve.DbfilenameShelf(filename))
        # cleaning the dict on the way out
        atexit.register(self._clean)
 
    def __getattribute__(self, name):
        if name not in ("DICT", '_clean'):
            try:
                return self.DICT[name]
            except:
                return None
        return object.__getattribute__(self, name)
 
    def __setattr__(self, name, value):
        if name in ("DICT", '_clean'):
            raise ValueError("'%s' is a reserved name for this store" % name)
        self.DICT[name] = value
 
    def _clean(self):
        self.DICT.sync()
        self.DICT.close()
 
# Ainsi on peut faire store.foo = 'bar' et récupérer store.foo à la session
# suivante. Moi je store tout dans un truc temporaire mais si vous voulez
# garder la persistance entre deux reboots, il suffit de choisir un autre
# dossier. 
python_version = "py%s" % sys.version_info.major
try:
    store = Store(os.path.join(TEMP_DIR, 'store.%s.db') % python_version)
except:
    print('\n/!\ Un session utilisant le store existe déjà. On ne peut pas partager un store.')

Il est un peu relou puisqu’il faut qu’il marche pour P2 et P3…

Je me demande si je devrais pas faire un repo pour ce genre de truc.

10 thoughts on “Nouveau fichier de start up Python

  • touilleMan

    Quelle sensation incroyable de découvrir une fonctionnalité comme ça, je suis joie et félicité !

    Par contre je viens de tester et j’ai l’impression que tu as oublié un “import shelve” vu que j’ai une exception à ce propos au chargement du script…

  • francoisb

    MERCI !

    Je retiens la classe Store.

    Réciproquement, qu’est ce que vous conseillez pour une fonction restart qui réinitialise toutes les variables.

    J’ai un truc moche:

    def restart():

    variables = [var for var in globals() if var[0] != "_" and var!='restart']

    for var in variables:

    del globals()[var]

  • Sam Post author

    Ca dépend de ce que tu veux faire, mais dans ton cas un c’est plus rapide (- de touches) de faire CTRL + D puis enter puis flèche du haut et enter pour relancer l’interpréteur que de taper restart() puisque les deux effacent absolument tout y compris les imports.

  • foxmask

    avec python 3.4 ca hurle sur atexit not define que j’ai regle par un import plus haut

Leave a comment

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <pre> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Des questions Python sans rapport avec l'article ? Posez-les sur IndexError.