2 * py.js helpers and setup
4 openerp.web.pyeval = function (instance) {
5 instance.web.pyeval = {};
7 var obj = function () {};
8 obj.prototype = py.object;
9 var asJS = function (arg) {
10 if (arg instanceof obj) {
16 var datetime = py.PY_call(py.object);
17 datetime.datetime = py.type('datetime', null, {
18 __init__: function () {
19 var zero = py.float.fromJSON(0);
20 var args = py.PY_parseArgs(arguments, [
21 'year', 'month', 'day',
22 ['hour', zero], ['minute', zero], ['second', zero],
23 ['microsecond', zero], ['tzinfo', py.None]
25 for(var key in args) {
26 if (!args.hasOwnProperty(key)) { continue; }
27 this[key] = asJS(args[key]);
30 strftime: function () {
32 var args = py.PY_parseArgs(arguments, 'format');
33 return py.str.fromJSON(args.format.toJSON()
34 .replace(/%([A-Za-z])/g, function (m, c) {
36 case 'Y': return self.year;
37 case 'm': return _.str.sprintf('%02d', self.month);
38 case 'd': return _.str.sprintf('%02d', self.day);
39 case 'H': return _.str.sprintf('%02d', self.hour);
40 case 'M': return _.str.sprintf('%02d', self.minute);
41 case 'S': return _.str.sprintf('%02d', self.second);
43 throw new Error('ValueError: No known conversion for ' + m);
46 now: py.classmethod.fromJSON(function () {
48 return py.PY_call(datetime.datetime,
49 [d.getUTCFullYear(), d.getUTCMonth() + 1, d.getUTCDate(),
50 d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(),
51 d.getUTCMilliseconds() * 1000]);
53 today: py.classmethod.fromJSON(function () {
55 return py.PY_call(datetime.datetime,
56 [d.getUTCFullYear(), d.getUTCMonth() + 1, d.getUTCDate()]);
58 combine: py.classmethod.fromJSON(function () {
59 var args = py.PY_parseArgs(arguments, 'date time');
60 return py.PY_call(datetime.datetime, [
61 // FIXME: should use getattr
71 datetime.date = py.type('date', null, {
72 __init__: function () {
73 var args = py.PY_parseArgs(arguments, 'year month day');
74 this.year = asJS(args.year);
75 this.month = asJS(args.month);
76 this.day = asJS(args.day);
78 strftime: function () {
80 var args = py.PY_parseArgs(arguments, 'format');
81 return py.str.fromJSON(args.format.toJSON()
82 .replace(/%([A-Za-z])/g, function (m, c) {
84 case 'Y': return self.year;
85 case 'm': return _.str.sprintf('%02d', self.month);
86 case 'd': return _.str.sprintf('%02d', self.day);
88 throw new Error('ValueError: No known conversion for ' + m);
91 today: py.classmethod.fromJSON(function () {
94 datetime.date, [d.getUTCFullYear(), d.getUTCMonth() + 1, d.getUTCDate()]);
97 datetime.time = py.type('time', null, {
98 __init__: function () {
99 var zero = py.float.fromJSON(0);
100 var args = py.PY_parseArgs(arguments, [
101 ['hour', zero], ['minute', zero], ['second', zero], ['microsecond', zero],
106 if (!args.hasOwnProperty(k)) { continue; }
107 this[k] = asJS(args[k]);
112 var time = py.PY_call(py.object);
113 time.strftime = py.PY_def.fromJSON(function () {
114 // FIXME: needs PY_getattr
115 var d = py.PY_call(datetime.__getattribute__('datetime')
116 .__getattribute__('now'));
117 var args = [].slice.call(arguments);
118 return py.PY_call.apply(
119 null, [d.__getattribute__('strftime')].concat(args));
122 var relativedelta = py.type('relativedelta', null, {
123 __init__: function () {
124 this.ops = py.PY_parseArgs(arguments,
125 '* year month day hour minute second microsecond '
126 + 'years months weeks days hours minutes secondes microseconds '
127 + 'weekday leakdays yearday nlyearday');
129 __add__: function (other) {
130 if (py.PY_call(py.isinstance, [datetime.date]) !== py.True) {
131 return py.NotImplemented;
133 // TODO: test this whole mess
134 var year = asJS(this.ops.year) || asJS(other.year);
135 if (asJS(this.ops.years)) {
136 year += asJS(this.ops.years);
139 var month = asJS(this.ops.month) || asJS(other.month);
140 if (asJS(this.ops.months)) {
141 month += asJS(this.ops.months);
142 // FIXME: no divmod in JS?
153 var lastMonthDay = new Date(year, month, 0).getDate();
154 var day = asJS(this.ops.day) || asJS(other.day);
155 if (day > lastMonthDay) { day = lastMonthDay; }
156 var days_offset = ((asJS(this.ops.weeks) || 0) * 7) + (asJS(this.ops.days) || 0);
158 day = new Date(year, month-1, day + days_offset).getDate();
161 // TODO: hours, minutes, seconds? Not used in XML domains
163 // FIXME: use date.replace
164 return py.PY_call(datetime.date, [
165 py.float.fromJSON(year),
166 py.float.fromJSON(month),
167 py.float.fromJSON(day)
170 __radd__: function (other) {
171 return this.__add__(other);
174 __sub__: function (other) {
175 if (py.PY_call(py.isinstance, [datetime.date]) !== py.True) {
176 return py.NotImplemented;
178 // TODO: test this whole mess
179 var year = asJS(this.ops.year) || asJS(other.year);
180 if (asJS(this.ops.years)) {
181 year -= asJS(this.ops.years);
184 var month = asJS(this.ops.month) || asJS(other.month);
185 if (asJS(this.ops.months)) {
186 month -= asJS(this.ops.months);
187 // FIXME: no divmod in JS?
198 var lastMonthDay = new Date(year, month, 0).getDate();
199 var day = asJS(this.ops.day) || asJS(other.day);
200 if (day > lastMonthDay) { day = lastMonthDay; }
201 var days_offset = ((asJS(this.ops.weeks) || 0) * 7) + (asJS(this.ops.days) || 0);
203 day = new Date(year, month-1, day - days_offset).getDate();
206 // TODO: hours, minutes, seconds? Not used in XML domains
208 return py.PY_call(datetime.date, [
209 py.float.fromJSON(year),
210 py.float.fromJSON(month),
211 py.float.fromJSON(day)
214 __rsub__: function (other) {
215 return this.__sub__(other);
219 var eval_contexts = function (contexts, evaluation_context) {
220 evaluation_context = evaluation_context || {};
221 return _(contexts).reduce(function (result_context, ctx) {
222 // __eval_context evaluations can lead to some of `contexts`'s
223 // values being null, skip them as well as empty contexts
224 if (_.isEmpty(ctx)) { return result_context; }
228 evaluated = py.eval(ctx.__debug, evaluation_context);
230 case 'compound_context':
231 var eval_context = eval_contexts([ctx.__eval_context]);
232 evaluated = eval_contexts(
233 ctx.__contexts, _.extend({}, evaluation_context, eval_context));
236 // add newly evaluated context to evaluation context for following
238 _.extend(evaluation_context, evaluated);
239 return _.extend(result_context, evaluated);
240 }, _.extend({}, instance.session.user_context));
242 var eval_domains = function (domains, evaluation_context) {
243 var result_domain = [];
244 _(domains).each(function (domain) {
245 switch(domain.__ref) {
247 result_domain.push.apply(
248 result_domain, py.eval(domain.__debug, evaluation_context));
250 case 'compound_domain':
251 var eval_context = eval_contexts([domain.__eval_context]);
252 result_domain.push.apply(
253 result_domain, eval_domains(
254 domain.__domains, _.extend(
255 {}, evaluation_context, eval_context)));
258 result_domain.push.apply(result_domain, domain);
261 return result_domain;
263 var eval_groupbys = function (contexts, evaluation_context) {
264 var result_group = [];
265 _(contexts).each(function (ctx) {
270 evaluated = py.eval(ctx.__debug, evaluation_context);
272 case 'compound_context':
273 var eval_context = eval_contexts([ctx.__eval_context]);
274 evaluated = eval_contexts(
275 ctx.__contexts, _.extend({}, evaluation_context, eval_context));
278 group = evaluated.group_by;
279 if (!group) { return; }
280 if (typeof group === 'string') {
281 result_group.push(group);
282 } else if (group instanceof Array) {
283 result_group.push.apply(result_group, group);
285 throw new Error('Got invalid groupby {{'
286 + JSON.stringify(group) + '}}');
288 _.extend(evaluation_context, evaluated);
293 instance.web.pyeval.context = function () {
295 uid: py.float.fromJSON(instance.session.uid),
298 relativedelta: relativedelta,
299 current_date: py.PY_call(
300 time.strftime, [py.str.fromJSON('%Y-%m-%d')]),
305 * @param {String} type "domains", "contexts" or "groupbys"
306 * @param {Array} object domains or contexts to evaluate
307 * @param {Object} [context] evaluation context
309 instance.web.pyeval.eval = function (type, object, context) {
310 context = _.extend(instance.web.pyeval.context(), context || {});
311 context['context'] = py.dict.fromJSON(context);
314 case 'contexts': return eval_contexts(object, context);
315 case 'domains': return eval_domains(object, context);
316 case 'groupbys': return eval_groupbys(object, context);
318 throw new Error("Unknow evaluation type " + type)