24 from future
import standard_library
25 standard_library.install_aliases()
26 from past.builtins
import basestring
35 from .
import LogicalLocation, Persistence, Policy, StorageList, Registry, Storage, RepositoryCfg, safeFileIo
38 from .safeFileIo
import SafeFilename
48 self.
log = Log.getLogger(
"daf.persistence.butler")
49 self.
root = parseRes = urllib.parse.urlparse(uri).path
50 if self.
root and not os.path.exists(self.
root):
51 os.makedirs(self.
root)
55 self.
persistence = Persistence.getPersistence(persistencePolicy)
60 return 'PosixStorage(root=%s)' % self.
root
64 """Get a persisted RepositoryCfg
67 parseRes = urllib.parse.urlparse(uri)
68 loc = os.path.join(parseRes.path,
'repositoryCfg.yaml')
69 if os.path.exists(loc):
70 with open(loc,
'r') as f:
71 repositoryCfg = yaml.load(f)
72 if repositoryCfg.root
is None:
73 repositoryCfg.root = parseRes.path
78 repositoryCfg = PosixStorage._getRepositoryCfg(uri)
79 if repositoryCfg
is not None:
83 parseRes = urllib.parse.urlparse(uri)
84 if repositoryCfg
is None:
85 mapper = PosixStorage.getMapperClass(parseRes.path)
86 if mapper
is not None:
87 repositoryCfg = RepositoryCfg(mapper=mapper,
91 isLegacyRepository=
True)
96 if cfg.isLegacyRepository:
100 if loc
is None or cfg.root == loc:
106 if not os.path.exists(loc):
108 loc = os.path.join(loc,
'repositoryCfg.yaml')
109 with safeFileIo.FileForWriteOnceCompareSame(loc)
as f:
114 """Get the mapper class associated with a repository root.
116 Supports the legacy _parent symlink search (which was only ever posix-only. This should not be used by
117 new code and repositories; they should use the Repository parentCfg mechanism.
119 :param root: the location of a persisted ReositoryCfg is (new style repos), or the location where a
120 _mapper file is (old style repos).
121 :return: a class object or a class instance, depending on the state of the mapper when the repository
127 cfg = PosixStorage._getRepositoryCfg(root)
133 mapperFile =
"_mapper"
134 while not os.path.exists(os.path.join(basePath, mapperFile)):
136 if os.path.exists(os.path.join(basePath,
"_parent")):
137 basePath = os.path.join(basePath,
"_parent")
142 if mapperFile
is not None:
143 mapperFile = os.path.join(basePath, mapperFile)
146 with open(mapperFile,
"r") as f:
147 mapperName = f.readline().strip()
148 components = mapperName.split(".")
149 if len(components) <= 1:
150 raise RuntimeError(
"Unqualified mapper name %s in %s" %
151 (mapperName, mapperFile))
152 pkg = importlib.import_module(
".".join(components[:-1]))
153 return getattr(pkg, components[-1])
158 """Get the class object for the mapper specified in the stored repository"""
159 return PosixStorage.getMapperClass(self.
root)
161 def write(self, butlerLocation, obj):
162 """Writes an object to a location and persistence format specified by ButlerLocation
164 :param butlerLocation: the location & formatting for the object to be written.
165 :param obj: the object to be written.
168 self.log.debug(
"Put location=%s obj=%s", butlerLocation, obj)
170 additionalData = butlerLocation.getAdditionalData()
171 storageName = butlerLocation.getStorageName()
172 locations = butlerLocation.getLocations()
174 pythonType = butlerLocation.getPythonType()
175 if pythonType
is not None:
176 if isinstance(pythonType, basestring):
178 pythonTypeTokenList = pythonType.split(
'.')
179 importClassString = pythonTypeTokenList.pop()
180 importClassString = importClassString.strip()
181 importPackage =
".".join(pythonTypeTokenList)
182 importType = __import__(importPackage, globals(), locals(), [importClassString], 0)
183 pythonType = getattr(importType, importClassString)
188 if hasattr(pythonType,
'butlerWrite'):
189 pythonType.butlerWrite(obj, butlerLocation=butlerLocation)
193 logLoc = LogicalLocation(locationString, additionalData)
195 if storageName ==
"PickleStorage":
196 with open(logLoc.locString(),
"wb")
as outfile:
197 pickle.dump(obj, outfile, pickle.HIGHEST_PROTOCOL)
200 if storageName ==
"ConfigStorage":
201 obj.save(logLoc.locString())
204 if storageName ==
"FitsCatalogStorage":
205 flags = additionalData.getInt(
"flags", 0)
206 obj.writeFits(logLoc.locString(), flags=flags)
210 storageList = StorageList()
211 storage = self.persistence.getPersistStorage(storageName, logLoc)
212 storageList.append(storage)
214 if storageName ==
'FitsStorage':
215 self.persistence.persist(obj, storageList, additionalData)
219 if hasattr(obj,
'__deref__'):
221 self.persistence.persist(obj.__deref__(), storageList, additionalData)
223 self.persistence.persist(obj, storageList, additionalData)
225 def read(self, butlerLocation):
226 """Read from a butlerLocation.
228 :param butlerLocation:
229 :return: a list of objects as described by the butler location. One item for each location in
230 butlerLocation.getLocations()
232 additionalData = butlerLocation.getAdditionalData()
234 storageName = butlerLocation.getStorageName()
236 locations = butlerLocation.getLocations()
237 pythonType = butlerLocation.getPythonType()
238 if pythonType
is not None:
239 if isinstance(pythonType, basestring):
241 pythonTypeTokenList = pythonType.split(
'.')
242 importClassString = pythonTypeTokenList.pop()
243 importClassString = importClassString.strip()
244 importPackage =
".".join(pythonTypeTokenList)
245 importType = __import__(importPackage, globals(), locals(), [importClassString], 0)
246 pythonType = getattr(importType, importClassString)
250 if hasattr(pythonType,
'butlerRead'):
251 results = pythonType.butlerRead(butlerLocation=butlerLocation)
254 for locationString
in locations:
255 logLoc = LogicalLocation(locationString, additionalData)
257 if storageName ==
"PafStorage":
258 finalItem = pexPolicy.Policy.createPolicy(logLoc.locString())
259 elif storageName ==
"YamlStorage":
260 finalItem = Policy(filePath=logLoc.locString())
261 elif storageName ==
"PickleStorage":
262 if not os.path.exists(logLoc.locString()):
263 raise RuntimeError(
"No such pickle file: " + logLoc.locString())
264 with open(logLoc.locString(),
"rb")
as infile:
265 finalItem = pickle.load(infile)
266 elif storageName ==
"FitsCatalogStorage":
267 if not os.path.exists(logLoc.locString()):
268 raise RuntimeError(
"No such FITS catalog file: " + logLoc.locString())
269 hdu = additionalData.getInt(
"hdu", 0)
270 flags = additionalData.getInt(
"flags", 0)
271 finalItem = pythonType.readFits(logLoc.locString(), hdu, flags)
272 elif storageName ==
"ConfigStorage":
273 if not os.path.exists(logLoc.locString()):
274 raise RuntimeError(
"No such config file: " + logLoc.locString())
275 finalItem = pythonType()
276 finalItem.load(logLoc.locString())
278 storageList = StorageList()
279 storage = self.persistence.getRetrieveStorage(storageName, logLoc)
280 storageList.append(storage)
281 itemData = self.persistence.unsafeRetrieve(
282 butlerLocation.getCppType(), storageList, additionalData)
283 finalItem = pythonType.swigConvert(itemData)
284 results.append(finalItem)
289 """Check if 'location' exists relative to root.
294 return os.path.exists(os.path.join(self.
root, location))
297 """Get the full path to the location.
302 return os.path.join(self.
root, location)
305 """Perform a lookup in the registry"""
306 return self.registry.lookup(*args, **kwargs)
309 Storage.registerStorageClass(scheme=
'', cls=PosixStorage)
310 Storage.registerStorageClass(scheme=
'file', cls=PosixStorage)
a container for holding hierarchical configuration data in memory.
Abstract base class for storage implementations.