#!/usr/bin/env python
#############################################################################
##
# This file is part of Taurus
##
# http://taurus-scada.org
##
# Copyright 2011 CELLS / ALBA Synchrotron, Bellaterra, Spain
##
# Taurus is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
##
# Taurus is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
##
# You should have received a copy of the GNU Lesser General Public License
# along with Taurus. If not, see .
##
#############################################################################
"""
propertyfile.py:
A Python replacement for java.util.Properties class
This is modelled as closely as possible to the Java original.
Adapted from http://code.activestate.com/recipes/496795/
Created - Anand B Pillai
Modified - Tiago Coutinho
"""
from builtins import next
from builtins import object
import sys
import re
import time
__all__ = ["Properties"]
__docformat__ = "restructuredtext"
class Properties(object):
""" A Python replacement for java.util.Properties """
def __init__(self, props=None):
# Note: We don't take a default properties object
# as argument yet
# Dictionary of properties.
self._props = {}
# Dictionary of properties with 'pristine' keys
# This is used for dumping the properties to a file
# using the 'store' method
self._origprops = {}
# Dictionary mapping keys from property
# dictionary to pristine dictionary
self._keymap = {}
self.othercharre = re.compile(r'(?',line
# Means we need to split by space.
first, last = m2.span()
sepidx = first
elif m:
# print 'Other match=>',line
# No matching wspace char found, need
# to split by either '=' or ':'
first, last = m.span()
sepidx = last - 1
# print line[sepidx]
# If the last character is a backslash
# it has to be preceded by a space in which
# case the next line is read as part of the
# same property
while line[-1] == '\\':
# Read next line
nextline = next(i)
nextline = nextline.strip()
lineno += 1
# This line will become part of the value
line = line[:-1] + nextline
# Now split to key,value according to separation char
if sepidx != -1:
key, value = line[:sepidx], line[sepidx + 1:]
else:
key, value = line, ''
self.processPair(key, value)
def processPair(self, key, value):
""" Process a (key, value) pair """
oldkey = key
oldvalue = value
# Create key intelligently
keyparts = self.bspacere.split(key)
# print keyparts
strippable = False
lastpart = keyparts[-1]
if lastpart.find('\\ ') != -1:
keyparts[-1] = lastpart.replace('\\', '')
# If no backspace is found at the end, but empty
# space is found, strip it
elif lastpart and lastpart[-1] == ' ':
strippable = True
key = ''.join(keyparts)
if strippable:
key = key.strip()
oldkey = oldkey.strip()
oldvalue = self.unescape(oldvalue)
value = self.unescape(value)
self._props[key] = value.strip()
# Check if an entry exists in pristine keys
if key in self._keymap:
oldkey = self._keymap.get(key)
self._origprops[oldkey] = oldvalue.strip()
else:
self._origprops[oldkey] = oldvalue.strip()
# Store entry in keymap
self._keymap[key] = oldkey
def escape(self, value):
# Java escapes the '=' and ':' in the value
# string with backslashes in the store method.
# So let us do the same.
newvalue = value.replace(':', '\:')
newvalue = newvalue.replace('=', '\=')
return newvalue
def unescape(self, value):
# Reverse of escape
newvalue = value.replace('\:', ':')
newvalue = newvalue.replace('\=', '=')
return newvalue
def load(self, stream):
""" Load properties from an open file stream """
# For the time being only accept file input streams
if type(stream) is not file:
raise TypeError('Argument should be a file object!')
# Check for the opened mode
if stream.mode != 'r':
raise ValueError('Stream should be opened in read-only mode!')
try:
lines = stream.readlines()
self.__parse(lines)
except IOError as e:
raise
def getProperty(self, key):
""" Return a property for the given key """
return self._props.get(key, '')
def setProperty(self, key, value):
""" Set the property for the given key """
if type(key) is str and type(value) is str:
self.processPair(key, value)
else:
raise TypeError('both key and value should be strings!')
def propertyNames(self):
""" Return an iterator over all the keys of the property
dictionary, i.e the names of the properties """
return list(self._props.keys())
def list(self, out=sys.stdout):
""" Prints a listing of the properties to the
stream 'out' which defaults to the standard output """
out.write('-- listing properties --\n')
for key, value in list(self._props.items()):
out.write(''.join((key, '=', value, '\n')))
def store(self, out, header=""):
""" Write the properties list to the stream 'out' along
with the optional 'header' """
if out.mode[0] != 'w':
raise ValueError('Steam should be opened in write mode!')
try:
out.write(''.join(('#', header, '\n')))
# Write timestamp
tstamp = time.strftime('%a %b %d %H:%M:%S %Z %Y', time.localtime())
out.write(''.join(('#', tstamp, '\n')))
# Write properties from the pristine dictionary
for prop, val in list(self._origprops.items()):
out.write(''.join((prop, '=', self.escape(val), '\n')))
out.close()
except IOError as e:
raise
def getPropertyDict(self):
return self._props
def __getitem__(self, name):
""" To support direct dictionary like access """
return self.getProperty(name)
def __setitem__(self, name, value):
""" To support direct dictionary like access """
self.setProperty(name, value)
def __getattr__(self, name):
""" For attributes not found in self, redirect
to the properties dictionary """
try:
return self.__dict__[name]
except KeyError:
if hasattr(self._props, name):
return getattr(self._props, name)
if __name__ == "__main__":
p = Properties()
p.load(open('test2.properties'))
p.list()
p['hello'] = "no"
# print p
# print p.items()
# print p['name3']
# p['name3'] = 'changed = value'
# print p['name3']
# p['new key'] = 'new value'
p.store(open('test2.properties', 'w'))