goa/__init__.py
changeset 0 b97547f5f1fa
child 447 0e52d72104a6
equal deleted inserted replaced
-1:000000000000 0:b97547f5f1fa
       
     1 """cubicweb on google appengine
       
     2 
       
     3 :organization: Logilab
       
     4 :copyright: 2001-2008 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
       
     5 :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
       
     6 """
       
     7 __docformat__ = "restructuredtext en"
       
     8 
       
     9 
       
    10 from datetime import datetime, time, date
       
    11 from mx.DateTime import DateTime, Date, Time
       
    12 
       
    13 def mx2datetime(mxobj, yamstype):
       
    14     """converts a mx date object (DateTime, Date or Time) into a
       
    15     regular python datetime object
       
    16     """
       
    17     #if yamstype == 'Datetime':
       
    18     # don't use date, db model doesn't actually support it, only datetime
       
    19     return datetime(mxobj.year, mxobj.month, mxobj.day,
       
    20                     mxobj.hour, mxobj.minute, int(mxobj.second))
       
    21 #     elif yamstype == 'Date':
       
    22 #         return date(mxobj.year, mxobj.month, mxobj.day)
       
    23 #     # XXX don't support time either, what should we do here ?
       
    24 #     return time(mxobj.hour, mxobj.minute, int(mxobj.second))
       
    25 
       
    26 def datetime2mx(datetimeobj, yamstype=None):
       
    27     """converts a mx date object (DateTime, Date or Time) into a
       
    28     regular python datetime object
       
    29     """
       
    30     if yamstype is None:
       
    31         yamstype = guess_yamstype_from_date(datetimeobj)
       
    32     assert yamstype is not None
       
    33     if yamstype == 'Datetime':
       
    34         # don't use date, db model doesn't actually support it, only datetime
       
    35         return DateTime(datetimeobj.year, datetimeobj.month, datetimeobj.day,
       
    36                         datetimeobj.hour, datetimeobj.minute, int(datetimeobj.second))
       
    37     elif yamstype == 'Date':
       
    38         return Date(datetimeobj.year, datetimeobj.month, datetimeobj.day)
       
    39     # XXX don't support time either, what should we do here ?
       
    40     return Time(datetimeobj.hour, datetimeobj.minute, int(datetimeobj.second))
       
    41 
       
    42 
       
    43 def guess_yamstype_for_date(datetimeobj):
       
    44     """guesses yams correct type according to `datetimeobj`'s type"""
       
    45     if isinstance(datetimeobj, datetime):
       
    46         return 'Datetime'
       
    47     elif isinstance(datetimeobj, date):
       
    48         return 'Date'
       
    49     elif isinstance(datetimeobj, time):
       
    50         return 'Time'
       
    51     return None
       
    52 
       
    53 
       
    54 def use_mx_for_dates(func):
       
    55     """decorator to convert func's return value into mx objects
       
    56     instead of datetime objects
       
    57     """
       
    58     def wrapper(*args, **kwargs):
       
    59         value = func(*args, **kwargs)
       
    60         yamstype = guess_yamstype_for_date(value)
       
    61         if yamstype is None:
       
    62             return value
       
    63         return datetime2mx(value, yamstype)
       
    64     return wrapper
       
    65 
       
    66 
       
    67 try:
       
    68     # WARNING: do not import the google's db module here since it will take
       
    69     #          precedence over our own db submodule
       
    70     from google.appengine.api.datastore import Key, Get, Query
       
    71     from google.appengine.api.datastore_errors import BadKeyError
       
    72 except ImportError:
       
    73     # not in google app environment
       
    74     pass
       
    75 else:
       
    76 
       
    77     import os    
       
    78     _SS = os.environ.get('SERVER_SOFTWARE')
       
    79     if _SS is None:
       
    80         MODE = 'test'
       
    81     elif _SS.startswith('Dev'):
       
    82         MODE = 'dev'
       
    83     else:
       
    84         MODE = 'prod'
       
    85 
       
    86     from cubicweb.server import SOURCE_TYPES
       
    87     from cubicweb.goa.gaesource import GAESource
       
    88     SOURCE_TYPES['gae'] = GAESource
       
    89 
       
    90     
       
    91     def do_monkey_patch():
       
    92 
       
    93         # monkey patch yams Bytes validator since it should take a bytes string with gae
       
    94         # and not a StringIO
       
    95         def check_bytes(eschema, value):
       
    96             """check value is a bytes string"""
       
    97             return isinstance(value, str)
       
    98         from yams import constraints
       
    99         constraints.BASE_CHECKERS['Bytes'] = check_bytes
       
   100 
       
   101         def rql_for_eid(eid):
       
   102             return 'Any X WHERE X eid "%s"' % eid
       
   103         from cubicweb.common import uilib
       
   104         uilib.rql_for_eid = rql_for_eid
       
   105 
       
   106         def typed_eid(eid):
       
   107             try:
       
   108                 return str(Key(eid))
       
   109             except BadKeyError:
       
   110                 raise ValueError(eid)
       
   111         import cubicweb
       
   112         cubicweb.typed_eid = typed_eid
       
   113 
       
   114         # XXX monkey patch cubicweb.schema.CubicWebSchema to have string eid with
       
   115         #     optional cardinality (since eid is set after the validation)
       
   116         
       
   117         import re
       
   118         from yams import buildobjs as ybo
       
   119         
       
   120         def add_entity_type(self, edef):
       
   121             edef.name = edef.name.encode()
       
   122             assert re.match(r'[A-Z][A-Za-z0-9]*[a-z]+[0-9]*$', edef.name), repr(edef.name)
       
   123             eschema = super(CubicWebSchema, self).add_entity_type(edef)
       
   124             if not eschema.is_final():
       
   125                 # automatically add the eid relation to non final entity types 
       
   126                 rdef = ybo.RelationDefinition(eschema.type, 'eid', 'Bytes',
       
   127                                               cardinality='?1', uid=True)
       
   128                 self.add_relation_def(rdef)
       
   129                 rdef = ybo.RelationDefinition(eschema.type, 'identity', eschema.type)
       
   130                 self.add_relation_def(rdef)
       
   131             self._eid_index[eschema.eid] = eschema
       
   132             return eschema
       
   133         
       
   134         from cubicweb.schema import CubicWebSchema
       
   135         CubicWebSchema.add_entity_type = add_entity_type
       
   136 
       
   137 
       
   138         # don't reset vreg on repository set_schema
       
   139         from cubicweb.server import repository
       
   140         orig_set_schema = repository.Repository.set_schema
       
   141         def set_schema(self, schema, resetvreg=True):
       
   142             orig_set_schema(self, schema, False)
       
   143         repository.Repository.set_schema = set_schema
       
   144         # deactivate function ensuring relation cardinality consistency
       
   145         repository.del_existing_rel_if_needed = lambda *args: None
       
   146 
       
   147         def get_cubes(self):
       
   148             """return the list of top level cubes used by this instance"""
       
   149             config = self.config
       
   150             cubes = config['included-cubes'] + config['included-yams-cubes']
       
   151             return config.expand_cubes(cubes)
       
   152         repository.Repository.get_cubes = get_cubes
       
   153         
       
   154         from rql import RQLHelper
       
   155         RQLHelper.simplify = lambda x,r: None
       
   156 
       
   157         # activate entity caching on the server side
       
   158 
       
   159         def set_entity_cache(self, entity):
       
   160             self._query_data.setdefault('_eid_cache', {})[entity.eid] = entity
       
   161 
       
   162         def entity_cache(self, eid):
       
   163             return self._query_data['_eid_cache'][eid]
       
   164 
       
   165         def drop_entity_cache(self, eid=None):
       
   166             if eid is None:
       
   167                 self._query_data['_eid_cache'] = {}
       
   168             elif '_eid_cache' in self._query_data:
       
   169                 self._query_data['_eid_cache'].pop(eid, None)
       
   170 
       
   171         def datastore_get(self, key):
       
   172             if isinstance(key, basestring):
       
   173                 key = Key(key)
       
   174             try:
       
   175                 gentity = self._query_data['_key_cache'][key]
       
   176                 #self.critical('cached %s', gentity)
       
   177             except KeyError:
       
   178                 gentity = Get(key)
       
   179                 #self.critical('Get %s', gentity)
       
   180                 self._query_data.setdefault('_key_cache', {})[key] = gentity
       
   181             return gentity
       
   182 
       
   183         def clear_datastore_cache(self, key=None):
       
   184             if key is None:
       
   185                 self._query_data['_key_cache'] = {}
       
   186             else:
       
   187                 if isinstance(key, basestring):
       
   188                     key = Key(key)
       
   189                 self._query_data['_key_cache'].pop(key, None)
       
   190 
       
   191         from cubicweb.server.session import Session
       
   192         Session.set_entity_cache = set_entity_cache
       
   193         Session.entity_cache = entity_cache
       
   194         Session.drop_entity_cache = drop_entity_cache
       
   195         Session.datastore_get = datastore_get
       
   196         Session.clear_datastore_cache = clear_datastore_cache
       
   197 
       
   198         from docutils.frontend import OptionParser
       
   199         # avoid a call to expanduser which is not available under gae
       
   200         def get_standard_config_files(self):
       
   201             return self.standard_config_files
       
   202         OptionParser.get_standard_config_files = get_standard_config_files