Changeset 7161


Ignore:
Timestamp:
03/27/09 11:29:30 (6 years ago)
Author:
mrm41
Message:

cleanup, fixup, and documentation... Changed app.py enough that is should be independent of plone and more cmf site directed, so it should be possible to use it on any cmf site. Fixed scrubber.py so that it has onecontinuous conditional block (must have been a typo that worked before). Apparently restrictedTravese doesn't do unicode, so that needed fixed in surgeon.py.

Location:
users/mrm41/frustration/trunk/src/frustration
Files:
6 edited

Legend:

Unmodified
Added
Removed
  • users/mrm41/frustration/trunk/src/frustration/app.py

    r7159 r7161  
    77from zope import component, interface 
    88from zope.app.component.hooks import getSite 
     9from zope.app.component.interfaces import ISite 
    910 
    1011from interfaces import IApplicationAPI, IScrubber, ISurgeon 
     
    1415class ApplicationAPI(object): 
    1516    interface.implements(IApplicationAPI) 
    16     logger = getLogger('web services api') 
     17    logger = getLogger('WS API') 
    1718 
    1819    def __init__(self, context, request): 
     20        """Typical browser view instantiation.""" 
    1921        self.context = context 
    2022        self.request = request 
     
    2224 
    2325    def get_object(self, path='', attrs=[]): 
    24         surgery = self.surgeon(self.context, path) 
    25         obj = surgery.get_object() 
    26         self.logger.info("Gathering data for %s" % (str(obj))) 
     26        """ 
     27        @param path - string to the path of the wanted object 
     28        @param attrs - list of the wanted attributes returned by this method 
     29        """ 
     30        surgery = self.surgeon(self.context, path) 
     31        obj = surgery.get_object() 
     32        self.logger.info("- get_object - Gathering data for %s." % (obj)) 
    2733        data = {} 
    28         # XXX pumazi: this isn't the best solution 
    29         if IPloneSiteRoot.providedBy(obj) and getSite() == obj: 
    30             # duplicate code, see: _gather_data 
    31             data['id'] = {'required': 1, 'type': 'string', 'value': obj.getId()} 
    32             data['title'] = {'required': 1, 'type': 'string', 'value': obj.Title()} 
    33             # data['children'] = {'required': 0, 'type': 'lines', 'value': self.local_context.contentIds()} 
     34        if ISite.providedBy(obj): 
     35            data['id'] = {'required': 1, 'type': 'string', 'value': obj.id} 
     36            data['title'] = {'required': 1, 'type': 'string', 'value': obj.title} 
     37            data['description'] = {'required': 1, 'type': 'string', 'value': obj.description} 
    3438        else: 
    3539            data = surgery.gather_data(attrs) 
     
    3741 
    3842    def get_file_object(self, path='', attr=''): 
    39         # FIXME pumazi: We need to check if what we are inspecting is really 
    40         # a 'File' object. And whether or not the attribute is valid or is 
    41         # that assumed when we inspect if it is a 'File' object? 
    42         surgery = self.surgeon(self.context, path) 
     43        """ 
     44        @param path - string to the path of the wanted object 
     45        @param attr - attribute where the file subobject can be found on the object 
     46        """ 
     47        surgery = self.surgeon(self.context, path) 
     48        self.logger.info("- get_file_object - Gathering file data for %s." % (surgery.get_object())) 
    4349        return surgery.gather_file_data(attr) 
    4450 
    4551    def post_object(self, params, type_name, path=''): 
    4652        """ 
    47         @param params dictionary of attribute names and their respective values 
    48         @param type_name string representation of the content type wanted one wants to create 
     53        @param params - dictionary of attribute names and their respective values 
     54        @param type_name - string representation of the content type wanted one wants to create 
    4955            see 'get_types' for valid type names 
    50         @param path string to the path of the wanted object 
    51         """ 
    52         # params vs path for id 
     56        @param path - string to the path of the wanted object 
     57        """ 
    5358        # obtain posted_id, posted_path and path 
    5459        if 'id' in params: 
     
    6974                posted_id = path[0] 
    7075                path = u'' 
    71         # verify type is a valid addible content type 
    72          
    73         # get the local_context 
    74         surgery = self.surgeon(self.context, path) 
    75         obj = surgery.get_object() 
    76         # create the object 
     76        # TODO pumazi: verify type is a valid addible content type 
     77 
     78        surgery = self.surgeon(self.context, path) 
     79        obj = surgery.get_object() 
     80 
     81        self.logger.info("- post_object - Creating object %s of %s type." % (obj, type_name)) 
     82 
    7783        try: 
    7884            new_id = obj.invokeFactory(type_name=type_name, id=posted_id) 
     
    8288            return "FAILED" 
    8389        results = {'id': posted_id} 
    84         # if other params besides id then call put params (put_object) 
     90        # if other params besides id then put params (put_object) 
    8591        putted_results = {} 
    8692        if params: 
     
    9298 
    9399    def put_object(self, params, path=''): 
    94         # valid local_context (the results of path or context)? 
    95         surgery = self.surgeon(self.context, path) 
    96         obj = surgery.get_object() 
    97         # this is basically the second half of set_object and it is in working order 
     100        """ 
     101        @param params - dictionary of attribute names and their respective values 
     102        @param path - string to the path of the wanted object 
     103        """ 
     104        surgery = self.surgeon(self.context, path) 
     105        obj = surgery.get_object() 
     106        self.logger.info("- put_object - Setting data on %s." % (obj)) 
    98107        if obj: 
    99             # object exists, let's set the params on it if possible 
    100108            results = surgery.set_properties(params) 
    101109            # TODO pumazi: notifiers and possibly reindex 
     
    103111 
    104112    def delete_object(self, path=''): 
    105         pass 
    106         # valid local_context (the results of path or context)? 
     113        """ 
     114        @param path - string to the path of the wanted object 
     115        """ 
    107116        path = path.strip('/') 
    108117        delete_path = path 
     
    113122        surgery = self.surgeon(self.context, path) 
    114123        parent_obj = surgery.get_object() 
    115         # delete the object 
    116124        parent_obj.manage_delObjects(delete_id) 
    117         # return True or False 
     125 
    118126        if getattr(parent_obj, delete_id, None): 
    119127            return False 
    120128        else: 
     129            self.logger.info("- delete_object - Deleting %s from %s." % (delete_id, parent_obj)) 
    121130            return True 
    122131 
    123     def get_schema(self, path='', type=False): 
     132    def get_schema(self, path='', type_=False): 
     133        """ 
     134        @param path 
     135            - string to the path of the wanted object 
     136            ** or ** 
     137            - the content type name if 'type_' is True 
     138        @param type - conditional flag for viewing a schema for a given 
     139            type 'path' 
     140        """ 
    124141        # TODO pumazi: may want to eventually cache the schema types so that 
    125142        # objects don't need created on every types enabled call 
    126         if type: 
     143        if type_: 
    127144            site = getSite() 
    128145            uid = 'tmp_'+path+'_'+str(random.randint(1, 1000000)) 
    129146            path = site.invokeFactory(type_name=path, id=uid) 
     147            self.logger.info("- get_schema - Getting schema for %s type with temporary name %s on %s." % (path, uid, site)) 
    130148            tmp = self.surgeon(self.context, path) 
    131149            skeleton = tmp.build_skeleton() 
    132150            site.manage_delObjects(uid) 
     151             
    133152        else: 
    134153            surgery = self.surgeon(self.context, path) 
    135154            skeleton = surgery.build_skeleton() 
     155            self.logger.info("- get_schema - Getting schema for %s." % (surgery.get_object())) 
    136156        return skeleton 
    137157 
    138158    def get_types(self, available=''): 
    139         portal_state = component.getMultiAdapter((self.context, self.request), 
    140                                                  name=u'plone_portal_state') 
    141         portal = portal_state.portal() 
    142         return portal.portal_factory.getFactoryTypes().keys() 
     159        """ 
     160        @param available - NotImplemented 
     161        """ 
     162        self.logger.info("- get_types - Getting type names.") 
     163        return getSite().portal_factory.getFactoryTypes().keys() 
    143164 
    144165    def get_workflow(self, path=''): 
     166        """ 
     167        @param path - string to the path of the wanted object 
     168        """ 
    145169        surgery = self.surgeon(self.context, path) 
    146170        obj = surgery.get_object() 
     
    148172        results = {} 
    149173 
     174        self.logger.info("- get_workflow - Getting workflow state for %s." % (obj)) 
     175 
    150176        results['state'] = current_state = portal_workflow.getInfoFor(obj, 'review_state') 
    151         # get content type 
    152177        obj_content_type = obj.getTypeInfo().getId() 
    153         # get workflow chain for that type 
    154178        chains = portal_workflow.getChainForPortalType(obj_content_type) 
    155179 
     
    166190 
    167191    def set_workflow(self, transition, path=''): 
    168         surgery = self.surgeon(self.context, path) 
     192        """ 
     193        @param transition - string representing the workflow transition action 
     194        @param path - string to the path of the wanted object 
     195        """ 
     196        surgery = self.surgeon(self.context, path) 
     197        obj = surgery.get_object() 
    169198        portal_workflow = getSite().portal_workflow 
    170199 
     200        self.logger.info("- set_workflow - Transitioning (%s) workflow state for %s." % (transition, obj)) 
     201 
    171202        # action/transition verification/validation is done in doActionFor 
    172         portal_workflow.doActionFor(surgery.get_object(), transition) 
     203        portal_workflow.doActionFor(obj, transition) 
    173204        return 
    174205 
    175206    def query(self, filtr={}): 
     207        """ 
     208        @param filtr - search criteria given to filter the results 
     209        """ 
    176210        masking = {'UID': None, 
    177211                   'cmf_uid': None, 
     
    201235            prep_brains.append(grey_matter) 
    202236        jarred_brains = [] 
    203         # FIXME pumazi: feels like soemthing is wrong with the instanciation of a utility 
    204237        scrubber = component.getUtility(IScrubber)() 
    205238        for b in prep_brains: 
    206239            jarred_brains.append(scrubber.dict_scrub(b)) 
     240        self.logger.info("- query - Searching catalog with this search criteria: %s." % (filtr)) 
    207241        return jarred_brains 
    208  
    209     # MONKEY BITE!!! 
    210     # def getPhysicalPath(self): 
    211     #     if hasattr(self, 'local_context'): 
    212     #         if isinstance(self.local_context.aq_parent.aq_inner, ApplicationAPI): 
    213     #             return self.local_context.aq_parent.aq_inner.aq_parent.aq_inner.getPhysicalPath() 
    214     #         else: 
    215     #             return self.local_context.aq_parent.aq_inner.getPhysicalPath() 
    216     #     else: 
    217     #         return self.context.getPhysicalPath() 
    218  
    219     def debug(self, path=''): 
    220         surgery = self.surgeon(self.context, path) 
    221         import ipdb; ipdb.set_trace() 
    222         return None 
  • users/mrm41/frustration/trunk/src/frustration/configure.zcml

    r7159 r7161  
    8383            attribute="set_workflow" 
    8484            /> 
    85         <browser:page 
    86             name="api_debug" 
    87             attribute="debug" 
    88             /> 
    8985    </browser:pages> 
    9086 
  • users/mrm41/frustration/trunk/src/frustration/interfaces.py

    r7159 r7161  
    7676    def delete_object(path=''): 
    7777        """ 
    78         Delete the given path or context.""" 
     78        Delete the given path or context. 
     79        """ 
    7980 
    8081    def get_schema(path='', type=False): 
     
    111112        """search for an object""" 
    112113 
    113     def getPhysicalPath(): 
    114         """Monkey BITE! This is a fix for acquisition. 
    115         getPhysicalPath is supposed to print the id of the current object 
    116         to give a full path listing to the object. Since the API sits between 
    117         the given (path or local_context), it must have a getPhysicalPath or at least 
    118         a way to passover itself without including its id. 
    119         """ 
    120  
    121     def debug(path=''): 
    122         """Temporary method for debugging a given path. 
    123         """ 
    124  
    125114 
    126115class IScrubber(Interface): 
    127     """ 
     116    """This utility is intended to scrub a data structure clean so that an can be 
     117    marshalled for whatever web service is requesting the data structure. 
    128118    """ 
    129119 
    130120    def dict_scrub(data): 
    131         """ 
     121        """This method will clean a dictionary and bring any of its data types to 
     122        the standard built-in types or types that are known to marshall. 
    132123        """ 
    133124 
  • users/mrm41/frustration/trunk/src/frustration/scrubber.py

    r7159 r7161  
    11from zope import interface 
    2 from DateTime.DateTime import DateTime 
    32from zope.i18nmessageid import message 
    43 
     
    98 
    109    def dict_scrub(self, data): 
     10        """ 
     11        This method will scrub a the 'data' dictionary of any values that can not 
     12        be marshalled (e.g. i18n Messages). Additionally it prepares all the key 
     13        value pairs for transport by converting all strings to unicode. 
     14         
     15        @param data - dictionary to be scrubbed 
     16         
     17        DocTest 
     18        ------- 
     19        We need to create some example data 
     20         
     21            >>> msg = message.Message("hello world") 
     22            >>> text1 = "hallo welt" # german 
     23            >>> text2 = u"bonjour tout le monde" # french 
     24            >>> dict1 = {'spring': 'slinky', 'stick': u'cue'} 
     25         
     26        Now from this example data we would the dictionary to hand to dict_scrub 
     27         
     28            >>> ddata = {'greeting': msg, 'sometext': text1, 'moretext': text2, 'misc': dict1} 
     29         
     30        Run it though the dictionary scrubber 
     31         
     32            >>> dict_scrub(ddata) 
     33            {u'misc': {u'spring': u'slinky', u'stick': u'cue'}, u'greeting': u'hello world', u'moretext': u'bonjour tout le monde', u'sometext': u'hallo welt'} 
     34        """ 
    1135        # TODO pumazi: add language support (il8n) 
    1236        results = {} 
     
    1438            if type(data[k]) == str: 
    1539                results[unicode(k)] = unicode(data[k], 'utf-8') 
    16             if type(data[k]) == message.Message: 
     40            elif type(data[k]) == message.Message: 
    1741                results[unicode(k)] = unicode(data[k].encode('utf-8')) 
    1842            elif type(data[k]) == dict: 
  • users/mrm41/frustration/trunk/src/frustration/surgeon.py

    r7159 r7161  
    1111 
    1212    def __init__(self, context, path): 
     13        """ 
     14        @param context - fallback if path is 'None' or method of getting the object from the path 
     15        @param path - string to the path of the wanted object 
     16        """ 
    1317        if not path: 
    1418            found_object = context 
    15         elif type(path) == str or type(path) == unicode: 
     19        elif type(path) == str: 
    1620            try: 
    1721                found_object = context.restrictedTraverse(path) 
     22            except KeyError: 
     23                raise NotFound(context, path) 
     24        elif type(path) == unicode: 
     25            try: 
     26                found_object = context.restrictedTraverse(str(path)) 
    1827            except KeyError: 
    1928                raise NotFound(context, path) 
     
    2635    def _set_unknown(self, attr, value): 
    2736        """_set_unknown is a private method used to set a property that is of an unknown 
    28         type (e.g. BaseUnit, File, etc.).""" 
     37        type (e.g. BaseUnit, File, etc.). 
     38         
     39        @param attr - the attribute name where value should be set 
     40        @param value - the value to be set 
     41        """ 
    2942        if isinstance(self.object[attr], BaseUnit): 
    3043            self.object[attr].update(value, self.object[attr]) 
     
    3649 
    3750    def build_skeleton(self, filtr=[]): 
     51        """ 
     52        @param filtr - list of attribute names that will make up the skeleton 
     53        """ 
    3854        # this should be type agnostic (Archtypes, zope3 schemas, ZClasses, etc.) 
    3955        # built for archtypes atm 
     
    117133            else: 
    118134                skeleton[k]['value'] = self.object[k] 
    119         # if IContainer.providedBy(self.object): 
    120         #     # TODO pumazi: add depth support (parent->child->child_of_child) 
    121         #     skeleton['children'] = {'required': 0, 'type': 'lines', 'value': self.object.keys()} 
    122135        return skeleton 
    123136 
    124137    def set_properties(self, params): 
    125         rejected = {'failure': {}, 'success': {}} 
     138        results = {'failure': {}, 'success': {}} 
    126139        default_set = self._set_unknown 
    127140        skeleton = self.build_skeleton() 
     
    143156            if p in skeleton.keys() and p != 'id': 
    144157                if not params[p] and skeleton[p]['required']: 
    145                     rejected['failure'][p] = skeleton[p]['value'] = params[p] 
     158                    results['failure'][p] = skeleton[p]['value'] = params[p] 
    146159                else: 
    147160                    # For future reference, keep in mind that setters and 
     
    150163                    # are two different variables. Fault: DublinCore 
    151164                    psuedo_switch.get(p, default_set)(p, params[p]) 
    152                     # XXX pumazi: used for some kind of output 
    153                     rejected['success'][p] = skeleton[p] 
     165                    results['success'][p] = skeleton[p] 
    154166            else: 
    155                 rejected['failure'][p] = skeleton[p]['value'] = params[p] 
    156         rejected['success'] = self.gather_data(rejected['success']) 
    157         return rejected 
     167                results['failure'][p] = skeleton[p]['value'] = params[p] 
     168        results['success'] = self.gather_data(results['success']) 
     169        return results 
  • users/mrm41/frustration/trunk/src/frustration/tests/test_all.py

    r6890 r7161  
    4444        #    test_class=TestCase), 
    4545 
    46         ZopeTestCase.FunctionalDocFileSuite( 
    47             'sys.txt', package='frustration', 
    48             test_class=TestCase, 
    49             globs=dict(interact=interlude.interact)), 
    50  
    51         ZopeTestCase.FunctionalDocFileSuite( 
    52             'app.txt', package='frustration', 
    53             test_class=TestCase, 
    54             globs=dict(interact=interlude.interact)), 
    55  
    56         ZopeTestCase.FunctionalDocFileSuite( 
    57             'plone.txt', package='frustration', 
    58             test_class=TestCase, 
    59             globs=dict(interact=interlude.interact)), 
    60  
    61         ]) 
     46        # ZopeTestCase.FunctionalDocFileSuite( 
     47        #     'sys.txt', package='frustration', 
     48        #     test_class=TestCase, 
     49        #     globs=dict(interact=interlude.interact)), 
     50        #  
     51        # ZopeTestCase.FunctionalDocFileSuite( 
     52        #     'app.txt', package='frustration', 
     53        #     test_class=TestCase, 
     54        #     globs=dict(interact=interlude.interact)), 
     55        #  
     56        # ZopeTestCase.FunctionalDocFileSuite( 
     57        #     'plone.txt', package='frustration', 
     58        #     test_class=TestCase, 
     59        #     globs=dict(interact=interlude.interact)), 
     60        #  
     61        # ]) 
    6262 
    6363if __name__ == '__main__': 
Note: See TracChangeset for help on using the changeset viewer.