Plik Properties w Pythonie (podobny do Java Properties)


137

Biorąc pod uwagę następujący format ( .properties lub .ini ):

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

W przypadku języka Java istnieje klasa Właściwości, która oferuje funkcje analizowania / interakcji z powyższym formatem.

Czy jest coś podobnego w python „s standardowej biblioteki (2.x)?

Jeśli nie, jakie mam inne alternatywy?


5
To nie jest pytanie dotyczące języka Java. Dlaczego wycofałeś usuwanie tagu Java?
BalusC

Odpowiedzi:


69

W przypadku plików .ini istnieje moduł ConfigParser , który zapewnia format zgodny z plikami .ini.

W każdym razie nie ma nic do parsowania kompletnych plików .properties, kiedy muszę to zrobić, po prostu używam jythona (mówię o skryptach).


10
pyjavaproperties wydaje się być opcją, jeśli nie chcesz używać Jythona
Hans-Christoph Steiner

2
plik właściwości java nie jest równoważny z plikiem .ini. pyjavaproperties to właściwa odpowiedź
igni

2
Alex Matelli zasugerował łatwy sposób parsowania plików .properties za pomocą ConfigParser tutaj stackoverflow.com/a/2819788/15274
pi.

bitbucket.org/jnoller/pyjavaproperties nie jest utrzymywany od 2010 roku. Nie jest kompatybilny z pythonem 3. Korzystałbym z rozwiązań, do których link @pi.
codyzu

Ponieważ nigdzie o tym nie ma, dodam jeszcze raz, że to nie to samo. Nie mogę mówić w języku Java ani Py3 i może to działa dla prostych kluczy / wartości. Ale składnia interpolacji ciągów jest inna. To rozwiązanie zapewnia formatowanie Pythona, tj. % (string) s, podczas gdy (np. Ant) użyłbym $ {string}. pymotw.com/2/ConfigParser
mpe

74

Udało mi się to wykorzystać ConfigParser, nikt nie pokazał żadnych przykładów, jak to zrobić, więc tutaj jest prosty czytnik Pythona pliku właściwości i przykład pliku właściwości. Zauważ, że rozszerzenie jest nadal .properties, ale musiałem dodać nagłówek sekcji podobny do tego, co widzisz w plikach .ini ... trochę bastardyzacji, ale działa.

Plik Pythona: PythonPropertyReader.py

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

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

Plik nieruchomości: ConfigFile.properties

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

Aby uzyskać więcej funkcji, przeczytaj: https://docs.python.org/2/library/configparser.html


5
Nazwa modułu ConfigParser została zmieniona na configparser w Pythonie 3.
Gursewak Singh

Dotyczy to plików .ini, a nie plików .properties, ponieważ nie zawierają one sekcji, a parametr configParser kończy się niepowodzeniem, jeśli nie znajdzie żadnego nagłówka sekcji. Co więcej, pliki ini mogą nie zawierać sekcji, więc ten configParser nie wydaje się w ogóle niezawodny
BiAiB

65

Plik właściwości Java jest również często prawidłowym kodem w języku Python. Możesz zmienić nazwę pliku myconfig.properties na myconfig.py. Następnie po prostu zaimportuj plik, w ten sposób

import myconfig

i uzyskać bezpośredni dostęp do właściwości

print myconfig.propertyName1

11
Pomysł mi się podoba, ale nie działa dla właściwości, które zawierają kropki, tj. prop.name="val"Nie będzie działać w tym przypadku.
maxjakob

36
A java properties file is valid python code: Muszę się różnić. Niektóre pliki właściwości Java zostaną przekazane do prawidłowego kodu w języku Python, ale z pewnością nie wszystkie. Jak powiedział @mmjj, kropki są problemem. Tak samo jak niecytowane ciągi literałów. -1.
Manoj Govindan

24
Raczej zły pomysł ... ponieważ jest zepsuty. Pliki właściwości Java pozwalają na „:” zamiast „=”; jedzą białe spacje po kontynuacjach linii; nie cytują łańcuchów. Nic z tego nie jest „prawidłowym Pythonem”.
Dan H

2
Pliki właściwości Java na ogół nie zostaną przekazane do prawidłowego kodu Pythona. Jedną z alternatyw jest po prostu ustawienie swoich właściwości w pliku Pythona i użycie prawidłowego języka Python (np .: MEDIA_ROOT = '/ foo') ...
danbgray

3
To jest hack, którego najlepiej unikać. Będziesz miał zły dzień, gdy zmienią się właściwości i plik nie jest już prawidłowym Pythonem.
r_2

59

Wiem, że to bardzo stare pytanie, ale potrzebuję go właśnie teraz i zdecydowałem się wdrożyć własne rozwiązanie, rozwiązanie w czystym Pythonie, które obejmuje większość przypadków użycia (nie wszystkie):

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

Możesz zmienić na sep„:”, aby analizować pliki w formacie:

key : value

Kod poprawnie analizuje wiersze, takie jak:

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

Otrzymasz dyktando z:

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

1
Rozwiązanie na najwyższym poziomie i jest dokładnie tym, czego szukałem!
Russell

Zauważ, że to nie obsługuje komentarzy w tej samej linii, co wpisy takie jak foo = "bar" # bat.
Thomas W

1
@ThomasW Jeśli używamy Javy jako de facto standardu, Properties # load potraktuje to jako właściwość fooz wartością "bar" # bat.
bonh

1
Pomyślałeś, jaki jest sens w publikowaniu odpowiedzi na stare pytanie? Chodzi o to, że udało mi się zaoszczędzić czas, po prostu skopiuj wklej to, w jednym z moich lazurowych potoków, zamiast wdrażać go samodzielnie. więc dzięki :)
stary-mnich

1
Uwielbiam odpowiedź! Jedyną zmianą, jaką wprowadziłem w obsłudze komentarzy w wierszu, była zmiana l = line.strip()na, l = line.split(comment_char)[0].strip()a następnie sprawdzenie tylko, czy lma wartość, a w kolejnym wierszu z if l:.
Ben Dalling

17

Jeśli masz opcję formatów plików, sugeruję użycie .ini i ConfigParser Pythona, jak wspomniano. Jeśli potrzebujesz kompatybilności z plikami Java .properties, napisałem dla niego bibliotekę o nazwie jprops . Używaliśmy pyjavaproperties, ale po napotkaniu różnych ograniczeń zaimplementowałem własne. Ma pełne wsparcie dla formatu .properties, w tym obsługę Unicode i lepszą obsługę sekwencji ucieczki. Jprops może również analizować dowolny obiekt podobny do pliku, podczas gdy pyjavaproperties działa tylko z prawdziwymi plikami na dysku.


1
Właśnie spróbowałem. Działa jak marzenie. +1 dla MattGood!
Dan H

1
jeśli dodasz pip install i przykład kodu, twoja odpowiedź będzie jeszcze lepsza pip install jprops, z open (path) as fp: properties = jprops.load_properties (fp) print (properties)
Rubber Duck

10

jeśli nie masz właściwości wielowierszowych i jest to bardzo prosta potrzeba, kilka wierszy kodu może rozwiązać ten problem:

Plik t.properties:

a=b
c=d
e=f

Kod Pythona:

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



3

To jest wymiana jeden do jednego java.util.Propeties

Z dokumentu:

  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

Możesz użyć obiektu podobnego do pliku w ConfigParser.RawConfigParser.readfpzdefiniowanym tutaj -> https://docs.python.org/2/library/configparser.html#ConfigParser.RawConfigParser.readfp

Zdefiniuj klasę, która nadpisuje, readlinektóra dodaje nazwę sekcji przed rzeczywistą zawartością pliku właściwości.

Umieściłem go w klasie, która zwraca a dictze wszystkich zdefiniowanych właściwości.

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

Użyłem tego, ta biblioteka jest bardzo przydatna

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

Oto, co robię w moim projekcie: po prostu tworzę kolejny plik .py o nazwie properties.py, który zawiera wszystkie typowe zmienne / właściwości, których użyłem w projekcie, aw każdym pliku muszę odwoływać się do tych zmiennych, umieszczam

from properties import *(or anything you need)

Użyłem tej metody, aby zachować spokój svn, gdy często zmieniałem lokalizacje deweloperów, a niektóre typowe zmienne były dość zależne od lokalnego środowiska. Działa dobrze dla mnie, ale nie jestem pewien, czy ta metoda byłaby sugerowana dla formalnego środowiska programistycznego itp.


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

Zawartość pliku test.json: {"host": "127.0.0.1", "user": "jms"}


2

Stworzyłem moduł Pythona, który jest prawie podobny do klasy Właściwości w Javie (w rzeczywistości jest podobny do PropertyPlaceholderConfigurer wiosną, który pozwala używać $ {zmienna-referencja} do odwoływania się do już zdefiniowanej właściwości)

EDYCJA: Możesz zainstalować ten pakiet, uruchamiając polecenie (obecnie testowane pod kątem Pythona 3).
pip install property

Projekt jest hostowany na GitHub

Przykład: (szczegółową dokumentację można znaleźć tutaj )

Załóżmy, że masz zdefiniowane następujące właściwości w pliku my_file.properties

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

Kod do załadowania powyższych właściwości

from properties.p import Property

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

Załóżmy, że masz następujące właściwości zdefiniowane w pliku my_file.properties foo = Jestem niesamowity bar = $ {czekolada} -bar czekolada = krówka Kod do załadowania powyższych właściwości prop = Property () prop.load ('ścieżka / do / mój_plik .properties ') prop.get (' foo ') # I am super prop.get (' bar ') # fudge-bar
Anand Joshi

Gotowe . Mam nadzieję, że to pomoże
Anand Joshi

2

Jeśli chcesz w prosty sposób odczytać wszystkie wartości z sekcji w pliku właściwości:

config.propertiesUkład Twojego pliku:

[SECTION_NAME]  
key1 = value1  
key2 = value2  

Kodujesz:

   import configparser

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

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

To da ci słownik, w którym klucze są takie same jak w pliku konfiguracyjnym i odpowiadające im wartości.

details_dict jest :

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

Teraz, aby uzyskać wartość klucza1: details_dict['key1']

Umieszczenie tego wszystkiego w metodzie, która wczytuje tę sekcję z pliku konfiguracyjnego tylko raz (przy pierwszym wywołaniu metody podczas wykonywania programu).

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

Teraz wywołaj powyższą funkcję i uzyskaj wartość wymaganego klucza:

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

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

Rozszerzenie powyższego podejścia, automatyczne czytanie sekcji po sekcji, a następnie uzyskiwanie dostępu za pomocą nazwy sekcji, po której następuje nazwa klucza.

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

Mieć dostęp:

config_dict = get_config_section()

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

(tutaj „DB” to nazwa sekcji w pliku konfiguracyjnym, a „port” to klucz w sekcji „DB”).


1

Poniżej 2 wiersze kodu pokazują, jak używać funkcji rozumienia list w języku Python do ładowania pliku właściwości „styl java”.

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

Proszę spojrzeć na poniższy post, aby uzyskać szczegółowe informacje https://ilearnonlinesite.wordpress.com/2017/07/24/reading-property-file-in-python-using-comprehension-and-generators/


Kod nie zamyka obiektu pliku, nie jest też mile widziana odpowiedź z samym dowiązaniem.
aristotll

To rozwiązanie nie obejmuje wartości wielowierszowych ani wartości zawierających znak równości.
Konstantin Tarashchanskiy

1

możesz użyć parametru "fromfile_prefix_chars" z argparse do odczytu z pliku konfiguracyjnego, jak poniżej ---

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)

plik konfiguracyjny

--a
hello
--b
hello dear

Uruchom polecenie

python temp.py "#config"

0

Zrobiłem to za pomocą ConfigParser w następujący sposób. Kod zakłada, że ​​w tym samym katalogu, w którym znajduje się BaseTest, znajduje się plik o nazwie config.prop:

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

To jest to, co napisałem, aby przeanalizować plik i ustawić go jako zmienne env, które pomijają komentarze i dodano przełączniki nie zawierające wartości klucza, aby określić hg: d

  • -h lub --help wyświetla podsumowanie użycia
  • -c Określ znak identyfikujący komentarz
  • -s Separator między kluczem a wartością w pliku prop
  • i określ plik właściwości, który ma zostać przeanalizowany, np .: 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 wydał bibliotekę Typesafe Config , która analizuje pliki właściwości, a także niektóre rozszerzenia oparte na JSON. Biblioteka Lightbend jest przeznaczona tylko dla JVM, ale wydaje się, że jest szeroko stosowana i obecnie istnieją porty w wielu językach, w tym w Pythonie: https://github.com/chimpler/pyhocon


0

Możesz użyć następującej funkcji, która jest zmodyfikowanym kodem @mvallebr. Szanuje komentarze do pliku właściwości, ignoruje puste nowe wiersze i umożliwia pobranie pojedynczej wartości klucza.

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

to działa dla mnie.

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

Usuń ten zduplikowany post. btw zagłosowałem za twoją drugą;)
javadba

0

Podążyłem za podejściem configparser i zadziałało to całkiem dobrze. Utworzono jeden plik PropertyReader i użyłem tam parsera konfiguracji do gotowej właściwości odpowiadającej każdej sekcji.

** Użyto Pythona 2.7

Zawartość pliku 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

Zawartość odczytanego pliku schematu:

from PropertyReader import *

class ReadSchema:

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

Zawartość pliku .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

To jest plik ini, plik właściwości nie będzie zawierał nagłówków sekcji
Akshay

0

utwórz słownik w swoim module Pythona i zapisz wszystko w nim i uzyskaj do niego dostęp, na przykład:

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

Teraz, aby uzyskać do niego dostęp, możesz po prostu zrobić:

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

1
Zdecydowanie zaleca się udostępnienie próbki kodu. Na razie twoja odpowiedź jest bardzo słaba
Nikolai Shevchenko

@NikolayShevchenko przepraszam za złe formatowanie, zaktualizowałem moją odpowiedź
Vineet Singh
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.