2010-02-11 11 views
10

Je vous écris une petite suite de tests de DB, qui lit les fichiers de configuration avec les requêtes et les résultats attendus, .: par exemplePython: lire le fichier de configuration avec plusieurs lignes par clé

query   = "SELECT * from cities WHERE name='Unknown';" 
count   = 0 
level   = 1 
name   = "Check for cities whose name should be null" 
suggested_fix = "UPDATE cities SET name=NULL WHERE name='Unknown';" 

Cela fonctionne bien; Je divise chaque ligne en utilisant le string.partition('=') de Python.

Mon problème est de très longues requêtes SQL. Actuellement, je colle juste ces requêtes en tant que doublure, ce qui est laid et non maintenable.

Je veux trouver une façon élégante et pythonique de lire le droit d'une expression, même si elle s'étend sur plusieurs lignes.

Notes:

  • mes requêtes SQL peuvent contenir le =
  • Je ne ai pas envie l'idée de forcer " s autour du côté droit, parce qu'il ya beaucoup de fichiers existants sans elle.

EDIT:

ConfigParser est grande, mais il me oblige à ajouter un espace ou une tabulation au début de chaque ligne dans une entrée multiligne. Cela pourrait être une grande douleur.

Merci à l'avance,

Adam

+0

cet espace/onglet ne sont pas inclus dans la valeur finale – SilentGhost

+0

Pouvez-vous préciser? Je n'ai pas compris votre commentaire. –

Répondre

9

C'est presque exactement le cas d'utilisation qui nous a fait allumons à YAML (Wikipedia, python implementation, documentation, vous voudrez peut-être regarder JSON comme alternative).YAML a quelques avantages sur configparser ou json:

  • lisibilité humaine (mieux que JSON pour des fichiers plus volumineux);
  • peut sérialiser des objets python arbitraires (ce qui le rend aussi sûr que pickle, mais il existe une fonction safe_load dans l'implémentation python pour résoudre ce problème). C'est déjà utile pour quelque chose d'aussi simple qu'un objet datetime.

Pour être complet, les principaux inconvénients (OMI):

  • Python mise en œuvre par un ordre de grandeur plus lente que la mise en œuvre JSON;
  • moins portable sur les plates-formes que JSON.

Par exemple

import yaml 

sql = """ 
query   : "SELECT * from cities 
WHERE name='Unknown';" 
count   : 0 
level   : 1 
name   : "Check for cities whose name should be null" 
suggested_fix : "UPDATE cities SET name=NULL WHERE name='Unknown';" 
""" 

sql_dict = yaml.safe_load(sql) 

print(sql_dict['query']) 

impressions

SELECT * from cities WHERE name='Unknown'; 
+0

+1: yaml est idéal pour une telle configuration – van

+0

+1 Bonne idée. Je vais y regarder. –

+0

+1 correspond magnifiquement au cas d'utilisation. –

12

Le module de bibliothèque standard Python ConfigParser prend en charge cette fonction par défaut. Le fichier de configuration doit être dans un format standard:

[Long Section] 
short: this is a normal line 
long: this value continues 
in the next line 

Le fichier de configuration peut être lu ci-dessus avec le code suivant:

import ConfigParser 
config = ConfigParser.ConfigParser() 
config.read('longsections.cfg') 
long = config.get('Long Section', 'long') 
+1

J'ai un problème avec cette solution car des erreurs sont survenues lors de l'analyse du fichier. Selon la documentation, pour les valeurs multilignes, l'indentation est nécessaire. J'ai ajouté 4 espaces au début de "dans la ligne suivante" et cela fonctionne. – MikeCPT

1

Je vous suggère d'utiliser une expression régulière ... Le le code pourrait ressembler à ceci pour vous donner êtes commencer:

import re 

test="""query = "select * from cities;" 
count = 0 
multine_query = "select * 
from cities 
    where name='unknown';" 
""" 

re_config = re.compile(r'^(\w+)\s*=\s*((?:".[^"]*")|(?:\d+))$', re.M) 
for key, value in re_config.findall(test): 
    if value.startswith('"'): 
     value = value[1:-1] 
    else: 
     value = int(value) 
    print key, '=', repr(value) 

La sortie de cet exemple est la suivante:

~> python test.py 
query = 'select * from cities;' 
count = 0 
multine_query = "select *\nfrom cities\n  where name='unknown';" 

Espérons que ça aide!

Cordialement, Christoph

+1

+1 Cela devrait fonctionner, mais je préfère vraiment un ensemble prêt à l'emploi qui supporte toutes sortes de conditions de bords. –