diff options
Diffstat (limited to 'paste/webkit/FakeWebware/MiscUtils/PropertiesObject.py')
| -rw-r--r-- | paste/webkit/FakeWebware/MiscUtils/PropertiesObject.py | 155 |
1 files changed, 155 insertions, 0 deletions
diff --git a/paste/webkit/FakeWebware/MiscUtils/PropertiesObject.py b/paste/webkit/FakeWebware/MiscUtils/PropertiesObject.py new file mode 100644 index 0000000..d32f1a3 --- /dev/null +++ b/paste/webkit/FakeWebware/MiscUtils/PropertiesObject.py @@ -0,0 +1,155 @@ +from UserDict import UserDict +import os, string, sys, types + +class WillNotRunError(Exception): pass + + +class PropertiesObject(UserDict): + """ + 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): + UserDict.__init__(self) + if filename: + self.readFileNamed(filename) + + def loadValues(self, dict): + self.update(dict) + self.cleanPrivateItems() + + + def readFileNamed(self, filename): + self['filename'] = filename + results = {} + exec open(filename) in results + # @@ 2001-01-20 ce: try "...in self" + self.update(results) + self.cleanPrivateItems() + self.createDerivedItems() + + + ## Self utility ## + + def cleanPrivateItems(self): + """ Removes items whose keys start with a double underscore, such as __builtins__. """ + for key in self.keys(): + if key[:2]=='__': + del self[key] + + def createDerivedItems(self): + self.createVersionString() + self.createRequiredPyVersionString() + self.createWillRun() + + def _versionString(self, version): + """ For a sequence containing version information such as (2, 0, 0, 'pre'), this returns a printable string such as '2.0-pre'. The micro version number is only excluded from the string if it is zero. """ + ver = map(lambda x: str(x), version) + if ver[2]=='0': # e.g., if minor version is 0 + numbers = ver[:2] + else: + numbers = ver[:3] + rest = ver[3:] + numbers = string.join(numbers, '.') + rest = string.join(rest, '-') + if rest: + return numbers + rest + else: + return numbers + + def createVersionString(self): + self['versionString'] = self._versionString(self['version']) + + def createRequiredPyVersionString(self): + self['requiredPyVersionString'] = self._versionString(self['requiredPyVersion']) + + def createWillRun(self): + self['willRun'] = 0 + try: + # Invoke each of the checkFoo() methods + for key in self.willRunKeys(): + methodName = 'check' + string.upper(key[0]) + key[1:] + method = getattr(self, methodName) + method() + except WillNotRunError, msg: + self['willNotRunReason'] = msg + return + self['willRun'] = 1 # we passed all the tests + + def willRunKeys(self): + """ Returns a list of keys whose values should be examined in order to determine if the component will run. Used by createWillRun(). """ + return ['requiredPyVersion', 'requiredOpSys', 'deniedOpSys', 'willRunFunc'] + + def checkRequiredPyVersion(self): + pyVer = getattr(sys, 'version_info', None) + if not pyVer: + # Prior 2.0 there was no version_info + # So we parse it out of .version which is a string + pyVer = string.split(sys.version)[0] + pyVer = string.split(pyVer, '.') + pyVer = map(lambda x: int(x), pyVer) + if tuple(pyVer)<tuple(self['requiredPyVersion']): + raise WillNotRunError, 'Required python ver is %s, but actual ver is %s.' % (self['requiredPyVersion'], pyVer) + + def checkRequiredOpSys(self): + requiredOpSys = self.get('requiredOpSys', None) + if requiredOpSys: + # We accept a string or list of strings + if type(requiredOpSys)==types.StringType: + requiredOpSys = [requiredOpSys] + if not os.name in requiredOpSys: + raise WillNotRunError, 'Required op sys is %s, but actual op sys is %s.' % (requiredOpSys, os.name) + + def checkDeniedOpSys(self): + deniedOpSys = self.get('deniedOpSys', None) + if deniedOpSys: + # We accept a string or list of strings + if type(deniedOpSys)==types.StringType: + deniedOpSys = [deniedOpSys] + if os.name in deniedOpSys: + raise WillNotRunError, 'Will not run on op sys %s and actual op sys is %s.' % (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', None) + if reqSoft: + for soft in reqSoft: + # type, name, version + pass + + def checkWillRunFunc(self): + willRunFunc = self.get('willRunFunc', None) + if willRunFunc: + whyNotMsg = willRunFunc() + if whyNotMsg: + raise WillNotRunError, whyNotMsg |
