sob.py 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. # -*- test-case-name: twisted.test.test_sob -*-
  2. # Copyright (c) Twisted Matrix Laboratories.
  3. # See LICENSE for details.
  4. #
  5. """
  6. Save and load Small OBjects to and from files, using various formats.
  7. Maintainer: Moshe Zadka
  8. """
  9. from __future__ import division, absolute_import
  10. import os
  11. import sys
  12. try:
  13. import cPickle as pickle
  14. except ImportError:
  15. import pickle
  16. from twisted.python import log, runtime
  17. from twisted.persisted import styles
  18. from zope.interface import implementer, Interface
  19. class IPersistable(Interface):
  20. """An object which can be saved in several formats to a file"""
  21. def setStyle(style):
  22. """Set desired format.
  23. @type style: string (one of 'pickle' or 'source')
  24. """
  25. def save(tag=None, filename=None, passphrase=None):
  26. """Save object to file.
  27. @type tag: string
  28. @type filename: string
  29. @type passphrase: string
  30. """
  31. @implementer(IPersistable)
  32. class Persistent:
  33. style = "pickle"
  34. def __init__(self, original, name):
  35. self.original = original
  36. self.name = name
  37. def setStyle(self, style):
  38. """Set desired format.
  39. @type style: string (one of 'pickle' or 'source')
  40. """
  41. self.style = style
  42. def _getFilename(self, filename, ext, tag):
  43. if filename:
  44. finalname = filename
  45. filename = finalname + "-2"
  46. elif tag:
  47. filename = "%s-%s-2.%s" % (self.name, tag, ext)
  48. finalname = "%s-%s.%s" % (self.name, tag, ext)
  49. else:
  50. filename = "%s-2.%s" % (self.name, ext)
  51. finalname = "%s.%s" % (self.name, ext)
  52. return finalname, filename
  53. def _saveTemp(self, filename, dumpFunc):
  54. with open(filename, 'wb') as f:
  55. dumpFunc(self.original, f)
  56. def _getStyle(self):
  57. if self.style == "source":
  58. from twisted.persisted.aot import jellyToSource as dumpFunc
  59. ext = "tas"
  60. else:
  61. def dumpFunc(obj, file):
  62. pickle.dump(obj, file, 2)
  63. ext = "tap"
  64. return ext, dumpFunc
  65. def save(self, tag=None, filename=None, passphrase=None):
  66. """Save object to file.
  67. @type tag: string
  68. @type filename: string
  69. @type passphrase: string
  70. """
  71. ext, dumpFunc = self._getStyle()
  72. if passphrase is not None:
  73. raise TypeError("passphrase must be None")
  74. ext = 'e' + ext
  75. finalname, filename = self._getFilename(filename, ext, tag)
  76. log.msg("Saving "+self.name+" application to "+finalname+"...")
  77. self._saveTemp(filename, dumpFunc)
  78. if runtime.platformType == "win32" and os.path.isfile(finalname):
  79. os.remove(finalname)
  80. os.rename(filename, finalname)
  81. log.msg("Saved.")
  82. # "Persistant" has been present since 1.0.7, so retain it for compatibility
  83. Persistant = Persistent
  84. class _EverythingEphemeral(styles.Ephemeral):
  85. initRun = 0
  86. def __init__(self, mainMod):
  87. """
  88. @param mainMod: The '__main__' module that this class will proxy.
  89. """
  90. self.mainMod = mainMod
  91. def __getattr__(self, key):
  92. try:
  93. return getattr(self.mainMod, key)
  94. except AttributeError:
  95. if self.initRun:
  96. raise
  97. else:
  98. log.msg("Warning! Loading from __main__: %s" % key)
  99. return styles.Ephemeral()
  100. def load(filename, style):
  101. """Load an object from a file.
  102. Deserialize an object from a file. The file can be encrypted.
  103. @param filename: string
  104. @param style: string (one of 'pickle' or 'source')
  105. """
  106. mode = 'r'
  107. if style=='source':
  108. from twisted.persisted.aot import unjellyFromSource as _load
  109. else:
  110. _load, mode = pickle.load, 'rb'
  111. fp = open(filename, mode)
  112. ee = _EverythingEphemeral(sys.modules['__main__'])
  113. sys.modules['__main__'] = ee
  114. ee.initRun = 1
  115. with fp:
  116. try:
  117. value = _load(fp)
  118. finally:
  119. # restore __main__ if an exception is raised.
  120. sys.modules['__main__'] = ee.mainMod
  121. styles.doUpgrade()
  122. ee.initRun = 0
  123. persistable = IPersistable(value, None)
  124. if persistable is not None:
  125. persistable.setStyle(style)
  126. return value
  127. def loadValueFromFile(filename, variable):
  128. """Load the value of a variable in a Python file.
  129. Run the contents of the file in a namespace and return the result of the
  130. variable named C{variable}.
  131. @param filename: string
  132. @param variable: string
  133. """
  134. with open(filename, 'r') as fileObj:
  135. data = fileObj.read()
  136. d = {'__file__': filename}
  137. codeObj = compile(data, filename, "exec")
  138. eval(codeObj, d, d)
  139. value = d[variable]
  140. return value
  141. def guessType(filename):
  142. ext = os.path.splitext(filename)[1]
  143. return {
  144. '.tac': 'python',
  145. '.etac': 'python',
  146. '.py': 'python',
  147. '.tap': 'pickle',
  148. '.etap': 'pickle',
  149. '.tas': 'source',
  150. '.etas': 'source',
  151. }[ext]
  152. __all__ = ['loadValueFromFile', 'load', 'Persistent', 'Persistant',
  153. 'IPersistable', 'guessType']