Skip to content

Commit 24b0da5

Browse files
author
Daniel Abercrombie
authored
Merge pull request #64 from dabercro/reset-cache
Added function to Info classes to reset selectively.
2 parents 349c4eb + ebe6fa1 commit 24b0da5

1 file changed

Lines changed: 62 additions & 44 deletions

File tree

CMSToolBox/workflowinfo.py

Lines changed: 62 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@
1010
import time
1111
import datetime
1212

13+
from collections import defaultdict
1314
from functools import wraps
15+
1416
from .webtools import get_json
1517
from .sitereadiness import site_list
1618

@@ -43,22 +45,21 @@ def function_wrapper(self, *args, **kwargs):
4345
:returns: Output of the originally decorated function
4446
:rtype: dict
4547
"""
46-
if not os.path.exists('/tmp/workflowinfo'):
47-
os.mkdir('/tmp/workflowinfo')
48-
49-
file_name = '/tmp/workflowinfo/%s_%s.cache.json' % (self, attribute)
48+
if not os.path.exists(self.cache_dir):
49+
os.mkdir(self.cache_dir)
5050

5151
check_var = self.cache.get(attribute)
5252

5353
if check_var is None:
54+
file_name = self.cache_filename(attribute)
5455
if os.path.exists(file_name) and \
5556
(timeout is None or time.time() - timeout < os.stat(file_name).st_mtime):
56-
with open(file_name, 'r') as cache_file:
57-
try:
57+
try:
58+
with open(file_name, 'r') as cache_file:
5859
check_var = json.load(cache_file)
59-
except ValueError:
60-
print 'JSON file no good. Delete %s and try again.' % file_name
61-
exit(5)
60+
except ValueError:
61+
print 'JSON file no good. Deleting %s. Try again later.' % file_name
62+
os.remove(file_name)
6263

6364
else:
6465
check_var = func(self, *args, **kwargs)
@@ -159,7 +160,48 @@ def explain_errors(workflow, errorcode):
159160
return output
160161

161162

162-
class WorkflowInfo(object):
163+
class Info(object):
164+
"""
165+
Implements shared operations on the cache
166+
"""
167+
168+
def __init__(self):
169+
# Stores things using the cached_json decorator
170+
self.cache = {}
171+
self.cache_dir = os.path.join(os.environ.get('TMPDIR', '/tmp'), 'workflowinfo')
172+
self.bak_dir = os.path.join(self.cache_dir, 'bak')
173+
174+
def __str__(self):
175+
pass
176+
177+
def cache_filename(self, attribute):
178+
"""
179+
Return the name of the file for caching
180+
181+
:param str attribute: The information to store in the file
182+
:returns: The full file name to store the cache
183+
:rtype: str
184+
"""
185+
return os.path.join(self.cache_dir, '%s_%s.cache.json' % (self, attribute))
186+
187+
def reset(self):
188+
"""
189+
Reset the cache for this object and clear out the files.
190+
"""
191+
print 'Reseting %s' % self
192+
193+
if not os.path.exists(self.bak_dir):
194+
os.mkdir(self.bak_dir)
195+
196+
for attribute in self.cache:
197+
cache_file = self.cache_filename(attribute)
198+
if os.path.exists(cache_file):
199+
os.rename(cache_file, cache_file.replace(self.cache_dir, self.bak_dir))
200+
201+
self.cache.clear()
202+
203+
204+
class WorkflowInfo(Info):
163205
"""
164206
Class that holds methods for accessing various information about a workflow.
165207
"""
@@ -172,11 +214,10 @@ def __init__(self, workflow, url='cmsweb.cern.ch'):
172214
:param str url: is the url to fetch information from
173215
"""
174216

217+
super(WorkflowInfo, self).__init__()
175218
self.workflow = workflow
176219
self.url = url
177220

178-
# Stores things using the cached_json decorator
179-
self.cache = {}
180221
# Is set first time get_explanation() is called
181222
self.explanations = None
182223

@@ -341,39 +382,19 @@ def get_explanation(self, errorcode, step=''):
341382
"""
342383

343384
if self.explanations is None:
344-
self.explanations = {}
385+
self.explanations = defaultdict(lambda: defaultdict(lambda: []))
345386
result = self._get_jobdetail()
346387
for stepname, stepdata in result['result'][0].get(self.workflow, {}).iteritems():
347388
# Get the errors from both 'jobfailed' and 'submitfailed' details
348-
for error, site in \
349-
sum([stepdata.get(status, {}).items() for status in \
350-
['jobfailed', 'submitfailed']], []):
389+
for error, site in [(error, site) for status in ['jobfailed', 'submitfailed'] \
390+
for error, site in stepdata.get(status, {}).items()]:
351391
if error == '0':
352392
continue
353393

354-
if self.explanations.get(error) is None:
355-
self.explanations[error] = {}
356-
357-
if self.explanations[error].get(stepname) is None:
358-
self.explanations[error][stepname] = []
359-
360394
for sitename, samples in site.iteritems():
361-
362-
#
363-
# Flatten the following nested loops:
364-
#
365-
# for sample in samples['samples']:
366-
# for values in sample['errors'].values():
367-
# for detail in values:
368-
#
369-
# Both ways are equally unreadable, I think
370-
#
371-
372-
for detail in sum(
373-
[values for values in sum(
374-
[sample['errors'].values() for sample in samples['samples']],
375-
[])],
376-
[]):
395+
for detail in [values for sample in samples['samples']
396+
for errs in sample['errors'].values()
397+
for values in errs]:
377398

378399
self.explanations[error][stepname].append('\n\n'.join(
379400
['Site name: %s' % sitename,
@@ -385,7 +406,7 @@ def get_explanation(self, errorcode, step=''):
385406
if step in explain.keys():
386407
return explain[step]
387408

388-
return sum([val for val in explain.values()], [])
409+
return [val for expl in explain.values() for val in expl]
389410

390411
def get_prep_id(self):
391412
"""
@@ -396,19 +417,16 @@ def get_prep_id(self):
396417
return str(self.get_workflow_parameters().get('PrepID', 'NoPrepID'))
397418

398419

399-
class PrepIDInfo(object):
420+
class PrepIDInfo(Info):
400421
"""
401422
A class that just holds a small amount of information about a given PrepID.
402423
"""
403424

404425
def __init__(self, prep_id, url='cmsweb.cern.ch'):
405-
426+
super(PrepIDInfo, self).__init__()
406427
self.prep_id = prep_id
407428
self.url = url
408429

409-
# Stores things using the cached_json decorator
410-
self.cache = {}
411-
412430
def __str__(self):
413431
return 'prepIDinfo_%s' % self.prep_id
414432

0 commit comments

Comments
 (0)