Eigenschaftendatei in Python (ähnlich wie Java Properties)


137

Bei folgendem Format ( .properties oder .ini ):

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

Für Java gibt es die Properties- Klasse, die Funktionen zum Parsen / Interagieren mit dem obigen Format bietet.

Gibt es etwas ähnliches in Python ‚s Standard - Bibliothek (2.x)?

Wenn nicht, welche anderen Alternativen habe ich?


5
Dies ist keine Java-Frage. Warum haben Sie das Entfernen von Java-Tags rückgängig gemacht?
BalusC

Antworten:


69

Für INI-Dateien gibt es die ConfigParser- Modul, das ein mit INI-Dateien kompatibles Format bereitstellt.

Auf jeden Fall ist nichts zum Parsen vollständiger .properties-Dateien verfügbar. Wenn ich das tun muss, verwende ich einfach Jython (ich spreche von Skripten).


10
pyjavaproperties scheint eine Option zu sein, wenn Sie Jython nicht verwenden möchten: bitbucket.org/jnoller/pyjavaproperties
Hans-Christoph Steiner

2
Die Java-Eigenschaftendatei entspricht nicht der INI-Datei. pyjavaproperties ist die richtige Antwort
igni

2
Alex Matelli schlug eine einfache Möglichkeit vor, .properties-Dateien mit ConfigParser hier zu analysieren
.

bitbucket.org/jnoller/pyjavaproperties wurde seit 2010 nicht mehr gepflegt. Es ist nicht kompatibel mit Python 3. Ich würde die von @pi verknüpften Lösungen verwenden.
Codyzu

Da hier nirgends erwähnt wird, möchte ich noch einmal hinzufügen, dass dies nicht dasselbe ist. Ich kann nicht für Java oder Py3 sprechen, und vielleicht funktioniert es für einfache Schlüssel / Werte. Die Syntax für die String-Interpolation ist jedoch unterschiedlich. Diese Lösung bietet Python-Formatierung, dh. % (string) s while (für zB Ant) würde ich $ {string} verwenden. pymotw.com/2/ConfigParser
mpe

74

Ich konnte dies zum Laufen bringen ConfigParser, niemand zeigte Beispiele dafür, also hier ein einfacher Python-Reader einer Eigenschaftendatei und ein Beispiel der Eigenschaftendatei. Beachten Sie, dass die Erweiterung immer noch vorhanden ist .properties, aber ich musste einen Abschnittsheader hinzufügen, der dem ähnelt, was Sie in INI-Dateien sehen ... ein bisschen bastardisiert, aber es funktioniert.

Die Python-Datei: PythonPropertyReader.py

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

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

Die Eigenschaftendatei: ConfigFile.properties

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

Weitere Funktionen finden Sie unter: https://docs.python.org/2/library/configparser.html


5
Das ConfigParser-Modul wurde in Python 3 in configparser umbenannt.
Gursewak Singh

Dies gilt für INI-Dateien, nicht für .properties-Dateien, da diese keine Abschnitte enthalten. ConfigParser schlägt fehl, wenn kein Abschnittsheader gefunden wird. Darüber hinaus enthalten INI-Dateien möglicherweise keine Abschnitte, sodass dieser configParser überhaupt nicht zuverlässig zu sein scheint
BiAiB

65

Eine Java-Eigenschaftendatei ist häufig auch ein gültiger Python-Code. Sie können Ihre Datei myconfig.properties in myconfig.py umbenennen. Dann importieren Sie einfach Ihre Datei wie folgt

import myconfig

und greifen Sie direkt auf die Eigenschaften zu

print myconfig.propertyName1

11
Ich mag die Idee, aber sie funktioniert nicht für Eigenschaften, die Punkte enthalten, dh sie prop.name="val"wird in diesem Fall nicht funktionieren.
Maxjakob

36
A java properties file is valid python code: Ich muss mich unterscheiden. Einige Java-Eigenschaftendateien werden als gültiger Python-Code übergeben, aber sicherlich nicht alle. Wie @mmjj sagte, sind Punkte ein Problem. So sind nicht zitierte wörtliche Zeichenfolgen. -1.
Manoj Govindan

24
Eine ziemlich schlechte Idee ... da sie kaputt ist. Java-Requisitendateien erlauben ":" anstelle von "="; sie essen Leerzeichen nach Zeilenfortsetzungen; Sie zitieren keine Zeichenfolgen. Nichts davon ist "gültiges Python".
Dan H

2
Java-Eigenschaftendateien werden im Allgemeinen nicht als gültiger Python-Code übergeben. Eine Alternative besteht darin, Ihre Eigenschaften einfach in einer Python-Datei festzulegen und eine gültige Python-Datei zu verwenden (z. B.: MEDIA_ROOT = '/ foo') ...
danbgray

3
Dies ist ein Hack, der am besten vermieden wird. Sie werden einen schlechten Tag haben, wenn sich Ihre Eigenschaften ändern und die Datei kein gültiges Python mehr ist.
r_2

59

Ich weiß, dass dies eine sehr alte Frage ist, aber ich brauche sie gerade und habe beschlossen, meine eigene Lösung zu implementieren, eine reine Python-Lösung, die die meisten Anwendungsfälle abdeckt (nicht alle):

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

Sie können das sepin ':' ändern , um Dateien mit folgendem Format zu analysieren:

key : value

Der Code analysiert Zeilen wie folgt korrekt:

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

Sie erhalten ein Diktat mit:

{"url": "http://my-host.com", "name": "Paul = Pablo" }

1
Erstklassige Lösung und genau das, wonach ich gesucht habe!
Russell

Beachten Sie, dass dies keine Kommentare in derselben Zeile wie die Einträge unterstützt foo = "bar" # bat.
ThomasW

1
@ThomasW Wenn wir Java als De-facto-Standard verwenden, behandelt Properties # load dies als eine Eigenschaft foomit Wert "bar" # bat.
Bonh

1
Sie dachten, was bringt es, eine alte Frage zu beantworten? Der Punkt ist, dass ich Zeit sparen konnte, indem ich dies einfach kopierte und in eine meiner Azure-Pipelines einfügte, anstatt es selbst zu implementieren. also danke :)
alter Mönch

1
Ich liebe die Antwort! Die einzige Änderung ich Inline - Kommentare zu handhaben gemacht wurde ändern l = line.strip()zu l = line.split(comment_char)[0].strip()und dann nur prüfen , ob lein Wert eher auf der nachfolgenden Zeile mit if l:.
Ben Dalling

17

Wenn Sie eine Option für Dateiformate haben, empfehle ich die Verwendung von .ini und Pythons ConfigParser wie erwähnt. Wenn Sie Kompatibilität mit Java .properties-Dateien benötigen, habe ich eine Bibliothek namens jprops dafür geschrieben . Wir haben Pyjavaproperties verwendet, aber nachdem ich auf verschiedene Einschränkungen gestoßen war, habe ich meine eigenen implementiert. Es bietet volle Unterstützung für das .properties-Format, einschließlich Unicode-Unterstützung und besserer Unterstützung für Escape-Sequenzen. Jprops kann auch jedes dateiähnliche Objekt analysieren, während pyjavaproperties nur mit echten Dateien auf der Festplatte funktioniert.


1
Ich habe es gerade versucht. Klappt wunderbar. +1 für MattGood!
Dan H

1
Wenn Sie pip install und ein Codebeispiel hinzufügen, ist Ihre Antwort noch besser pip install jprops, mit open (Pfad) als fp: properties = jprops.load_properties (fp) print (properties)
Rubber Duck

10

Wenn Sie keine mehrzeiligen Eigenschaften und einen sehr einfachen Bedarf haben, können einige Codezeilen dies für Sie lösen:

Datei t.properties:

a=b
c=d
e=f

Python-Code:

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

6

Dies sind nicht gerade Eigenschaften, aber Python verfügt über eine schöne Bibliothek zum Parsen von Konfigurationsdateien. Siehe auch dieses Rezept: Ein Python-Ersatz für java.util.Properties .


1
Für den zweiten Link ... Dies wird nicht mehr aktiv entwickelt. Jesse Noller hat aus diesem Rezept ein Projekt mit einigen Korrekturen erstellt, die hier nicht verfügbar sind. Der Autor empfiehlt dieses Projekt jedem, der dieses Rezept verwendet. pypi.python.org/pypi/pyjavaproperties
Big Al


3

Dies ist eine Eins-zu-Eins-Ersetzung von java.util.Propeties

Aus dem Dokument:

  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.

3

Sie können ein dateiähnliches Objekt verwenden, ConfigParser.RawConfigParser.readfpdas hier definiert ist -> https://docs.python.org/2/library/configparser.html#ConfigParser.RawConfigParser.readfp

Definieren Sie eine Klasse, die überschreibt readline einen Abschnittsnamen vor dem eigentlichen Inhalt Ihrer Eigenschaftendatei hinzufügt.

Ich habe es in die Klasse gepackt, die eine dictder definierten Eigenschaften zurückgibt .

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()

3

Ich habe dies verwendet, diese Bibliothek ist sehr nützlich

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'

2

Dies ist, was ich in meinem Projekt mache: Ich erstelle einfach eine andere .py-Datei namens properties.py, die alle allgemeinen Variablen / Eigenschaften enthält, die ich im Projekt verwendet habe, und in jeder Datei muss auf diese Variablen verwiesen werden

from properties import *(or anything you need)

Verwendete diese Methode, um svn-Frieden zu bewahren, wenn ich häufig die Entwicklungsstandorte wechselte und einige allgemeine Variablen relativ zur lokalen Umgebung waren. Funktioniert gut für mich, ist sich aber nicht sicher, ob diese Methode für formale Entwicklungsumgebungen usw. vorgeschlagen wird.


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

Inhalt von test.json: {"host": "127.0.0.1", "user": "jms"}


2

Ich habe ein Python-Modul erstellt, das der Properties-Klasse von Java fast ähnlich ist (tatsächlich ähnelt es dem PropertyPlaceholderConfigurer im Frühjahr, mit dem Sie $ {variable-reference} verwenden können, um auf bereits definierte Eigenschaften zu verweisen).

BEARBEITEN: Sie können dieses Paket installieren, indem Sie den Befehl ausführen (derzeit für Python 3 getestet).
pip install property

Das Projekt wird am gehostet GitHub gehostet

Beispiel: (Detaillierte Dokumentation finden Sie hier )

Angenommen, Sie haben die folgenden Eigenschaften in der Datei my_file.properties definiert

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

Code zum Laden der oben genannten Eigenschaften

from properties.p import Property

prop = Property()
# Simply load it into a dictionary
dic_prop = prop.load_property_files('my_file.properties')

Angenommen, Sie haben die folgenden Eigenschaften in der Datei my_file.properties definiert. Foo = Ich bin großartig .properties ') prop.get (' foo ') # Ich bin großartig prop.get (' bar ') # fudge-bar
Anand Joshi

Getan . Hoffe es hilft
Anand Joshi

2

Wenn Sie alle Werte aus einem Abschnitt in der Eigenschaftendatei auf einfache Weise lesen müssen:

Ihr config.propertiesDateilayout:

[SECTION_NAME]  
key1 = value1  
key2 = value2  

Sie codieren:

   import configparser

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

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

Dadurch erhalten Sie ein Wörterbuch, in dem die Schlüssel mit den Konfigurationsdateien und den entsprechenden Werten identisch sind.

details_dict ist:

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

Um nun den Wert von key1 zu erhalten: details_dict['key1']

Fügen Sie alles in eine Methode ein, die diesen Abschnitt nur einmal aus der Konfigurationsdatei liest (das erste Mal, wenn die Methode während eines Programmlaufs aufgerufen wird).

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

Rufen Sie nun die obige Funktion auf und erhalten Sie den Wert des gewünschten Schlüssels:

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

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

Erweitern Sie den oben genannten Ansatz, lesen Sie Abschnitt für Abschnitt automatisch und greifen Sie dann auf den Abschnittsnamen gefolgt vom Schlüsselnamen zu.

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

Zugreifen:

config_dict = get_config_section()

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

(Hier ist 'DB' ein Abschnittsname in der Konfigurationsdatei und 'Port' ist ein Schlüssel unter Abschnitt 'DB'.)


1

Die folgenden 2 Codezeilen zeigen, wie Sie mit Python List Comprehension die Eigenschaftendatei 'Java Style' laden.

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

Weitere Informationen finden Sie im folgenden Beitrag. Https://ilearnonlinesite.wordpress.com/2017/07/24/reading-property-file-in-python-using-comprehension-and-generators/


Der Code schließt das Dateiobjekt nicht, auch eine Antwort nur mit Link ist nicht erwünscht.
Aristotll

Diese Lösung deckt keine mehrzeiligen Werte oder Werte ab, die ein Gleichheitszeichen enthalten.
Konstantin Tarashchanskiy

1

Sie können den Parameter "fromfile_prefix_chars" mit argparse verwenden, um wie folgt aus der Konfigurationsdatei zu lesen ---

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)

Konfigurationsdatei

--a
hello
--b
hello dear

Führen Sie den Befehl aus

python temp.py "#config"

0

Ich habe dies mit ConfigParser wie folgt gemacht. Der Code setzt voraus, dass sich eine Datei mit dem Namen config.prop in demselben Verzeichnis befindet, in dem sich BaseTest befindet:

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

0

Dies ist, was ich geschrieben hatte, um die Datei zu analysieren und als env-Variablen festzulegen, die Kommentare überspringen und Schalter ohne Schlüsselwerte hinzufügen, um hg: d anzugeben

  • -h oder --help Zusammenfassung der Drucknutzung
  • -c Geben Sie ein Zeichen an, das den Kommentar identifiziert
  • -s Trennzeichen zwischen Schlüssel und Wert in der Requisitendatei
  • und geben Sie die Eigenschaftendatei an, die analysiert werden muss, z. B.: 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:])

0

Lightbend hat die Typesafe Config- Bibliothek veröffentlicht, die Eigenschaftendateien und einige JSON-basierte Erweiterungen analysiert. Die Bibliothek von Lightbend ist nur für die JVM gedacht, scheint jedoch weit verbreitet zu sein, und es gibt jetzt Ports in vielen Sprachen, einschließlich Python: https://github.com/chimpler/pyhocon


0

Sie können die folgende Funktion verwenden, bei der es sich um den geänderten Code von @mvallebr handelt. Es berücksichtigt die Kommentare der Eigenschaftendatei, ignoriert leere neue Zeilen und ermöglicht das Abrufen eines einzelnen Schlüsselwerts.

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

0

das funktioniert bei mir.

from pyjavaproperties import Properties
p = Properties()
p.load(open('test.properties'))
p.list()
print p
print p.items()
print p['name3']

Bitte entfernen Sie diese doppelte Veröffentlichung. Übrigens habe ich deine andere positiv bewertet;)
javadba

0

Ich folgte dem Configparser-Ansatz und es funktionierte ziemlich gut für mich. Erstellt eine PropertyReader-Datei und verwendet dort den Konfigurationsparser, um die Eigenschaft für jeden Abschnitt vorzubereiten.

** Verwendetes Python 2.7

Inhalt der PropertyReader.py-Datei:

#!/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

Inhalt der gelesenen Schemadatei:

from PropertyReader import *

class ReadSchema:

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

Inhalt der .properties-Datei:

[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

Dies ist eine INI-Datei, Eigenschaftendatei hat keine Abschnittsüberschriften
Akshay

0

Erstellen Sie ein Wörterbuch in Ihrem Python-Modul, speichern Sie alles darin und greifen Sie darauf zu, zum Beispiel:

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

Um darauf zuzugreifen, können Sie einfach Folgendes tun:

submitButton = driver.find_element_by_id(dict['elementID'])

1
Es wird dringend empfohlen, ein Codebeispiel zu teilen. Im Moment ist Ihre Antwort sehr schlecht
Nikolai Shevchenko

@ NikolayShevchenko Entschuldigung für die schlechte Formatierung, ich habe meine Antwort aktualisiert
Vineet Singh
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.