Add module wfobjs to enable workflow in gae.
Add module vcard to enable usage of cube person in gae.
Add init file creation for cubes gae directory.
"""cubicweb on google appengine
:organization: Logilab
:copyright: 2001-2008 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
:contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
"""
__docformat__ = "restructuredtext en"
from datetime import datetime, time, date
from mx.DateTime import DateTime, Date, Time
def mx2datetime(mxobj, yamstype):
"""converts a mx date object (DateTime, Date or Time) into a
regular python datetime object
"""
#if yamstype == 'Datetime':
# don't use date, db model doesn't actually support it, only datetime
return datetime(mxobj.year, mxobj.month, mxobj.day,
mxobj.hour, mxobj.minute, int(mxobj.second))
# elif yamstype == 'Date':
# return date(mxobj.year, mxobj.month, mxobj.day)
# # XXX don't support time either, what should we do here ?
# return time(mxobj.hour, mxobj.minute, int(mxobj.second))
def datetime2mx(datetimeobj, yamstype=None):
"""converts a mx date object (DateTime, Date or Time) into a
regular python datetime object
"""
if yamstype is None:
yamstype = guess_yamstype_from_date(datetimeobj)
assert yamstype is not None
if yamstype == 'Datetime':
# don't use date, db model doesn't actually support it, only datetime
return DateTime(datetimeobj.year, datetimeobj.month, datetimeobj.day,
datetimeobj.hour, datetimeobj.minute, int(datetimeobj.second))
elif yamstype == 'Date':
return Date(datetimeobj.year, datetimeobj.month, datetimeobj.day)
# XXX don't support time either, what should we do here ?
return Time(datetimeobj.hour, datetimeobj.minute, int(datetimeobj.second))
def guess_yamstype_for_date(datetimeobj):
"""guesses yams correct type according to `datetimeobj`'s type"""
if isinstance(datetimeobj, datetime):
return 'Datetime'
elif isinstance(datetimeobj, date):
return 'Date'
elif isinstance(datetimeobj, time):
return 'Time'
return None
def use_mx_for_dates(func):
"""decorator to convert func's return value into mx objects
instead of datetime objects
"""
def wrapper(*args, **kwargs):
value = func(*args, **kwargs)
yamstype = guess_yamstype_for_date(value)
if yamstype is None:
return value
return datetime2mx(value, yamstype)
return wrapper
try:
# WARNING: do not import the google's db module here since it will take
# precedence over our own db submodule
from google.appengine.api.datastore import Key, Get, Query
from google.appengine.api.datastore_errors import BadKeyError
except ImportError:
# not in google app environment
pass
else:
import os
_SS = os.environ.get('SERVER_SOFTWARE')
if _SS is None:
MODE = 'test'
elif _SS.startswith('Dev'):
MODE = 'dev'
else:
MODE = 'prod'
from cubicweb.server import SOURCE_TYPES
from cubicweb.goa.gaesource import GAESource
SOURCE_TYPES['gae'] = GAESource
def do_monkey_patch():
# monkey patch yams Bytes validator since it should take a bytes string with gae
# and not a StringIO
def check_bytes(eschema, value):
"""check value is a bytes string"""
return isinstance(value, str)
from yams import constraints
constraints.BASE_CHECKERS['Bytes'] = check_bytes
def rql_for_eid(eid):
return 'Any X WHERE X eid "%s"' % eid
from cubicweb.common import uilib
uilib.rql_for_eid = rql_for_eid
def typed_eid(eid):
try:
return str(Key(eid))
except BadKeyError:
raise ValueError(eid)
import cubicweb
cubicweb.typed_eid = typed_eid
# XXX monkey patch cubicweb.schema.CubicWebSchema to have string eid with
# optional cardinality (since eid is set after the validation)
import re
from yams import buildobjs as ybo
def add_entity_type(self, edef):
edef.name = edef.name.encode()
assert re.match(r'[A-Z][A-Za-z0-9]*[a-z]+[0-9]*$', edef.name), repr(edef.name)
eschema = super(CubicWebSchema, self).add_entity_type(edef)
if not eschema.is_final():
# automatically add the eid relation to non final entity types
rdef = ybo.RelationDefinition(eschema.type, 'eid', 'Bytes',
cardinality='?1', uid=True)
self.add_relation_def(rdef)
rdef = ybo.RelationDefinition(eschema.type, 'identity', eschema.type)
self.add_relation_def(rdef)
self._eid_index[eschema.eid] = eschema
return eschema
from cubicweb.schema import CubicWebSchema
CubicWebSchema.add_entity_type = add_entity_type
# don't reset vreg on repository set_schema
from cubicweb.server import repository
orig_set_schema = repository.Repository.set_schema
def set_schema(self, schema, resetvreg=True):
orig_set_schema(self, schema, False)
repository.Repository.set_schema = set_schema
# deactivate function ensuring relation cardinality consistency
repository.del_existing_rel_if_needed = lambda *args: None
def get_cubes(self):
"""return the list of top level cubes used by this instance"""
config = self.config
cubes = config['included-cubes'] + config['included-yams-cubes']
return config.expand_cubes(cubes)
repository.Repository.get_cubes = get_cubes
from rql import RQLHelper
RQLHelper.simplify = lambda x,r: None
# activate entity caching on the server side
def set_entity_cache(self, entity):
self._query_data.setdefault('_eid_cache', {})[entity.eid] = entity
def entity_cache(self, eid):
return self._query_data['_eid_cache'][eid]
def drop_entity_cache(self, eid=None):
if eid is None:
self._query_data['_eid_cache'] = {}
elif '_eid_cache' in self._query_data:
self._query_data['_eid_cache'].pop(eid, None)
def datastore_get(self, key):
if isinstance(key, basestring):
key = Key(key)
try:
gentity = self._query_data['_key_cache'][key]
#self.critical('cached %s', gentity)
except KeyError:
gentity = Get(key)
#self.critical('Get %s', gentity)
self._query_data.setdefault('_key_cache', {})[key] = gentity
return gentity
def clear_datastore_cache(self, key=None):
if key is None:
self._query_data['_key_cache'] = {}
else:
if isinstance(key, basestring):
key = Key(key)
self._query_data['_key_cache'].pop(key, None)
from cubicweb.server.session import Session
Session.set_entity_cache = set_entity_cache
Session.entity_cache = entity_cache
Session.drop_entity_cache = drop_entity_cache
Session.datastore_get = datastore_get
Session.clear_datastore_cache = clear_datastore_cache
from docutils.frontend import OptionParser
# avoid a call to expanduser which is not available under gae
def get_standard_config_files(self):
return self.standard_config_files
OptionParser.get_standard_config_files = get_standard_config_files