123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200 |
- # -*- test-case-name: twisted.test.test_sob -*-
- # Copyright (c) Twisted Matrix Laboratories.
- # See LICENSE for details.
- #
- """
- Save and load Small OBjects to and from files, using various formats.
- Maintainer: Moshe Zadka
- """
- import os
- import pickle
- import sys
- from zope.interface import Interface, implementer
- from twisted.persisted import styles
- from twisted.python import log, runtime
- class IPersistable(Interface):
- """An object which can be saved in several formats to a file"""
- def setStyle(style):
- """Set desired format.
- @type style: string (one of 'pickle' or 'source')
- """
- def save(tag=None, filename=None, passphrase=None):
- """Save object to file.
- @type tag: string
- @type filename: string
- @type passphrase: string
- """
- @implementer(IPersistable)
- class Persistent:
- style = "pickle"
- def __init__(self, original, name):
- self.original = original
- self.name = name
- def setStyle(self, style):
- """Set desired format.
- @type style: string (one of 'pickle' or 'source')
- """
- self.style = style
- def _getFilename(self, filename, ext, tag):
- if filename:
- finalname = filename
- filename = finalname + "-2"
- elif tag:
- filename = f"{self.name}-{tag}-2.{ext}"
- finalname = f"{self.name}-{tag}.{ext}"
- else:
- filename = f"{self.name}-2.{ext}"
- finalname = f"{self.name}.{ext}"
- return finalname, filename
- def _saveTemp(self, filename, dumpFunc):
- with open(filename, "wb") as f:
- dumpFunc(self.original, f)
- def _getStyle(self):
- if self.style == "source":
- from twisted.persisted.aot import jellyToSource as dumpFunc
- ext = "tas"
- else:
- def dumpFunc(obj, file=None):
- pickle.dump(obj, file, 2)
- ext = "tap"
- return ext, dumpFunc
- def save(self, tag=None, filename=None, passphrase=None):
- """Save object to file.
- @type tag: string
- @type filename: string
- @type passphrase: string
- """
- ext, dumpFunc = self._getStyle()
- if passphrase is not None:
- raise TypeError("passphrase must be None")
- finalname, filename = self._getFilename(filename, ext, tag)
- log.msg("Saving " + self.name + " application to " + finalname + "...")
- self._saveTemp(filename, dumpFunc)
- if runtime.platformType == "win32" and os.path.isfile(finalname):
- os.remove(finalname)
- os.rename(filename, finalname)
- log.msg("Saved.")
- # "Persistant" has been present since 1.0.7, so retain it for compatibility
- Persistant = Persistent
- class _EverythingEphemeral(styles.Ephemeral):
- initRun = 0
- def __init__(self, mainMod):
- """
- @param mainMod: The '__main__' module that this class will proxy.
- """
- self.mainMod = mainMod
- def __getattr__(self, key):
- try:
- return getattr(self.mainMod, key)
- except AttributeError:
- if self.initRun:
- raise
- else:
- log.msg("Warning! Loading from __main__: %s" % key)
- return styles.Ephemeral()
- def load(filename, style):
- """Load an object from a file.
- Deserialize an object from a file. The file can be encrypted.
- @param filename: string
- @param style: string (one of 'pickle' or 'source')
- """
- mode = "r"
- if style == "source":
- from twisted.persisted.aot import unjellyFromSource as _load
- else:
- _load, mode = pickle.load, "rb"
- fp = open(filename, mode)
- ee = _EverythingEphemeral(sys.modules["__main__"])
- sys.modules["__main__"] = ee
- ee.initRun = 1
- with fp:
- try:
- value = _load(fp)
- finally:
- # restore __main__ if an exception is raised.
- sys.modules["__main__"] = ee.mainMod
- styles.doUpgrade()
- ee.initRun = 0
- persistable = IPersistable(value, None)
- if persistable is not None:
- persistable.setStyle(style)
- return value
- def loadValueFromFile(filename, variable):
- """Load the value of a variable in a Python file.
- Run the contents of the file in a namespace and return the result of the
- variable named C{variable}.
- @param filename: string
- @param variable: string
- """
- with open(filename) as fileObj:
- data = fileObj.read()
- d = {"__file__": filename}
- codeObj = compile(data, filename, "exec")
- eval(codeObj, d, d)
- value = d[variable]
- return value
- def guessType(filename):
- ext = os.path.splitext(filename)[1]
- return {
- ".tac": "python",
- ".etac": "python",
- ".py": "python",
- ".tap": "pickle",
- ".etap": "pickle",
- ".tas": "source",
- ".etas": "source",
- }[ext]
- __all__ = [
- "loadValueFromFile",
- "load",
- "Persistent",
- "Persistant",
- "IPersistable",
- "guessType",
- ]
|