-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathPropertiesObject.py
More file actions
166 lines (135 loc) · 6.09 KB
/
Copy pathPropertiesObject.py
File metadata and controls
166 lines (135 loc) · 6.09 KB
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
import os
import sys
class WillNotRunError(Exception):
"""Error for Webware components that will not run."""
class PropertiesObject(dict):
"""A Properties Object.
A PropertiesObject represents, in a dictionary-like fashion, the values
found in a Properties.py file. That file is always included with a Webware
component to advertise its name, version, status, etc. Note that a Webware
component is a Python package that follows additional conventions.
Also, the top level Webware directory contains a Properties.py.
Component properties are often used for:
* generation of documentation
* runtime examination of components, especially prior to loading
PropertiesObject provides additional keys:
* filename - the filename from which the properties were read
* versionString - a nicely printable string of the version
* requiredPyVersionString - like versionString,
but for requiredPyVersion instead
* willRun - 1 if the component will run.
So far that means having the right Python version.
* willNotRunReason - defined only if willRun is 0,
contains a readable error message
Using a PropertiesObject is better than investigating the Properties.py
file directly, because the rules for determining derived keys and any
future convenience methods will all be provided here.
Usage example:
from MiscUtils.PropertiesObject import PropertiesObject
props = PropertiesObject(filename)
for item in props.items():
print '%s: %s' % item
Note: We don't normally suffix a class name with "Object" as we have
with this class, however, the name Properties.py is already used in
our containing package and all other packages.
"""
## Init and reading ##
def __init__(self, filename=None):
dict.__init__(self)
if filename:
self.readFileNamed(filename)
def loadValues(self, *args, **kwargs):
self.update(*args, **kwargs)
self.cleanPrivateItems()
def readFileNamed(self, filename):
results = {}
exec open(filename) in results
self.update(results)
self.cleanPrivateItems()
self.createDerivedItems()
## Self utility ##
def cleanPrivateItems(self):
"""Remove items whose keys start with a double underscore, such as __builtins__."""
for key in self.keys(): # must use keys() because dict is changed
if key.startswith('__'):
del self[key]
def createDerivedItems(self):
self.createVersionString()
self.createRequiredPyVersionString()
self.createWillRun()
def _versionString(self, version):
"""Return the version number as a string.
For a sequence containing version information such as (2, 0, 0, 'pre'),
this returns a printable string such as '2.0pre'.
The micro version number is only excluded from the string if it is zero.
"""
ver = map(str, version)
numbers, rest = ver[:2 if ver[2] == '0' else 3], ver[3:]
return '.'.join(numbers) + '-'.join(rest)
def createVersionString(self):
self['versionString'] = self._versionString(self['version'])
def createRequiredPyVersionString(self):
self['requiredPyVersionString'] = self._versionString(self['requiredPyVersion'])
def createWillRun(self):
self['willRun'] = False
try:
# Invoke each of the checkFoo() methods
for key in self.willRunKeys():
methodName = 'check' + key[0].upper() + key[1:]
method = getattr(self, methodName)
method()
except WillNotRunError as msg:
self['willNotRunReason'] = msg
return
self['willRun'] = True # we passed all the tests
def willRunKeys(self):
"""Return keys to be examined before running the component.
This returns a set of all keys whose values should be examined in
order to determine if the component will run. Used by createWillRun().
"""
return set(('requiredPyVersion', 'requiredOpSys', 'deniedOpSys', 'willRunFunc'))
def checkRequiredPyVersion(self):
if tuple(sys.version_info) < tuple(self['requiredPyVersion']):
raise WillNotRunError('Required Python version is %s,'
' but actual version is %s.' % (
'.'.join(map(str, self['requiredPyVersion'])),
'.'.join(map(str, sys.version_info))))
def checkRequiredOpSys(self):
requiredOpSys = self.get('requiredOpSys')
if requiredOpSys:
# We accept a string or list of strings
if isinstance(requiredOpSys, basestring):
requiredOpSys = [requiredOpSys]
if not os.name in requiredOpSys:
raise WillNotRunError('Required operating system is %s,'
' but actual operating system is %s.' % (
'/'.join(requiredOpSys), os.name))
def checkDeniedOpSys(self):
deniedOpSys = self.get('deniedOpSys')
if deniedOpSys:
# We accept a string or list of strings
if isinstance(deniedOpSys, basestring):
deniedOpSys = [deniedOpSys]
if os.name in deniedOpSys:
raise WillNotRunError('Will not run on operating system %s'
' and actual operating system is %s.' % (
'/'.join(deniedOpSys), os.name))
def checkRequiredSoftware(self):
"""Not implemented. No op right now."""
# Check required software
# @@ 2001-01-24 ce: TBD
# Issues include:
# - order of dependencies
# - circular dependencies
# - examining Properties and willRun of dependencies
reqSoft = self.get('requiredSoftware')
if reqSoft:
for soft in reqSoft:
# type, name, version
pass
def checkWillRunFunc(self):
willRunFunc = self.get('willRunFunc')
if willRunFunc:
whyNotMsg = willRunFunc()
if whyNotMsg:
raise WillNotRunError(whyNotMsg)