/usr/lib/python2.7/dist-packages/pyjavaproperties.py is in python-pyjavaproperties 0.6-2.1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 | #! /usr/bin/env python
"""
A Python replacement for java.util.Properties class
This is modelled as closely as possible to the Java original.
Created - Anand B Pillai <abpillai@gmail.com>
"""
import sys,os
import re
import time
class IllegalArgumentException(Exception):
def __init__(self, lineno, msg):
self.lineno = lineno
self.msg = msg
def __str__(self):
s='Exception at line number %d => %s' % (self.lineno, self.msg)
return s
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 = {}
self._keyorder = []
# Dictionary mapping keys from property
# dictionary to pristine dictionary
self._keymap = {}
self.othercharre = re.compile(r'(?<!\\)(\s*\=)|(?<!\\)(\s*\:)')
self.othercharre2 = re.compile(r'(\s*\=)|(\s*\:)')
self.bspacere = re.compile(r'\\(?!\s$)')
def __str__(self):
s='{'
for key,value in self._props.items():
s = ''.join((s,key,'=',value,', '))
s=''.join((s[:-2],'}'))
return s
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 '#' or '!' 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.
lineno=0
i = iter(lines)
for line in i:
lineno += 1
line = line.strip()
# Skip null lines
if not line: continue
# Skip lines which are comments
if line[0] in ('#','!'): continue
# Some flags
escaped=False
# Position of first separation char
sepidx = -1
# A flag for performing wspace re check
flag = 0
# Check for valid space separation
# First obtain the max index to which we
# can search.
m = self.othercharre.search(line)
if m:
first, last = m.span()
start, end = 0, first
flag = 1
wspacere = re.compile(r'(?<![\\\=\:])(\s)')
else:
if self.othercharre2.search(line):
# Check if either '=' or ':' is present
# in the line. If they are then it means
# they are preceded by a backslash.
# This means, we need to modify the
# wspacere a bit, not to look for
# : or = characters.
wspacere = re.compile(r'(?<![\\])(\s)')
start, end = 0, len(line)
m2 = wspacere.search(line, start, end)
if m2:
# print 'Space match=>',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 = i.next()
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._keyorder.append(key)
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)
# Patch from N B @ ActiveState
curlies = re.compile("{.+?}")
found = curlies.findall(value)
for f in found:
srcKey = f[1:-1]
if self._props.has_key(srcKey):
value = value.replace(f, self._props[srcKey], 1)
self._props[key] = value.strip()
# Check if an entry exists in pristine keys
if self._keymap.has_key(key):
oldkey = self._keymap.get(key)
self._origprops[oldkey] = oldvalue.strip()
else:
self._origprops[oldkey] = oldvalue.strip()
# Store entry in keymap
self._keymap[key] = oldkey
if key not in self._keyorder:
self._keyorder.append(key)
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, 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 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 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 in self._keyorder:
if prop in self._origprops:
val = self._origprops[prop]
out.write(''.join((prop,'=',self.escape(val),'\n')))
out.close()
except IOError, 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()
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'))
|