python
  • configuration-files
  • text-parsing
  • sql
  • 2010-02-11 15 views 10 likes 
    10

    Estoy escribiendo un pequeño conjunto de pruebas DB, que lee los archivos de configuración con las consultas y los resultados esperados, por ejemplo .:Python: Leer archivo de configuración con múltiples líneas por clave

    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';" 
    

    Esto funciona bien; Divido cada línea usando Python's string.partition('=').

    Mi problema es consultas SQL muy largas. Actualmente, simplemente pego estas consultas como una línea, lo cual es feo y no se puede mantener.

    Quiero encontrar una manera elegante y pitonica de leer el derecho de una expresión, incluso si se extiende por muchas líneas.

    Notas:

    • mis consultas SQL puede contener las =
    • No me gusta la idea de obligar a " s alrededor del lado derecho, porque hay muchos archivos existentes sin ella.

    EDIT:

    ConfigParser es grande, pero me obliga a añadir un espacio o tabulador al principio de cada línea en una entrada de varias líneas. Esto podría ser un gran dolor.

    Gracias de antemano,

    Adam

    +0

    este espacio/pestaña no está incluido en el valor final – SilentGhost

    +0

    puedes contar? No entendí tu comentario. –

    Respuesta

    9

    Esto es casi exactamente el caso de uso que nos hizo cambiar a YAML (Wikipedia, python implementation, documentation, es posible que desee mirar a JSON como alternativa).YAML tiene algunas ventajas sobre configparser o json:

    • legibilidad humana (mejor que JSON para archivos más grandes);
    • puede serializar objetos arbitrarios de python (lo que lo hace tan poco seguro como pickle, pero hay una función safe_load en la implementación de python para aliviar este problema). Esto ya es útil para algo tan simple como un objeto datetime.

    Por el bien exhaustividad, las principales desventajas (IMO):

    • aplicación Python por un orden de magnitud más lenta que la aplicación JSON;
    • menos portátil en plataformas que JSON.

    Por ejemplo

    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']) 
    

    impresiones

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

    +1: yaml es ideal para dicha configuración – van

    +0

    +1 Gran idea. Lo investigaré. –

    +0

    +1 se adapta maravillosamente a la funda de uso. –

    12

    El Python módulo de biblioteca estándar ConfigParser soporta esto por defecto. El archivo de configuración tiene que estar en un formato estándar:

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

    el archivo de configuración anterior podría leerse con el siguiente código:

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

    Tengo un problema con esta solución ya que se producen errores al analizar el archivo. De acuerdo con la documentación, para los valores de líneas múltiples se necesita una sangría. Agregué 4 espacios al comienzo de "en la siguiente línea" y funciona. – MikeCPT

    1

    Yo te sugeriría a utilizar una expresión regular ... El código podría tener este aspecto para dar usted es empezar:

    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 salida de este ejemplo es:

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

    Espero que ayude!

    Saludos, Christoph

    +1

    +1 Eso debería funcionar, pero realmente prefiero un paquete listo para usar que admita todo tipo de condiciones de borde. –

    Cuestiones relacionadas