Archivo de propiedades en python (similar a las Propiedades de Java)

137

Dado el siguiente formato ( .properties o .ini ):

propertyName1=propertyValue1
propertyName2=propertyValue2
...
propertyNameN=propertyValueN

Para Java existe la clase Propiedades que ofrece funcionalidad para analizar / interactuar con el formato anterior.

¿Hay algo similar en la biblioteca estándar de python (2.x)?

Si no, ¿qué otras alternativas tengo?

Andrei Ciobanu
fuente
55
Esta no es una pregunta de Java. ¿Por qué revierte la eliminación de la etiqueta Java?
BalusC

Respuestas:

69

Para los archivos .ini existe el módulo ConfigParser que proporciona un formato compatible con los archivos .ini.

De todos modos, no hay nada disponible para analizar archivos .properties completos, cuando tengo que hacer eso simplemente uso jython (estoy hablando de secuencias de comandos).

pygabriel
fuente
10
pyjavaproperties parece ser una opción si no desea utilizar Jython: bitbucket.org/jnoller/pyjavaproperties
Hans-Christoph Steiner
2
el archivo de propiedades de java no es equivalente al archivo .ini. pyjavaproperties es la respuesta correcta
igni
2
Alex Matelli sugirió una manera fácil de analizar archivos .properties con ConfigParser aquí stackoverflow.com/a/2819788/15274
pi.
bitbucket.org/jnoller/pyjavaproperties no se ha mantenido desde 2010. No es compatible con python 3. Usaría las soluciones vinculadas por @pi.
codyzu
Como en ninguna parte aquí se menciona, permítanme agregar nuevamente que esto no es lo mismo. No puedo hablar para Java o Py3, y tal vez funcione para claves / valores simples. Pero la sintaxis para la interpolación de cadenas es diferente. Esta solución proporciona formato Python, es decir. % (string) s while (por ejemplo, Ant) Usaría $ {string}. pymotw.com/2/ConfigParser
MPE
74

Pude hacer que esto funcione ConfigParser, nadie mostró ningún ejemplo sobre cómo hacer esto, así que aquí hay un simple lector de Python de un archivo de propiedades y un ejemplo del archivo de propiedades. Tenga en cuenta que la extensión todavía está .properties, pero tuve que agregar un encabezado de sección similar a lo que ve en los archivos .ini ... un poco bastardo, pero funciona.

El archivo python: PythonPropertyReader.py

#!/usr/bin/python    
import ConfigParser
config = ConfigParser.RawConfigParser()
config.read('ConfigFile.properties')

print config.get('DatabaseSection', 'database.dbname');

El archivo de propiedades: ConfigFile.properties

[DatabaseSection]
database.dbname=unitTest
database.user=root
database.password=

Para obtener más funcionalidad, lea: https://docs.python.org/2/library/configparser.html

James Oravec
fuente
55
El módulo ConfigParser ha cambiado de nombre a configparser en Python 3.
Gursewak Singh
Esto es para archivos .ini, no para archivos .properties, ya que no contienen secciones, y configParser falla si no encuentra ningún encabezado de sección. Además, los archivos ini pueden no incluir secciones, por lo que este configParser no parece confiable en absoluto
BiAiB
65

Un archivo de propiedades de Java a menudo también es un código válido de Python. Puede cambiar el nombre de su archivo myconfig.properties a myconfig.py. Luego solo importa tu archivo, así

import myconfig

y acceder a las propiedades directamente

print myconfig.propertyName1
Travis Bear
fuente
11
Me gusta la idea, pero no funciona para propiedades que contienen puntos, prop.name="val"es decir, no funcionará en este caso.
maxjakob
36
A java properties file is valid python code: Tengo que diferir. Algunos archivos de propiedades Java pasarán por un código python válido, pero ciertamente no todos. Como dijo @mmjj, los puntos son un problema. Así son las cadenas literales sin comillas. -1.
Manoj Govindan
24
Una idea bastante mala ... ya que está rota. Los archivos de utilería de Java permiten ":" en lugar de "="; comen espacios en blanco después de las continuas líneas; No citan cadenas. Nada de eso es "Python válido".
Dan H
2
Los archivos de propiedades de Java en general no pasarán por un código válido de Python. Una alternativa es simplemente establecer sus propiedades en un archivo de pitón, y el uso de Python válida (por ejemplo: MEDIA_ROOT = '/ foo') ...
danbgray
3
Este es un truco que es mejor evitar. Va a tener un mal día cuando cambien sus propiedades y el archivo ya no sea válido en Python.
r_2
59

Sé que esta es una pregunta muy antigua, pero la necesito justo ahora y decidí implementar mi propia solución, una solución pura de Python, que cubre la mayoría de los casos de uso (no todos):

def load_properties(filepath, sep='=', comment_char='#'):
    """
    Read the file passed as parameter as a properties file.
    """
    props = {}
    with open(filepath, "rt") as f:
        for line in f:
            l = line.strip()
            if l and not l.startswith(comment_char):
                key_value = l.split(sep)
                key = key_value[0].strip()
                value = sep.join(key_value[1:]).strip().strip('"') 
                props[key] = value 
    return props

Puede cambiar sepa ':' para analizar archivos con formato:

key : value

El código analiza correctamente líneas como:

url = "http://my-host.com"
name = Paul = Pablo
# This comment line will be ignored

Obtendrá un dict con:

{"url": "http://my-host.com", "name": "Paul = Pablo" }
Roberto
fuente
1
¡Solución de primera clase y es exactamente lo que estaba buscando!
Russell
Tenga en cuenta que esto no admite comentarios en la misma línea que las entradas como foo = "bar" # bat.
ThomasW
1
@ThomasW Si estamos utilizando Java como el estándar de facto, Properties # load lo tratará como una propiedad foocon valor "bar" # bat.
bonh
1
¿Pensaste qué sentido tiene publicar una respuesta a una vieja pregunta? El punto es que pude ahorrar tiempo simplemente copiando y pegando esto, en una de mis tuberías azules, en lugar de implementarlo yo mismo. así que gracias :)
viejo monje
1
Me encanta la respuesta! El único cambio que hice la tramitación de observaciones en línea fue cambiar l = line.strip()a l = line.split(comment_char)[0].strip()y sólo comprobar si ltiene un valor más bien en la línea posterior con if l:.
Ben Dalling
17

Si tiene una opción de formatos de archivo, sugiero usar .ini y ConfigParser de Python como se mencionó. Si necesita compatibilidad con los archivos Java .properties, he escrito una biblioteca llamada jprops . Estábamos usando pyjavaproperties, pero después de encontrar varias limitaciones, terminé implementando la mía. Tiene soporte completo para el formato .properties, incluyendo soporte unicode y mejor soporte para secuencias de escape. Jprops también puede analizar cualquier objeto similar a un archivo, mientras que pyjavaproperties solo funciona con archivos reales en el disco.

Matt bueno
fuente
1
Acabo de probar esto. Funciona de maravilla. +1 para MattGood!
Dan H
1
si agrega pip install y un ejemplo de código, su respuesta será aún mejor pip install jprops, con open (ruta) como fp: properties = jprops.load_properties (fp) print (propiedades)
Rubber Duck
10

Si no tiene propiedades de varias líneas y una necesidad muy simple, unas pocas líneas de código pueden resolverlo por usted:

Archivo t.properties:

a=b
c=d
e=f

Código de Python:

with open("t.properties") as f:
    l = [line.split("=") for line in f.readlines()]
    d = {key.strip(): value.strip() for key, value in l}
mvallebr
fuente
6

Esto no es exactamente propiedades, pero Python tiene una buena biblioteca para analizar archivos de configuración. Consulte también esta receta: un reemplazo de Python para java.util.Properties .

Manoj Govindan
fuente
1
Para el segundo enlace ... Esto ya no se desarrolla activamente. Jesse noller ha creado un proyecto a partir de esta receta con algunas correcciones no disponibles aquí. El autor recomienda ese proyecto a cualquiera que use esta receta. pypi.python.org/pypi/pyjavaproperties
Big Al
3

Este es un reemplazo uno a uno de java.util.Propeties

Del documento:

  def __parse(self, lines):
        """ Parse a list of lines and create
        an internal property dictionary """

        # Every line in the file must consist of either a comment
        # or a key-value pair. A key-value pair is a line consisting
        # of a key which is a combination of non-white space characters
        # The separator character between key-value pairs is a '=',
        # ':' or a whitespace character not including the newline.
        # If the '=' or ':' characters are found, in the line, even
        # keys containing whitespace chars are allowed.

        # A line with only a key according to the rules above is also
        # fine. In such case, the value is considered as the empty string.
        # In order to include characters '=' or ':' in a key or value,
        # they have to be properly escaped using the backslash character.

        # Some examples of valid key-value pairs:
        #
        # key     value
        # key=value
        # key:value
        # key     value1,value2,value3
        # key     value1,value2,value3 \
        #         value4, value5
        # key
        # This key= this value
        # key = value1 value2 value3

        # Any line that starts with a '#' is considerered a comment
        # and skipped. Also any trailing or preceding whitespaces
        # are removed from the key/value.

        # This is a line parser. It parses the
        # contents like by line.
tmow
fuente
3

Puede usar un objeto similar a un archivo ConfigParser.RawConfigParser.readfpdefinido aquí -> https://docs.python.org/2/library/configparser.html#ConfigParser.RawConfigParser.readfp

Defina una clase que sustituya y readlineque agregue un nombre de sección antes del contenido real de su archivo de propiedades.

Lo he empaquetado en la clase que devuelve una dictde todas las propiedades definidas.

import ConfigParser

class PropertiesReader(object):

    def __init__(self, properties_file_name):
        self.name = properties_file_name
        self.main_section = 'main'

        # Add dummy section on top
        self.lines = [ '[%s]\n' % self.main_section ]

        with open(properties_file_name) as f:
            self.lines.extend(f.readlines())

        # This makes sure that iterator in readfp stops
        self.lines.append('')

    def readline(self):
        return self.lines.pop(0)

    def read_properties(self):
        config = ConfigParser.RawConfigParser()

        # Without next line the property names will be lowercased
        config.optionxform = str

        config.readfp(self)
        return dict(config.items(self.main_section))

if __name__ == '__main__':
    print PropertiesReader('/path/to/file.properties').read_properties()
Alexander Pogrebnyak
fuente
3

He usado esto, esta biblioteca es muy útil

from pyjavaproperties import Properties
p = Properties()
p.load(open('test.properties'))
p.list()
print(p)
print(p.items())
print(p['name3'])
p['name3'] = 'changed = value'
Andy Quiroz
fuente
2

Esto es lo que estoy haciendo en mi proyecto: acabo de crear otro archivo .py llamado properties.py que incluye todas las variables / propiedades comunes que utilicé en el proyecto, y en cualquier archivo necesito referirme a estas variables, poner

from properties import *(or anything you need)

Usé este método para mantener la paz cuando estaba cambiando las ubicaciones de desarrollo con frecuencia y algunas variables comunes eran bastante relativas al entorno local. Funciona bien para mí, pero no estoy seguro de que este método se sugiera para un entorno de desarrollo formal, etc.

fiesta
fuente
2
import json
f=open('test.json')
x=json.load(f)
f.close()
print(x)

Contenido de test.json: {"host": "127.0.0.1", "user": "jms"}


fuente
2

He creado un módulo de Python que es casi similar a la clase de propiedades de Java (en realidad es como el PropertyPlaceholderConfigurer en primavera que le permite usar $ {variable-reference} para referirse a la propiedad ya definida)

EDITAR: puede instalar este paquete ejecutando el comando (actualmente probado para python 3).
pip install property

El proyecto está alojado en GitHub

Ejemplo: (La documentación detallada se puede encontrar aquí )

Supongamos que tiene las siguientes propiedades definidas en el archivo my_file.properties

foo = I am awesome
bar = ${chocolate}-bar
chocolate = fudge

Código para cargar las propiedades anteriores

from properties.p import Property

prop = Property()
# Simply load it into a dictionary
dic_prop = prop.load_property_files('my_file.properties')
Anand Joshi
fuente
Supongamos que tiene las siguientes propiedades definidas en el archivo my_file.properties foo = Soy increíble bar = $ {chocolate} -bar chocolate = fudge Código para cargar las propiedades anteriores prop = Property () prop.load ('path / to / my_file .properties ') prop.get (' foo ') # Soy increíble prop.get (' bar ') # fudge-bar
Anand Joshi
Hecho . Espero que ayude
Anand Joshi
2

Si necesita leer todos los valores de una sección en el archivo de propiedades de una manera simple:

Su config.propertiesdiseño de archivo:

[SECTION_NAME]  
key1 = value1  
key2 = value2  

Usted codifica:

   import configparser

   config = configparser.RawConfigParser()
   config.read('path_to_config.properties file')

   details_dict = dict(config.items('SECTION_NAME'))

Esto le dará un diccionario donde las claves son las mismas que en el archivo de configuración y sus valores correspondientes.

details_dict es :

{'key1':'value1', 'key2':'value2'}

Ahora para obtener el valor de key1: details_dict['key1']

Poniendo todo en un método que lee esa sección del archivo de configuración solo una vez (la primera vez que se llama al método durante la ejecución de un programa).

def get_config_dict():
    if not hasattr(get_config_dict, 'config_dict'):
        get_config_dict.config_dict = dict(config.items('SECTION_NAME'))
    return get_config_dict.config_dict

Ahora llame a la función anterior y obtenga el valor de la clave requerida:

config_details = get_config_dict()
key_1_value = config_details['key1'] 

-------------------------------------------------- -----------

Extendiendo el enfoque mencionado anteriormente, leyendo sección por sección automáticamente y luego accediendo por nombre de sección seguido de nombre de clave.

def get_config_section():
    if not hasattr(get_config_section, 'section_dict'):
        get_config_section.section_dict = dict()

        for section in config.sections():
            get_config_section.section_dict[section] = 
                             dict(config.items(section))

    return get_config_section.section_dict

Acceder:

config_dict = get_config_section()

port = config_dict['DB']['port'] 

(aquí 'DB' es un nombre de sección en el archivo de configuración y 'puerto' es una clave en la sección 'DB').

TheCuriousOne
fuente
1

Debajo de 2 líneas de código se muestra cómo usar Python List Comprehension para cargar el archivo de propiedades 'java style'.

split_properties=[line.split("=") for line in open('/<path_to_property_file>)]
properties={key: value for key,value in split_properties }

Eche un vistazo a la publicación a continuación para obtener detalles https://ilearnonlinesite.wordpress.com/2017/07/24/reading-property-file-in-python-using-comprehension-and-generators/

Anoop Isaac
fuente
El código no cierra el objeto del archivo, también la respuesta solo enlace no es bienvenida.
aristotll
Esa solución no cubre valores de varias líneas o valores que incluyen un signo igual.
Konstantin Tarashchanskiy
1

puede usar el parámetro "fromfile_prefix_chars" con argparse para leer desde el archivo de configuración como se muestra a continuación ---

temp.py

parser = argparse.ArgumentParser(fromfile_prefix_chars='#')
parser.add_argument('--a')
parser.add_argument('--b')
args = parser.parse_args()
print(args.a)
print(args.b)

archivo de configuración

--a
hello
--b
hello dear

Ejecutar comando

python temp.py "#config"
Agrim Bansal
fuente
0

Hice esto usando ConfigParser de la siguiente manera. El código asume que hay un archivo llamado config.prop en el mismo directorio donde se ubica BaseTest:

config.prop

[CredentialSection]
app.name=MyAppName

BaseTest.py:

import unittest
import ConfigParser

class BaseTest(unittest.TestCase):
    def setUp(self):
        __SECTION = 'CredentialSection'
        config = ConfigParser.ConfigParser()
        config.readfp(open('config.prop'))
        self.__app_name = config.get(__SECTION, 'app.name')

    def test1(self):
        print self.__app_name % This should print: MyAppName
narko
fuente
0

Esto es lo que había escrito para analizar el archivo y configurarlo como variables env que omite los comentarios y las líneas de valor no clave agregaron interruptores para especificar hg: d

  • -h o --ayuda a imprimir el resumen de uso
  • -c Especifica char que identifica el comentario
  • -s Separador entre clave y valor en archivo prop
  • y especifique el archivo de propiedades que debe analizarse, por ejemplo: python EnvParamSet.py -c # -s = env.properties

    import pipes
    import sys , getopt
    import os.path
    
    class Parsing :
    
            def __init__(self , seprator , commentChar , propFile):
            self.seprator = seprator
            self.commentChar = commentChar
            self.propFile  = propFile
    
        def  parseProp(self):
            prop = open(self.propFile,'rU')
            for line in prop :
                if line.startswith(self.commentChar)==False and  line.find(self.seprator) != -1  :
                    keyValue = line.split(self.seprator)
                    key =  keyValue[0].strip() 
                    value = keyValue[1].strip() 
                            print("export  %s=%s" % (str (key),pipes.quote(str(value))))
    
    
    
    
    class EnvParamSet:
    
        def main (argv):
    
            seprator = '='
            comment =  '#'
    
            if len(argv)  is 0:
                print "Please Specify properties file to be parsed "
                sys.exit()
            propFile=argv[-1] 
    
    
            try :
                opts, args = getopt.getopt(argv, "hs:c:f:", ["help", "seprator=","comment=", "file="])
            except getopt.GetoptError,e:
                print str(e)
                print " possible  arguments  -s <key value sperator > -c < comment char >    <file> \n  Try -h or --help "
                sys.exit(2)
    
    
            if os.path.isfile(args[0])==False:
                print "File doesnt exist "
                sys.exit()
    
    
            for opt , arg  in opts :
                if opt in ("-h" , "--help"):
                    print " hg:d  \n -h or --help print usage summary \n -c Specify char that idetifes comment  \n -s Sperator between key and value in prop file \n  specify file  "
                    sys.exit()
                elif opt in ("-s" , "--seprator"):
                    seprator = arg 
                elif opt in ("-c"  , "--comment"):
                    comment  = arg
    
            p = Parsing( seprator, comment , propFile)
            p.parseProp()
    
        if __name__ == "__main__":
                main(sys.argv[1:])
patel
fuente
0

Lightbend ha lanzado la biblioteca de configuración Typesafe , que analiza los archivos de propiedades y también algunas extensiones basadas en JSON. La biblioteca de Lightbend es solo para JVM, pero parece ser ampliamente adoptada y ahora hay puertos en muchos idiomas, incluido Python: https://github.com/chimpler/pyhocon

DGrady
fuente
0

Puede usar la siguiente función, que es el código modificado de @mvallebr. Respeta los comentarios del archivo de propiedades, ignora las nuevas líneas vacías y permite recuperar un solo valor clave.

def getProperties(propertiesFile ="/home/memin/.config/customMemin/conf.properties", key=''):
    """
    Reads a .properties file and returns the key value pairs as dictionary.
    if key value is specified, then it will return its value alone.
    """
    with open(propertiesFile) as f:
        l = [line.strip().split("=") for line in f.readlines() if not line.startswith('#') and line.strip()]
        d = {key.strip(): value.strip() for key, value in l}

        if key:
            return d[key]
        else:
            return d
Memin
fuente
0

esto funciona para mi

from pyjavaproperties import Properties
p = Properties()
p.load(open('test.properties'))
p.list()
print p
print p.items()
print p['name3']
Andy Quiroz
fuente
Elimina esta publicación duplicada. por cierto, voté por el otro;)
javadba
0

Seguí el enfoque de configparser y funcionó bastante bien para mí. Creé un archivo PropertyReader y usé el analizador de configuración allí para preparar la propiedad correspondiente a cada sección.

** Utiliza Python 2.7

Contenido del archivo PropertyReader.py:

#!/usr/bin/python
import ConfigParser

class PropertyReader:

def readProperty(self, strSection, strKey):
    config = ConfigParser.RawConfigParser()
    config.read('ConfigFile.properties')
    strValue = config.get(strSection,strKey);
    print "Value captured for "+strKey+" :"+strValue
    return strValue

Contenido del archivo de esquema de lectura:

from PropertyReader import *

class ReadSchema:

print PropertyReader().readProperty('source1_section','source_name1')
print PropertyReader().readProperty('source2_section','sn2_sc1_tb')

Contenido del archivo .properties:

[source1_section]
source_name1:module1
sn1_schema:schema1,schema2,schema3
sn1_sc1_tb:employee,department,location
sn1_sc2_tb:student,college,country

[source2_section]
source_name1:module2
sn2_schema:schema4,schema5,schema6
sn2_sc1_tb:employee,department,location
sn2_sc2_tb:student,college,country
Vaibhav Shukla
fuente
Este es un archivo ini, el archivo de propiedades no tendrá encabezados de sección
Akshay
0

cree un diccionario en su módulo python y almacene todo en él y acceda a él, por ejemplo:

dict = {
       'portalPath' : 'www.xyx.com',
       'elementID': 'submit'}

Ahora para acceder a él simplemente puede hacer:

submitButton = driver.find_element_by_id(dict['elementID'])
Vineet Singh
fuente
1
Se recomienda encarecidamente compartir algunos ejemplos de código. Por ahora su respuesta es muy pobre
Nikolai Shevchenko
@NikolayShevchenko lo siento por un formato deficiente, he actualizado mi respuesta
Vineet Singh