from myslice.config import Config
-from manifoldresult import ManifoldResult, ManifoldCode
+from manifoldresult import ManifoldResult, ManifoldCode, ManifoldException
debug=False
debug=True
def __repr__ (self): return "ManifoldAPI[%s]"%self.url
+ # a one-liner to give a hint of what the return value looks like
+ def _print_result (self, result):
+ if not result: print "[no/empty result]"
+ elif isinstance (result,str): print "result is '%s'"%result
+ elif isinstance (result,list): print "result is a %d-elts list"%len(result)
+ else: print "[dont know how to display result]"
+
# xxx temporary code for scaffolding a ManifolResult on top of an API that does not expose error info
# as of march 2013 we work with an API that essentially either returns the value, or raises
# an xmlrpclib.Fault exception with always the same 8002 code
# a SESSION_EXPIRED code
def __getattr__(self, methodName):
def func(*args, **kwds):
- if (debug):
- print "entering ManifoldAPI.%s"%methodName,
- print "args",args,
- print "kwds",kwds
try:
+ if debug: print "====> ManifoldAPI.%s"%methodName,"args",args,"kwds",kwds
result=getattr(self.server, methodName)(self.auth, *args, **kwds)
+ if debug:
+ print '<==== backend call %s(*%s,**%s) returned'%(methodName,args,kwds),
+ print '.ctd. Authmethod=',self.auth['AuthMethod'], self.url,'->',
+ self._print_result(result)
### attempt to cope with old APIs and new APIs
if isinstance (result, dict) and 'code' in result:
- # this sounds like a result from a new API, leave it untouched
- # XXX jordan : we need to wrap it into a ResultValue structure
- # XXX this is not good until we merge both repos
- if result['code'] != 2:
+ if debug: print "taken as new API"
+ # this sounds like a result from a new API
+ # minimal treatment is required, but we do want to turn this into a
+ # class instance
+ if result['code'] != 2: # in the manifold world, this can be either
+ # 0 (ok) 1 (partial result) or 2 which means error
+ if debug: print "OK (new API)"
return ManifoldResult(code=result['code'], value=result['value'])
else:
- return ManifoldResult(code=result['code'], output=result['description'])
+ if debug: print "KO (new API) - raising ManifoldException"
+ raise ManifoldException(ManifoldResult(code=result['code'], output=result['description']))
else:
- if debug:
- print '<=== backend call', methodName, args, kwds
- print '.... ctd', 'Authmethod=',self.auth['AuthMethod'], self.url,'->',
- if not result: print "[no/empty result]"
- elif isinstance (result,str): print "result is '%s'"%result
- elif isinstance (result,list): print "result is a %d-elts list"%len(result)
- else: print "[dont know how to display result]"
+ if debug: print "taken as old API"
+ # we're talking to an old API
+ # so if we make it here it should mean success
return ManifoldResult (code=ManifoldCode.SUCCESS, value=result)
except xmlrpclib.Fault, error:
### xxx this is very rough for now
# in some less unpolite way than this anonymous exception, we assume it's a problem with the session
# that needs to be refreshed
if error.faultCode == 8002:
+ if debug: print "KO (old API - 8002) - raising ManifoldException"
reason="most likely your session has expired"
reason += " (the manifold API has no unambiguous error reporting mechanism yet)"
- return ManifoldResult (code=ManifoldCode.SESSION_EXPIRED, output=reason)
+ raise ManifoldException ( ManifoldResult (code=ManifoldCode.SESSION_EXPIRED, output=reason))
else:
+ if debug: print "KO (old API - other) - raising ManifoldException"
reason="xmlrpclib.Fault with faultCode = %s (not taken as session expired)"%error.faultCode
- return ManifoldResult (code=ManifoldCode.UNKNOWN_ERROR, output=reason)
+ raise ManifoldException ( ManifoldResult (code=ManifoldCode.UNKNOWN_ERROR, output=reason))
except Exception,error:
- print "ManifoldAPI: unexpected exception",error
- return ManifoldResult (code=ManifoldCode.UNKNOWN_ERROR, output="%s"%error)
+ if debug: print "KO (unexpected exception)",error
+ raise ManifoldException ( ManifoldResult (code=ManifoldCode.UNKNOWN_ERROR, output="%s"%error) )
return func
def send_manifold_query (self, query):
#from manifold.manifoldquery import ManifoldQuery
from manifold.core.query import Query
from manifold.manifoldapi import ManifoldAPI
+from manifold.manifoldresult import ManifoldException
debug=False
debug=True
# actually forward
manifold_api= ManifoldAPI(auth=manifold_api_session_auth)
- if debug: print 'manifoldproxy.proxy: sending to backend', manifold_query
- answer=manifold_api.send_manifold_query (manifold_query)
+ if debug: print '===> manifoldproxy.proxy: sending to backend', manifold_query
+ # for the benefit of the python code, manifoldAPI raises an exception if something is wrong
+ # however in this case we want to propagate the complete manifold result to the js world
+ try:
+ answer=manifold_api.send_manifold_query (manifold_query)
+ except ManifoldException, manifold_result:
+ answer=manifold_result
print "="*80
print "ANSWER IN PROXY", answer
print answer.ok_value()
else: print "result is other (type=%s) : %s"%(type(value),value)
json_answer=json.dumps(answer)
# if in debug mode we save this so we can use offline mode later
- if (debug):
+ if debug:
with (file(offline_filename,"w")) as f:
f.write(json_answer)
# this is an artificial delay added for debugging purposes only
for k in ['code','value','output']:
self[k]=d[k]
+ # raw accessors
+ def code (self): return self['code']
+ def output (self): return self['output']
+
# this returns None if there's a problem, the value otherwise
def ok_value (self):
if self['code']==ManifoldCode.SUCCESS:
return self['value']
+ # both data in a single string
def error (self):
return "code=%s -- %s"%(self['code'],self['output'])
result += " [output=%s]"%self['output']
result += "]]"
return result
+
+# probably simpler to use a single class and transport the whole result there
+# instead of a clumsy set of derived classes
+class ManifoldException (Exception):
+ def __init__ (self, manifold_result):
+ self.manifold_result=manifold_result
+ def __repr__ (self):
+ return "Manifold Exception %s"%(self.manifold_result.error())
self.auth=auth
self.hash_by_object={}
- # XXX Retrieve all metadata the first time we instanciate the class
- self.fetch()
-
def fetch (self):
offline_filename="offline-metadata.json"
if work_offline:
'object': 'local:object', # proposed to replace metadata:table
'fields': fields
})
-#old# rows_result = manifold_api.Get('metadata:table', [], [], fields)
rows = rows_result.ok_value()
- if not rows:
- print "Failed to retrieve metadata",rows_result.error()
- rows=[]
+# API errors will be handled by the outer logic
+# if not rows:
+# print "Failed to retrieve metadata",rows_result.error()
+# rows=[]
self.hash_by_object = dict ( [ (row['table'], row) for row in rows ] )
# save for next time we use offline mode
- if debug:
+ if debug and rows:
with file(offline_filename,'w') as f:
f.write(json.dumps(self.hash_by_object))
from django.shortcuts import render_to_response
from django.contrib.auth.decorators import login_required
+from django.http import HttpResponseRedirect
from unfold.page import Page
#from manifold.manifoldquery import ManifoldQuery
from plugins.quickfilter.quickfilter import QuickFilter
from plugins.messages.messages import Messages
-from myslice.viewutils import quickfilter_criterias
+from manifold.manifoldresult import ManifoldException
+from myslice.viewutils import quickfilter_criterias
from myslice.viewutils import topmenu_items, the_user
# XXX JORDAN
@login_required
def slice_view (request, slicename=tmp_default_slice):
-
+ # xxx Thierry - ugly hack
+ # fetching metadata here might fail - e.g. with an expired session..
+ # let's catch this early on and log out our user if needed
+ # it should of course be handled in a more generic way
+ try:
+ return _slice_view(request,slicename)
+ except ManifoldException, manifold_result:
+ # xxx needs a means to display this message to user...
+ from django.contrib.auth import logout
+ logout(request)
+ return HttpResponseRedirect ('/')
+ except Exception, e:
+ # xxx we need to sugarcoat this error message in some error template...
+ print "Unexpected exception",e
+ # return ...
+
+def _slice_view (request, slicename):
+
page = Page(request)
page.expose_js_metadata()
-
# TODO The query to run is embedded in the URL
main_query = Query.get('slice').filter_by('slice_hrn', '=', slicename)
# Get default fields from metadata unless specified
if not main_query.fields:
- md_fields = page.get_metadata()
- md_fields = md_fields.details_by_object('slice')
+ metadata = page.get_metadata()
+ md_fields = metadata.details_by_object('slice')
if debug:
print "METADATA", md_fields
# TODO Get default fields
manifold_api_session_auth = session['manifold']['auth']
metadata=MetaData (manifold_api_session_auth)
metadata.fetch()
- # store it for next time
+ # store it for next time
manifold['metadata']=metadata
if debug: print "Page.get_metadata: return new value"
return metadata