Mercurial > p > roundup > code
view roundup/xmlrpc.py @ 8266:43dc610bbd24
doc: known issues with possible dependent tests
When reversing the testing order, two blocks of tests fail. Document
these.
I spent time trying to fix them, but got nowhere. Obviously I am
missing something. But this doc gives future me or somebody else a
starting point.
| author | John Rouillard <rouilj@ieee.org> |
|---|---|
| date | Thu, 09 Jan 2025 09:32:10 -0500 |
| parents | f7bd22bdef9d |
| children |
line wrap: on
line source
# # Copyright (C) 2007 Stefan Seefeld # All rights reserved. # For license terms see the file COPYING.txt. # import logging from roundup import hyperdb from roundup.exceptions import Unauthorised, UsageError from roundup.date import Date, Range, Interval from roundup import actions from roundup.anypy.strings import us2s from traceback import format_exc from roundup.anypy import xmlrpc_ SimpleXMLRPCDispatcher = xmlrpc_.server.SimpleXMLRPCDispatcher Binary = xmlrpc_.client.Binary def translate(value): """Translate value to becomes valid for XMLRPC transmission.""" if isinstance(value, (Date, Range, Interval)): return repr(value) elif type(value) is list: return [translate(v) for v in value] elif type(value) is tuple: return tuple([translate(v) for v in value]) elif type(value) is dict: return dict([[translate(k), translate(value[k])] for k in value]) else: return value def props_from_args(db, cl, args, itemid=None): """Construct a list of properties from the given arguments, and return them after validation.""" props = {} for arg in args: if isinstance(arg, Binary): arg = arg.data try: key, value = arg.split('=', 1) except ValueError: raise UsageError('argument "%s" not propname=value' % arg) key = us2s(key) value = us2s(value) if value: try: props[key] = hyperdb.rawToHyperdb(db, cl, itemid, key, value) except hyperdb.HyperdbValueError as message: raise UsageError(message) else: # If we're syncing a file the contents may not be None if key == 'content': props[key] = '' else: props[key] = None return props class RoundupInstance: """The RoundupInstance provides the interface accessible through the Python XMLRPC mapping.""" def __init__(self, db, actions, translator): self.db = db self.actions = actions self.translator = translator def schema(self): s = {} for c in self.db.classes: cls = self.db.classes[c] props = [(n, repr(v)) for n, v in sorted(cls.properties.items())] s[c] = props return s def list(self, classname, propname=None): cl = self.db.getclass(classname) if not propname: propname = cl.labelprop() result = [cl.get(itemid, propname) for itemid in cl.list() if self.db.security.hasPermission('View', self.db.getuid(), classname, propname, itemid) ] return result def filter(self, classname, search_matches, filterspec, sort=[], group=[]): cl = self.db.getclass(classname) return cl.filter_with_permissions( search_matches, filterspec, sort=sort, group=group ) def lookup(self, classname, key): cl = self.db.getclass(classname) uid = self.db.getuid() prop = cl.getkey() search = self.db.security.hasSearchPermission access = self.db.security.hasPermission if (not search(uid, classname, prop) and not access('View', uid, classname, prop)): raise Unauthorised('Permission to lookup %s denied' % classname) return cl.lookup(key) def display(self, designator, *properties): classname, itemid = hyperdb.splitDesignator(designator) cl = self.db.getclass(classname) props = properties and list(properties) or list(cl.properties.keys()) props.sort() for p in props: if not self.db.security.hasPermission('View', self.db.getuid(), classname, p, itemid): raise Unauthorised('Permission to view %s of %s denied' % (p, designator)) result = [(prop, cl.get(itemid, prop)) for prop in props] return dict(result) def create(self, classname, *args): if not self.db.security.hasPermission('Create', self.db.getuid(), classname): raise Unauthorised('Permission to create %s denied' % classname) cl = self.db.getclass(classname) # convert types props = props_from_args(self.db, cl, args) # check for the key property key = cl.getkey() if key and key not in props: raise UsageError('you must provide the "%s" property.' % key) for key in props: if not self.db.security.hasPermission('Create', self.db.getuid(), classname, property=key): raise Unauthorised('Permission to create %s.%s denied' % (classname, key)) # do the actual create try: result = cl.create(**props) self.db.commit() except (TypeError, IndexError, ValueError) as message: # The exception we get may be a real error, log the traceback # if we're debugging logger = logging.getLogger('roundup.xmlrpc') for l in format_exc().split('\n'): logger.debug(l) raise UsageError(message) return result def set(self, designator, *args): classname, itemid = hyperdb.splitDesignator(designator) cl = self.db.getclass(classname) props = props_from_args(self.db, cl, args, itemid) # convert types for p in props.keys(): if not self.db.security.hasPermission('Edit', self.db.getuid(), classname, p, itemid): raise Unauthorised('Permission to edit %s of %s denied' % (p, designator)) try: result = cl.set(itemid, **props) self.db.commit() except (TypeError, IndexError, ValueError) as message: # The exception we get may be a real error, log the # traceback if we're debugging logger = logging.getLogger('roundup.xmlrpc') for l in format_exc().split('\n'): logger.debug(l) raise UsageError(message) return result builtin_actions = dict(retire=actions.Retire, restore=actions.Restore) def action(self, name, *args): """Execute a named action.""" if name in self.actions: action_type = self.actions[name] elif name in self.builtin_actions: action_type = self.builtin_actions[name] else: raise Exception('action "%s" is not supported %s' % (name, ','.join(self.actions.keys()))) action = action_type(self.db, self.translator) return action.execute(*args) class RoundupDispatcher(SimpleXMLRPCDispatcher): """RoundupDispatcher bridges from cgi.client to RoundupInstance. It expects user authentication to be done.""" def __init__(self, db, actions, translator, allow_none=False, encoding=None): SimpleXMLRPCDispatcher.__init__(self, allow_none, encoding) self.register_instance(RoundupInstance(db, actions, translator)) self.register_multicall_functions() def dispatch(self, input): return self._marshaled_dispatch(input) def _dispatch(self, method, params): retn = SimpleXMLRPCDispatcher._dispatch(self, method, params) retn = translate(retn) return retn
