155

Given the following format (.properties or .ini):

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

For Java there is the Properties class that offers functionality to parse / interact with the above format.

Is there something similar in python's standard library (2.x) ?

If not, what other alternatives do I have ?

Eduard Florinescu
  • 16,747
  • 28
  • 113
  • 179
Andrei Ciobanu
  • 12,500
  • 24
  • 85
  • 118

27 Answers27

96

I was able to get this to work with ConfigParser, no one showed any examples on how to do this, so here is a simple python reader of a property file and example of the property file. Note that the extension is still .properties, but I had to add a section header similar to what you see in .ini files... a bit of a bastardization, but it works.

The python file: PythonPropertyReader.py

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

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

The property file: ConfigFile.properties

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

For more functionality, read: https://docs.python.org/2/library/configparser.html

James Oravec
  • 19,579
  • 27
  • 94
  • 160
  • 17
    The ConfigParser module has been renamed to configparser in Python 3. – Gursewak Singh Mar 26 '19 at 06:42
  • 7
    This is for .ini files, not .properties files as they do not contain sections, and configParser fails if it doesn't find any section header. Moreover, ini files may not include sections so this configParser doesn't seem reliable at all – BiAiB Jul 17 '20 at 09:27
76

I know that this is a very old question, but I need it just now and I decided to implement my own solution, a pure python solution, that covers most uses cases (not all):

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

You can change the sep to ':' to parse files with format:

key : value

The code parses correctly lines like:

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

You'll get a dict with:

{"url": "http://my-host.com", "name": "Paul = Pablo" }
Roberto
  • 8,586
  • 3
  • 42
  • 53
  • 1
    Top notch solution and is exactly what I was looking for! – Russell Aug 23 '16 at 14:58
  • Note that this doesn't support comments on the same line as the entries like `foo = "bar" # bat`. – ThomasW Aug 09 '17 at 04:50
  • 1
    @ThomasW If we're using Java as the de-facto standard, Properties#load will treat that as a property `foo` with value `"bar" # bat`. – bonh Jul 28 '19 at 01:47
  • 1
    You thought what's the point in posting answer to an old question? The point is I was able to save time by just copy paste this, in one of my azure pipeline rather than implementing it myself. so thanks :) – old-monk Jan 28 '20 at 20:20
  • 1
    Love the answer! The only change I made to handle inline comments was to change `l = line.strip()` to `l = line.split(comment_char)[0].strip()` and then only check if `l` has a value rather on the subsequent line with `if l:`. – Ben Dalling Apr 22 '20 at 10:28
  • It's not so simple, for instance, this case will fail: `my.key = "text with # inside" # This is an example` – Roberto Apr 22 '20 at 10:36
  • +1 Ignoring those fancy inline comments, it could be simplified with `key_value = l.split(sep, 1)` and then `value = key_value[1].strip().strip('"')`. – Clerenz Dec 21 '20 at 09:25
76

For .ini files there is the configparser module that provides a format compatible with .ini files.

Anyway there's nothing available for parsing complete .properties files, when I have to do that I simply use jython (I'm talking about scripting).

Neuron
  • 5,141
  • 5
  • 38
  • 59
pygabriel
  • 9,840
  • 4
  • 41
  • 54
  • 11
    pyjavaproperties seems to be an option if you don't want to use Jython: https://bitbucket.org/jnoller/pyjavaproperties – Hans-Christoph Steiner Nov 16 '11 at 19:46
  • 2
    the java properties file is not equivalent to .ini file. pyjavaproperties is the right answer – igni Dec 01 '14 at 19:51
  • 2
    Alex Matelli suggested a easy way to parse .properties files with ConfigParser here http://stackoverflow.com/a/2819788/15274 – pi. Apr 16 '15 at 16:38
  • bitbucket.org/jnoller/pyjavaproperties hasn't been maintained since 2010. It is not compatible with python 3. I would use the solutions linked to by @pi. – codyzu Sep 02 '15 at 11:47
  • Since nowhere here it is mentioned, let me add again that this is not the same. I cant speak for Java or Py3, and maybe it works for simple key/values. But the syntax for string interpolation is different. This solution provides Python formatting, ie. %(string)s while (for e.g. Ant) I would use ${string}. https://pymotw.com/2/ConfigParser/ – mpe Dec 21 '16 at 18:55
  • get we code, please? – john k Dec 22 '21 at 17:18
66

A java properties file is often valid python code as well. You could rename your myconfig.properties file to myconfig.py. Then just import your file, like this

import myconfig

and access the properties directly

print myconfig.propertyName1
Travis Bear
  • 13,039
  • 7
  • 42
  • 51
  • 1
    Not a bad idea.. should be `import myconfig` though, without the `.py` – armandino Nov 28 '11 at 19:46
  • 14
    I like the idea, but it does not work for properties that contain dots, i.e. `prop.name="val"` is not going to work in this case. – maxjakob Apr 23 '12 at 14:38
  • 40
    `A java properties file is valid python code`: I have to differ. *Some* Java properties files will pass for valid python code, but certainly not all. As @mmjj said dots are a problem. So are unquoted literal strings. -1. – Manoj Govindan May 02 '12 at 12:45
  • 25
    A Rather Bad Idea... since it is broken. Java prop files allow ":" instead of "="; they eat whitespace after line-continuations; they don't quote strings. None of that is "valid Python". – Dan H May 11 '12 at 20:03
  • 2
    Java properties files are in general not going to pass for valid python code. One alternative is to just set your properties in a python file, and use valid python (e.g: MEDIA_ROOT='/foo') ... – danbgray May 11 '12 at 21:19
  • Properties files do not include quotes around values, so the two syntaxes are incompatible. If you just need a simple config file for Python, then yes you can use Python syntax where in Java you would use a .properties, but if you need to parse a Java-compatible file, this will not work. – Matt Good Aug 17 '15 at 20:13
  • 3
    This is a hack best avoided. You're going to have a bad day when you're properties change and the file is no longer valid python. – r_2 May 30 '17 at 18:40
  • 1
    This is a really bad idea - it is a big secutiry flaw. A property file containing malicious code could cause unforeseen consequences. – mvallebr Jul 10 '18 at 10:37
  • 1
    This is a really bad idea, as @DanH mentioned - properties are definitely not valid Python code, and this is a HUGE security vulnerability if these property files are coming from an external source, or if users are allowed to modify them – Boris Chervenkov Oct 06 '20 at 18:21
19

if you don't have multi line properties and a very simple need, a few lines of code can solve it for you:

File 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}
mvallebr
  • 2,388
  • 21
  • 36
17

If you have an option of file formats I suggest using .ini and Python's ConfigParser as mentioned. If you need compatibility with Java .properties files I have written a library for it called jprops. We were using pyjavaproperties, but after encountering various limitations I ended up implementing my own. It has full support for the .properties format, including unicode support and better support for escape sequences. Jprops can also parse any file-like object while pyjavaproperties only works with real files on disk.

Fabio Zadrozny
  • 24,814
  • 4
  • 66
  • 78
Matt Good
  • 3,027
  • 22
  • 15
  • 1
    I just gave this a try. Works like a charm. +1 for MattGood! – Dan H May 11 '12 at 20:05
  • 1
    if you add pip install and a code example your answer will be even better pip install jprops, with open(path) as fp: properties = jprops.load_properties(fp) print(properties) – Rubber Duck Jul 09 '18 at 07:32
6

This is not exactly properties but Python does have a nice library for parsing configuration files. Also see this recipe: A python replacement for java.util.Properties.

Manoj Govindan
  • 72,339
  • 21
  • 134
  • 141
  • 1
    For the second link...This is no longer developed actively. Jesse noller has created a project from this recipe with some fixes not available here. Author recommends that project to anyone using this recipe. http://pypi.python.org/pypi/pyjavaproperties – Big Al Feb 21 '14 at 20:02
6

i have used this, this library is very useful

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
  • 833
  • 7
  • 8
4

Here is link to my project: https://sourceforge.net/projects/pyproperties/. It is a library with methods for working with *.properties files for Python 3.x.

But it is not based on java.util.Properties

marekjm
  • 41
  • 1
3

If you need to read all values from a section in properties file in a simple manner:

Your config.properties file layout :

[SECTION_NAME]  
key1 = value1  
key2 = value2  

You code:

   import configparser

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

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

This will give you a dictionary where keys are same as in config file and their corresponding values.

details_dict is :

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

Now to get key1's value : details_dict['key1']

Putting it all in a method which reads that section from config file only once(the first time the method is called during a program run).

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

Now call the above function and get the required key's value :

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

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

Extending the approach mentioned above, reading section by section automatically and then accessing by section name followed by key name.

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

To access:

config_dict = get_config_section()

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

(here 'DB' is a section name in config file and 'port' is a key under section 'DB'.)

MANU
  • 1,358
  • 1
  • 16
  • 29
3

You can use a file-like object in ConfigParser.RawConfigParser.readfp defined here -> https://docs.python.org/2/library/configparser.html#ConfigParser.RawConfigParser.readfp

Define a class that overrides readline that adds a section name before the actual contents of your properties file.

I've packaged it into the class that returns a dict of all the properties defined.

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
  • 44,836
  • 10
  • 105
  • 121
3

create a dictionary in your python module and store everything into it and access it, for example:

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

Now to access it you can simply do:

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

My Java ini files didn't have section headers and I wanted a dict as a result. So i simply injected an "[ini]" section and let the default config library do its job.

Take a version.ini fie of the eclipse IDE .metadata directory as an example:

#Mon Dec 20 07:35:29 CET 2021
org.eclipse.core.runtime=2
org.eclipse.platform=4.19.0.v20210303-1800
# 'injected' ini section
[ini]
#Mon Dec 20 07:35:29 CET 2021
org.eclipse.core.runtime=2
org.eclipse.platform=4.19.0.v20210303-1800

The result is converted to a dict:

from configparser import ConfigParser

@staticmethod
    def readPropertyFile(path):
        # https://stackoverflow.com/questions/3595363/properties-file-in-python-similar-to-java-properties
        config = ConfigParser()
        s_config= open(path, 'r').read()
        s_config="[ini]\n%s" % s_config
        # https://stackoverflow.com/a/36841741/1497139
        config.read_string(s_config)
        items=config.items('ini')
        itemDict={}
        for key,value in items:
            itemDict[key]=value
        return itemDict
Wolfgang Fahl
  • 15,016
  • 11
  • 93
  • 186
3

This is a one-to-one replacement of java.util.Propeties

From the doc:

  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
  • 207
  • 2
  • 13
2

This is what I'm doing in my project: I just create another .py file called properties.py which includes all common variables/properties I used in the project, and in any file need to refer to these variables, put

from properties import *(or anything you need)

Used this method to keep svn peace when I was changing dev locations frequently and some common variables were quite relative to local environment. Works fine for me but not sure this method would be suggested for formal dev environment etc.

festony
  • 71
  • 6
2

I have created a python module that is almost similar to the Properties class of Java ( Actually it is like the PropertyPlaceholderConfigurer in spring which lets you use ${variable-reference} to refer to already defined property )

EDIT : You may install this package by running the command(currently tested for python 3).
pip install property

The project is hosted on GitHub

Example : ( Detailed documentation can be found here )

Let's say you have the following properties defined in my_file.properties file

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

Code to load the above properties

from properties.p import Property

prop = Property()
# Simply load it into a dictionary
dic_prop = prop.load_property_files('my_file.properties')
Anand Joshi
  • 91
  • 1
  • 3
  • Let's say you have the following properties defined in my_file.properties file foo = I am awesome bar = ${chocolate}-bar chocolate = fudge Code to load the above properties prop = Property() prop.load('path/to/my_file.properties') prop.get('foo') # I am awesome prop.get('bar') # fudge-bar – Anand Joshi May 28 '16 at 19:04
  • Done . Hope it helps – Anand Joshi May 28 '16 at 19:17
2
import json
f=open('test.json')
x=json.load(f)
f.close()
print(x)

Contents of test.json: {"host": "127.0.0.1", "user": "jms"}

1

Below 2 lines of code shows how to use Python List Comprehension to load 'java style' property file.

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

Please have a look at below post for details https://ilearnonlinesite.wordpress.com/2017/07/24/reading-property-file-in-python-using-comprehension-and-generators/

Anoop Isaac
  • 932
  • 12
  • 15
1

you can use parameter "fromfile_prefix_chars" with argparse to read from config file as below---

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)

config file

--a
hello
--b
hello dear

Run command

python temp.py "#config"
Jeremy Caney
  • 7,102
  • 69
  • 48
  • 77
1

You could use - https://pypi.org/project/property/

eg - my_file.properties

foo = I am awesome
bar = ${chocolate}-bar
chocolate = fudge
long = a very long property that is described in the property file which takes up \
multiple lines can be defined by the escape character as it is done here
url=example.com/api?auth_token=xyz
user_dir=${HOME}/test
unresolved = ${HOME}/files/${id}/${bar}/
fname_template = /opt/myapp/{arch}/ext/{objid}.dat

Code

from properties.p import Property


## set use_env to evaluate properties from shell / os environment
prop = Property(use_env = True)
dic_prop = prop.load_property_files('my_file.properties')

## Read multiple files
## dic_prop = prop.load_property_files('file1', 'file2')


print(dic_prop)

# Output

# {'foo': 'I am awesome', 'bar': 'fudge-bar', 'chocolate': 'fudge',
#  'long': 'a very long property that is described in the property file which takes up multiple lines
#  can be defined by the escape character as it is done here', 'url': 'example.com/api?auth_token=xyz',
#  'user_dir': '/home/user/test',
#  'unresolved': '/home/user/files/${id}/fudge-bar/',
#  'fname_template': '/opt/myapp/{arch}/ext/{objid}.dat'}
0

I did this using ConfigParser as follows. The code assumes that there is a file called config.prop in the same directory where BaseTest is placed:

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
  • 3,645
  • 1
  • 28
  • 33
0

This is what i had written to parse file and set it as env variables which skips comments and non key value lines added switches to specify hg:d

  • -h or --help print usage summary
  • -c Specify char that identifies comment
  • -s Separator between key and value in prop file
  • and specify properties file that needs to be parsed eg : 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
  • 186
  • 9
0

Lightbend has released the Typesafe Config library, which parses properties files and also some JSON-based extensions. Lightbend's library is only for the JVM, but it seems to be widely adopted and there are now ports in many languages, including Python: https://github.com/chimpler/pyhocon

DGrady
  • 1,065
  • 1
  • 13
  • 23
0

You can use the following function, which is the modified code of @mvallebr. It respects the properties file comments, ignores empty new lines, and allows retrieving a single key value.

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
  • 3,788
  • 30
  • 31
0

this works for me.

from pyjavaproperties import Properties
p = Properties()
p.load(open('test.properties'))
p.list()
print p
print p.items()
print p['name3']
Andy Quiroz
  • 833
  • 7
  • 8
0

I followed configparser approach and it worked quite well for me. Created one PropertyReader file and used config parser there to ready property to corresponding to each section.

**Used Python 2.7

Content of PropertyReader.py file:

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

Content of read schema file:

from PropertyReader import *

class ReadSchema:

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

Content of .properties file:

[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
  • 1
    This is an ini file, properties file will not have no section headers – Akshay Apr 01 '19 at 05:55
  • doesnt seem to work with python 3? I get `AttributeError: type object 'ConfigParser' has no attribute 'RawConfigParser'` – john k Dec 22 '21 at 17:27
0

You can try the python-dotenv library. This library reads key-value pairs from a .env (so not exactly a .properties file though) file and can set them as environment variables.

Here's a sample usage from the official documentation:

from dotenv import load_dotenv

load_dotenv()  # take environment variables from .env.

# Code of your application, which uses environment variables (e.g. from `os.environ` or
# `os.getenv`) as if they came from the actual environment.
Saikat
  • 14,222
  • 20
  • 104
  • 125