"static/lib/underscore/underscore.string.js",
"static/lib/backbone/backbone.js",
"static/lib/cleditor/jquery.cleditor.js",
- "static/lib/py.js/lib/py.js",
+ "static/lib/py.js/lib/py.js",
"static/src/js/boot.js",
+ "static/src/js/testing.js",
+ "static/src/js/pyeval.js",
"static/src/js/corelib.js",
"static/src/js/coresetup.js",
"static/src/js/dates.js",
id: _.uniqueId('r')
};
var deferred = $.Deferred();
- this.trigger('request', url, payload);
- var aborter = params.aborter;
- delete params.aborter;
+ if (! options.shadow)
+ this.trigger('request', url, payload);
- var request = this.rpc_function(url, payload).done(
+ var request;
+ if (url.url === '/web/session/eval_domain_and_context') {
+ // intercept eval_domain_and_context
+ request = instance.web.pyeval.eval_domains_and_contexts(
+ params)
+ } else {
+ request = this.rpc_function(url, payload);
+ }
- request.then(function (response, textStatus, jqXHR) {
- self.trigger('response', response);
++ request.then(
+ function (response, textStatus, jqXHR) {
+ if (! options.shadow)
+ self.trigger('response', response);
if (!response.error) {
- if (url.url === '/web/session/eval_domain_and_context') {
- self.test_eval(params, response.result);
- }
deferred.resolve(response["result"], textStatus, jqXHR);
} else if (response.error.data.type === "session_invalid") {
self.uid = false;
} else {
deferred.reject(response.error, $.Event());
}
- }
- ).fail(
+ },
function(jqXHR, textStatus, errorThrown) {
- self.trigger('error');
+ if (! options.shadow)
+ self.trigger('response_failed', jqXHR);
var error = {
code: -32098,
message: "XmlHttpRequestError " + errorThrown,
kwargs = args;
args = [];
}
+ instance.web.pyeval.ensure_evaluated(args, kwargs);
- return instance.session.rpc('/web/dataset/call_kw', {
+ var debug = instance.session.debug ? '/'+this.name+':'+method : '';
+ return instance.session.rpc('/web/dataset/call_kw' + debug, {
model: this.name,
method: method,
args: args,
--- /dev/null
+ // Test support structures and methods for OpenERP
+ openerp.testing = {};
+ (function (testing) {
+ var dependencies = {
- corelib: [],
++ pyeval: [],
++ corelib: ['pyeval'],
+ coresetup: ['corelib'],
+ data: ['corelib', 'coresetup'],
+ dates: [],
+ formats: ['coresetup', 'dates'],
+ chrome: ['corelib', 'coresetup'],
+ views: ['corelib', 'coresetup', 'data', 'chrome'],
+ search: ['data', 'coresetup', 'formats'],
+ list: ['views', 'data'],
+ form: ['data', 'views', 'list', 'formats'],
+ list_editable: ['list', 'form', 'data'],
+ };
+
+ testing.dependencies = window['oe_all_dependencies'] || [];
+ testing.current_module = null;
+ testing.templates = { };
+ testing.add_template = function (name) {
+ var xhr = QWeb2.Engine.prototype.get_xhr();
+ xhr.open('GET', name, false);
+ xhr.send(null);
+ (testing.templates[testing.current_module] =
+ testing.templates[testing.current_module] || [])
+ .push(xhr.responseXML);
+ };
+ /**
+ * Function which does not do anything
+ */
+ testing.noop = function () { };
+ /**
+ * Alter provided instance's ``session`` attribute to make response
+ * mockable:
+ *
+ * * The ``responses`` parameter can be used to provide a map of (RPC)
+ * paths (e.g. ``/web/view/load``) to a function returning a response
+ * to the query.
+ * * ``instance.session`` grows a ``responses`` attribute which is
+ * a map of the same (and is in fact initialized to the ``responses``
+ * parameter if one is provided)
+ *
+ * Note that RPC requests to un-mocked URLs will be rejected with an
+ * error message: only explicitly specified urls will get a response.
+ *
+ * Mocked sessions will *never* perform an actual RPC connection.
+ *
+ * @param instance openerp instance being initialized
+ * @param {Object} [responses]
+ */
+ testing.mockifyRPC = function (instance, responses) {
+ var session = instance.session;
+ session.responses = responses || {};
+ session.rpc_function = function (url, payload) {
+ var fn, params;
+ var needle = payload.params.model + ':' + payload.params.method;
+ if (url.url === '/web/dataset/call_kw'
+ && needle in this.responses) {
+ fn = this.responses[needle];
+ params = [
+ payload.params.args || [],
+ payload.params.kwargs || {}
+ ];
+ } else {
+ fn = this.responses[url.url];
+ params = [payload];
+ }
+
+ if (!fn) {
+ return $.Deferred().reject({}, 'failed',
+ _.str.sprintf("Url %s not found in mock responses, with arguments %s",
+ url.url, JSON.stringify(payload.params))
+ ).promise();
+ }
+ try {
+ return $.when(fn.apply(null, params)).then(function (result) {
+ // Wrap for RPC layer unwrapper thingy
+ return {result: result};
+ });
+ } catch (e) {
+ // not sure why this looks like that
+ return $.Deferred().reject({}, 'failed', String(e));
+ }
+ };
+ };
+
+ var StackProto = {
+ execute: function (fn) {
+ var args = [].slice.call(arguments, 1);
+ // Warning: here be dragons
+ var i = 0, setups = this.setups, teardowns = this.teardowns;
+ var d = $.Deferred();
+
+ var succeeded, failed;
+ var success = function () {
+ succeeded = _.toArray(arguments);
+ return teardown();
+ };
+ var failure = function () {
+ // save first failure
+ if (!failed) {
+ failed = _.toArray(arguments);
+ }
+ // chain onto next teardown
+ return teardown();
+ };
+
+ var setup = function () {
+ // if setup to execute
+ if (i < setups.length) {
+ var f = setups[i] || testing.noop;
+ $.when(f.apply(null, args)).then(function () {
+ ++i;
+ setup();
+ }, failure);
+ } else {
+ $.when(fn.apply(null, args)).then(success, failure);
+ }
+ };
+ var teardown = function () {
+ // if teardown to execute
+ if (i > 0) {
+ var f = teardowns[--i] || testing.noop;
+ $.when(f.apply(null, args)).then(teardown, failure);
+ } else {
+ if (failed) {
+ d.reject.apply(d, failed);
+ } else if (succeeded) {
+ d.resolve.apply(d, succeeded);
+ } else {
+ throw new Error("Didn't succeed or fail?");
+ }
+ }
+ };
+ setup();
+
+ return d;
+ },
+ push: function (setup, teardown) {
+ return _.extend(Object.create(StackProto), {
+ setups: this.setups.concat([setup]),
+ teardowns: this.teardowns.concat([teardown])
+ });
+ },
+ unshift: function (setup, teardown) {
+ return _.extend(Object.create(StackProto), {
+ setups: [setup].concat(this.setups),
+ teardowns: [teardown].concat(this.teardowns)
+ });
+ }
+ };
+ /**
+ *
+ * @param {Function} [setup]
+ * @param {Function} [teardown]
+ * @return {*}
+ */
+ testing.Stack = function (setup, teardown) {
+ return _.extend(Object.create(StackProto), {
+ setups: setup ? [setup] : [],
+ teardowns: teardown ? [teardown] : []
+ });
+ };
+
+ var db = window['oe_db_info'];
+ testing.section = function (name, options, body) {
+ if (_.isFunction(options)) {
+ body = options;
+ options = {};
+ }
+ _.defaults(options, {
+ setup: testing.noop,
+ teardown: testing.noop
+ });
+
+ QUnit.module(testing.current_module + '.' + name, {_oe: options});
+ body(testing.case);
+ };
+ testing.case = function (name, options, callback) {
+ if (_.isFunction(options)) {
+ callback = options;
+ options = {};
+ }
+
+ var module = testing.current_module;
+ var module_index = _.indexOf(testing.dependencies, module);
+ var module_deps = testing.dependencies.slice(
+ // If module not in deps (because only tests, no JS) -> indexOf
+ // returns -1 -> index becomes 0 -> replace with ``undefined`` so
+ // Array#slice returns a full copy
+ 0, module_index + 1 || undefined);
+
+ // Serialize options for this precise test case
+ // WARNING: typo is from jquery, do not fix!
+ var env = QUnit.config.currentModuleTestEnviroment;
+ // section setup
+ // case setup
+ // test
+ // case teardown
+ // section teardown
+ var case_stack = testing.Stack()
+ .push(env._oe.setup, env._oe.teardown)
+ .push(options.setup, options.teardown);
+ var opts = _.defaults({}, options, env._oe);
+ // FIXME: if this test is ignored, will still query
+ if (opts.rpc === 'rpc' && !db) {
+ QUnit.config.autostart = false;
+ db = {
+ source: null,
+ supadmin: null,
+ password: null
+ };
+ var $msg = $('<form style="margin: 0 1em 1em;">')
+ .append('<h3>A test needs to clone a database</h3>')
+ .append('<h4>Please provide the source clone information</h4>')
+ .append(' Source DB: ').append('<input name="source">').append('<br>')
+ .append(' DB Password: ').append('<input name="supadmin">').append('<br>')
+ .append('Admin Password: ').append('<input name="password">').append('<br>')
+ .append('<input type="submit" value="OK"/>')
+ .submit(function (e) {
+ e.preventDefault();
+ e.stopPropagation();
+ db.source = $msg.find('input[name=source]').val();
+ db.supadmin = $msg.find('input[name=supadmin]').val();
+ db.password = $msg.find('input[name=password]').val();
+ QUnit.start();
+ $.unblockUI();
+ });
+ $.blockUI({
+ message: $msg,
+ css: {
+ fontFamily: 'monospace',
+ textAlign: 'left',
+ whiteSpace: 'pre-wrap',
+ cursor: 'default'
+ }
+ });
+ }
+
+ QUnit.test(name, function () {
+ var instance;
+ if (!opts.dependencies) {
+ instance = openerp.init(module_deps);
+ } else {
+ // empty-but-specified dependencies actually allow running
+ // without loading any module into the instance
+
+ // TODO: clean up this mess
+ var d = opts.dependencies.slice();
+ // dependencies list should be in deps order, reverse to make
+ // loading order from last
+ d.reverse();
+ var di = 0;
+ while (di < d.length) {
+ var m = /^web\.(\w+)$/.exec(d[di]);
+ if (m) {
+ d[di] = m[1];
+ }
+ d.splice.apply(d, [di+1, 0].concat(
+ _(dependencies[d[di]]).reverse()));
+ ++di;
+ }
+
+ instance = openerp.init("fuck your shit, don't load anything you cunt");
+ _(d).chain()
+ .reverse()
+ .uniq()
+ .each(function (module) {
+ openerp.web[module](instance);
+ });
+ }
++ if (instance.session) {
++ instance.session.uid = 42;
++ }
+ if (_.isNumber(opts.asserts)) {
+ expect(opts.asserts);
+ }
+
+ if (opts.templates) {
+ for(var i=0; i<module_deps.length; ++i) {
+ var dep = module_deps[i];
+ var templates = testing.templates[dep];
+ if (_.isEmpty(templates)) { continue; }
+
+ for (var j=0; j < templates.length; ++j) {
+ instance.web.qweb.add_template(templates[j]);
+ }
+ }
+ }
+
+ var $fixture = $('#qunit-fixture');
+
+ var mock, async = false;
+ switch (opts.rpc) {
+ case 'mock':
+ async = true;
+ testing.mockifyRPC(instance);
+ mock = function (spec, handler) {
+ instance.session.responses[spec] = handler;
+ };
+ break;
+ case 'rpc':
+ async = true;
+ (function () {
+ // Bunch of random base36 characters
+ var dbname = 'test_' + Math.random().toString(36).slice(2);
+ // Add db setup/teardown at the start of the stack
+ case_stack = case_stack.unshift(function (instance) {
+ // FIXME hack: don't want the session to go through shitty loading process of everything
+ instance.session.session_init = testing.noop;
+ instance.session.load_modules = testing.noop;
+ instance.session.session_bind();
+ return instance.session.rpc('/web/database/duplicate', {
+ fields: [
+ {name: 'super_admin_pwd', value: db.supadmin},
+ {name: 'db_original_name', value: db.source},
+ {name: 'db_name', value: dbname}
+ ]
+ }).then(function (result) {
+ if (result.error) {
+ return $.Deferred().reject(result.error).promise();
+ }
+ return instance.session.session_authenticate(
+ dbname, 'admin', db.password, true);
+ });
+ }, function (instance) {
+ return instance.session.rpc('/web/database/drop', {
+ fields: [
+ {name: 'drop_pwd', value: db.supadmin},
+ {name: 'drop_db', value: dbname}
+ ]
+ }).then(function (result) {
+ if (result.error) {
+ return $.Deferred().reject(result.error).promise();
+ }
+ return result;
+ });
+ });
+ })();
+ }
+
+ // Always execute tests asynchronously
+ stop();
+ var timeout;
+ case_stack.execute(function () {
+ var result = callback.apply(null, arguments);
+ if (!(result && _.isFunction(result.then))) {
+ if (async) {
+ ok(false, "asynchronous test cases must return a promise");
+ }
+ } else {
+ if (!_.isNumber(opts.asserts)) {
+ ok(false, "asynchronous test cases must specify the "
+ + "number of assertions they expect");
+ }
+ }
+
+ return $.Deferred(function (d) {
+ $.when(result).then(function () {
+ d.resolve.apply(d, arguments)
+ }, function () {
+ d.reject.apply(d, arguments);
+ });
+ if (async || (result && result.then)) {
+ // async test can be either implicit async (rpc) or
+ // promise-returning
+ timeout = setTimeout(function () {
+ QUnit.config.semaphore = 1;
+ d.reject({message: "Test timed out"});
+ }, 2000);
+ }
+ });
+ }, instance, $fixture, mock).always(function () {
+ if (timeout) { clearTimeout(timeout); }
+ start();
+ }).fail(function (error) {
+ if (options.fail_on_rejection === false) {
+ return;
+ }
+ var message;
+ if (typeof error !== 'object'
+ || typeof error.message !== 'string') {
+ message = JSON.stringify([].slice.apply(arguments));
+ } else {
+ message = error.message;
+ if (error.data && error.data.debug) {
+ message += '\n\n' + error.data.debug;
+ }
+ }
+
+ ok(false, message);
+ });
+ });
+ };
+ })(openerp.testing);
- $(document).ready(function () {
- var openerp;
-
- module("eval.types", {
- setup: function () {
- openerp = window.openerp.testing.instanceFor('coresetup');
- openerp.session.uid = 42;
- }
- });
- test('strftime', function () {
++openerp.testing.section('eval.types', {
++ dependencies: ['web.coresetup']
++}, function (test) {
++ test('strftime', function (instance) {
+ var d = new Date();
- var context = openerp.web.pyeval.context();
++ var context = instance.web.pyeval.context();
+ strictEqual(
+ py.eval("time.strftime('%Y')", context),
+ String(d.getFullYear()));
+ strictEqual(
+ py.eval("time.strftime('%Y')+'-01-30'", context),
+ String(d.getFullYear()) + '-01-30');
+ strictEqual(
+ py.eval("time.strftime('%Y-%m-%d %H:%M:%S')", context),
+ _.str.sprintf('%04d-%02d-%02d %02d:%02d:%02d',
+ d.getFullYear(), d.getMonth() + 1, d.getDate(),
+ d.getHours(), d.getMinutes(), d.getSeconds()));
+ });
-
- module("eval.contexts", {
- setup: function () {
- openerp = window.openerp.testing.instanceFor('coresetup');
- openerp.session.uid = 42;
- }
- });
- test('context_recursive', function () {
++});
+ openerp.testing.section('eval.contexts', {
+ dependencies: ['web.coresetup']
+ }, function (test) {
++ test('context_recursive', function (instance) {
+ var context_to_eval = [{
+ __ref: 'context',
+ __debug: '{"foo": context.get("bar", "qux")}'
+ }];
+ deepEqual(
- openerp.web.pyeval.eval('contexts', context_to_eval, {bar: "ok"}),
++ instance.web.pyeval.eval('contexts', context_to_eval, {bar: "ok"}),
+ {foo: 'ok'});
+ deepEqual(
- openerp.web.pyeval.eval('contexts', context_to_eval, {bar: false}),
++ instance.web.pyeval.eval('contexts', context_to_eval, {bar: false}),
+ {foo: false});
+ deepEqual(
- openerp.web.pyeval.eval('contexts', context_to_eval),
++ instance.web.pyeval.eval('contexts', context_to_eval),
+ {foo: 'qux'});
+ });
- test('context_sequences', function () {
+ test('context_sequences', function (instance) {
// Context n should have base evaluation context + all of contexts
// 0..n-1 in its own evaluation context
var active_id = 4;
- var result = openerp.web.pyeval.eval('contexts', [
- var result = instance.session.test_eval_contexts([
++ var result = instance.web.pyeval.eval('contexts', [
{
"__contexts": [
{
record_id: active_id
});
});
- test('non-literal_eval_contexts', function () {
- var result = openerp.web.pyeval.eval('contexts', [{
+ test('non-literal_eval_contexts', function (instance) {
- var result = instance.session.test_eval_contexts([{
++ var result = instance.web.pyeval.eval('contexts', [{
"__ref": "compound_context",
"__contexts": [
{"__ref": "context", "__debug": "{'type':parent.type}",
}]);
deepEqual(result, {type: 'out_invoice'});
});
- module('eval.domains', {
- setup: function () {
- openerp = window.openerp.testing.instanceFor('coresetup');
- window.openerp.web.dates(openerp);
- openerp.session.uid = 42;
- }
- });
- test('current_date', function () {
- var current_date = openerp.web.date_to_str(new Date());
- var result = openerp.web.pyeval.eval('domains',
- [[],{"__ref":"domain","__debug":"[('name','>=',current_date),('name','<=',current_date)]","__id":"5dedcfc96648"}]);
+ });
+ openerp.testing.section('eval.contexts', {
+ dependencies: ['web.coresetup', 'web.dates']
+ }, function (test) {
+ test('current_date', function (instance) {
+ var current_date = instance.web.date_to_str(new Date());
- var result = instance.session.test_eval_domains(
++ var result = instance.web.pyeval.eval('domains',
+ [[],{"__ref":"domain","__debug":"[('name','>=',current_date),('name','<=',current_date)]","__id":"5dedcfc96648"}],
- instance.session.test_eval_get_context());
++ instance.web.pyeval.context());
deepEqual(result, [
['name', '>=', current_date],
['name', '<=', current_date]
]);
- })
+ });
- test('context_freevar', function () {
++ test('context_freevar', function (instance) {
+ var domains_to_eval = [{
+ __ref: 'domain',
+ __debug: '[("foo", "=", context.get("bar", "qux"))]'
+ }, [['bar', '>=', 42]]];
+ deepEqual(
- openerp.web.pyeval.eval('domains', domains_to_eval, {bar: "ok"}),
++ instance.web.pyeval.eval('domains', domains_to_eval, {bar: "ok"}),
+ [['foo', '=', 'ok'], ['bar', '>=', 42]]);
+ deepEqual(
- openerp.web.pyeval.eval('domains', domains_to_eval, {bar: false}),
++ instance.web.pyeval.eval('domains', domains_to_eval, {bar: false}),
+ [['foo', '=', false], ['bar', '>=', 42]]);
+ deepEqual(
- openerp.web.pyeval.eval('domains', domains_to_eval),
++ instance.web.pyeval.eval('domains', domains_to_eval),
+ [['foo', '=', 'qux'], ['bar', '>=', 42]]);
+ });
-
- module('eval.groupbys', {
- setup: function () {
- openerp = window.openerp.testing.instanceFor('coresetup');
- openerp.session.uid = 42;
- }
- });
- test('groupbys_00', function () {
- var result = openerp.web.pyeval.eval('groupbys', [
++});
++openerp.testing.section('eval.groupbys', {
++ dependencies: ['web.coresetup']
++}, function (test) {
++ test('groupbys_00', function (instance) {
++ var result = instance.web.pyeval.eval('groupbys', [
+ {group_by: 'foo'},
+ {group_by: ['bar', 'qux']},
+ {group_by: null},
+ {group_by: 'grault'}
+ ]);
+ deepEqual(result, ['foo', 'bar', 'qux', 'grault']);
+ });
- test('groupbys_01', function () {
- var result = openerp.web.pyeval.eval('groupbys', [
++ test('groupbys_01', function (instance) {
++ var result = instance.web.pyeval.eval('groupbys', [
+ {group_by: 'foo'},
+ { __ref: 'context', __debug: '{"group_by": "bar"}' },
+ {group_by: 'grault'}
+ ]);
+ deepEqual(result, ['foo', 'bar', 'grault']);
+ });
- test('groupbys_02', function () {
- var result = openerp.web.pyeval.eval('groupbys', [
++ test('groupbys_02', function (instance) {
++ var result = instance.web.pyeval.eval('groupbys', [
+ {group_by: 'foo'},
+ {
+ __ref: 'compound_context',
+ __contexts: [ {group_by: 'bar'} ],
+ __eval_context: null
+ },
+ {group_by: 'grault'}
+ ]);
+ deepEqual(result, ['foo', 'bar', 'grault']);
+ });
- test('groupbys_03', function () {
- var result = openerp.web.pyeval.eval('groupbys', [
++ test('groupbys_03', function (instance) {
++ var result = instance.web.pyeval.eval('groupbys', [
+ {group_by: 'foo'},
+ {
+ __ref: 'compound_context',
+ __contexts: [
+ { __ref: 'context', __debug: '{"group_by": value}' }
+ ],
+ __eval_context: { value: 'bar' }
+ },
+ {group_by: 'grault'}
+ ]);
+ deepEqual(result, ['foo', 'bar', 'grault']);
+ });
- test('groupbys_04', function () {
- var result = openerp.web.pyeval.eval('groupbys', [
++ test('groupbys_04', function (instance) {
++ var result = instance.web.pyeval.eval('groupbys', [
+ {group_by: 'foo'},
+ {
+ __ref: 'compound_context',
+ __contexts: [
+ { __ref: 'context', __debug: '{"group_by": value}' }
+ ],
+ __eval_context: { value: 'bar' }
+ },
+ {group_by: 'grault'}
+ ], { value: 'bar' });
+ deepEqual(result, ['foo', 'bar', 'grault']);
+ });
- test('groupbys_05', function () {
- var result = openerp.web.pyeval.eval('groupbys', [
++ test('groupbys_05', function (instance) {
++ var result = instance.web.pyeval.eval('groupbys', [
+ {group_by: 'foo'},
+ { __ref: 'context', __debug: '{"group_by": value}' },
+ {group_by: 'grault'}
+ ], { value: 'bar' });
+ deepEqual(result, ['foo', 'bar', 'grault']);
+ });
});
--- /dev/null
--- /dev/null
++<!DOCTYPE html>
++<html style="height: 100%">
++<head>
++ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
++ <title>OpenERP Web Test Suite</title>
++ <link rel="shortcut icon" href="/web/static/src/img/favicon.ico" type="image/x-icon"/>
++
++ <link rel="stylesheet" href="/web/static/lib/qunit/qunit.css">
++ <script src="/web/static/lib/qunit/qunit.js" type="text/javascript"></script>
++
++ <script src="/web/static/lib/underscore/underscore.js" type="text/javascript"></script>
++ <script src="/web/static/lib/underscore/underscore.string.js" type="text/javascript"></script>
++ <script src="/web/static/lib/backbone/backbone.js" type="text/javascript"></script>
++
++ <!-- jquery -->
++ <script src="/web/static/lib/jquery/jquery-1.7.2.js"></script>
++ <script src="/web/static/lib/jquery.ui/js/jquery-ui-1.8.17.custom.min.js"></script>
++ <script src="/web/static/lib/jquery.ba-bbq/jquery.ba-bbq.js"></script>
++
++ <script src="/web/static/lib/datejs/globalization/en-US.js"></script>
++ <script src="/web/static/lib/datejs/core.js"></script>
++ <script src="/web/static/lib/datejs/parser.js"></script>
++ <script src="/web/static/lib/datejs/sugarpak.js"></script>
++ <script src="/web/static/lib/datejs/extras.js"></script>
++
++ <script src="/web/static/lib/qweb/qweb2.js"></script>
++
++ <script src="/web/static/lib/py.js/lib/py.js"></script>
++
++ <script src="/web/static/src/js/boot.js"></script>
++ <script src="/web/static/src/js/pyeval.js"></script>
++ <script src="/web/static/src/js/corelib.js"></script>
++ <script src="/web/static/src/js/coresetup.js"></script>
++ <script src="/web/static/src/js/dates.js"></script>
++ <script src="/web/static/src/js/formats.js"></script>
++ <script src="/web/static/src/js/chrome.js"></script>
++ <script src="/web/static/src/js/data.js"></script>
++ <script src="/web/static/src/js/views.js"></script>
++ <script src="/web/static/src/js/search.js"></script>
++ <script src="/web/static/src/js/view_form.js"></script>
++ <script src="/web/static/src/js/view_list.js"></script>
++ <script src="/web/static/src/js/view_list_editable.js"></script>
++
++ <script src="/web/static/test/testing.js"></script>
++ <script type="text/javascript">
++ QUnit.config.testTimeout = 2000;
++ </script>
++</head>
++ <body id="oe" class="openerp">
++ <div id="qunit"></div>
++ <div id="qunit-fixture"></div>
++ </body>
++ <script type="text/javascript" src="/web/static/test/class.js"></script>
++ <script type="text/javascript" src="/web/static/test/registry.js"></script>
++ <script type="text/javascript" src="/web/static/test/form.js"></script>
++ <script type="text/javascript" src="/web/static/test/list-utils.js"></script>
++ <script type="text/javascript" src="/web/static/test/formats.js"></script>
++ <script type="text/javascript" src="/web/static/test/rpc.js"></script>
++ <script type="text/javascript" src="/web/static/test/evals.js"></script>
++ <script type="text/javascript" src="/web/static/test/search.js"></script>
++ <script type="text/javascript" src="/web/static/test/Widget.js"></script>
++ <script type="text/javascript" src="/web/static/test/list-editable.js"></script>
++</html>
+++ /dev/null
- .. OpenERP Web documentation master file, created by
- sphinx-quickstart on Fri Mar 18 16:31:55 2011.
- You can adapt this file completely to your liking, but it should at least
- contain the root `toctree` directive.
-
- Welcome to OpenERP Web's documentation!
- =======================================
-
- Contents:
-
- .. toctree::
- :maxdepth: 1
-
- changelog-7.0
-
- async
- rpc
-
- widget
- search-view
-
- list-view
- form-notes
-
- guides/client-action
-
- Indices and tables
- ==================
-
- * :ref:`genindex`
- * :ref:`modindex`
- * :ref:`search`
-:orphan:
-
-========================================
-OpenERP Server Developers Documentation
-========================================
-
-OpenERP Server
-''''''''''''''
-
-.. toctree::
- :maxdepth: 2
-
- 01_getting_started
- 02_architecture
- 03_module_dev
- 04_security
- 05_test_framework
- 06_misc
- 09_deployment
-
-OpenERP Server API
-''''''''''''''''''
-
-.. toctree::
- :maxdepth: 1
-
- api_core.rst
- api_models.rst
-
-
-
+++ /dev/null
--#!/usr/bin/env python
--# -*- coding: utf-8 -*-
--##############################################################################
--#
--# OpenERP, Open Source Management Solution
--# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
--#
--# This program is free software: you can redistribute it and/or modify
--# it under the terms of the GNU Affero General Public License as
--# published by the Free Software Foundation, either version 3 of the
--# License, or (at your option) any later version.
--#
--# This program is distributed in the hope that it will be useful,
--# but WITHOUT ANY WARRANTY; without even the implied warranty of
--# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
--# GNU Affero General Public License for more details.
--#
--# You should have received a copy of the GNU Affero General Public License
--# along with this program. If not, see <http://www.gnu.org/licenses/>.
--#
--##############################################################################
--
--import glob, os, re, setuptools, sys
--from os.path import join, isfile
--
--# List all data files
--def data():
-- files = []
-- for root, dirnames, filenames in os.walk('openerp'):
-- for filename in filenames:
-- if not re.match(r'.*(\.pyc|\.pyo|\~)$',filename):
-- files.append(os.path.join(root, filename))
-- d = {}
-- for v in files:
-- k=os.path.dirname(v)
-- if k in d:
-- d[k].append(v)
-- else:
-- d[k]=[v]
-- r = d.items()
-- if os.name == 'nt':
-- r.append(("Microsoft.VC90.CRT", glob.glob('C:\Microsoft.VC90.CRT\*.*')))
--
-- import babel
-- r.append(("localedata",
-- glob.glob(os.path.join(os.path.dirname(babel.__file__), "localedata" , '*'))))
--
-- return r
--
--def gen_manifest():
-- file_list="\n".join(data())
-- open('MANIFEST','w').write(file_list)
--
--if os.name == 'nt':
-- sys.path.append("C:\Microsoft.VC90.CRT")
--
--def py2exe_options():
-- if os.name == 'nt':
-- import py2exe
-- return {
-- "console" : [ { "script": "openerp-server", "icon_resources": [(1, join("install","openerp-icon.ico"))], }],
-- 'options' : {
-- "py2exe": {
-- "skip_archive": 1,
-- "optimize": 2,
-- "dist_dir": 'dist',
-- "packages": [ "DAV", "HTMLParser", "PIL", "asynchat", "asyncore", "commands", "dateutil", "decimal", "email", "encodings", "imaplib", "lxml", "lxml._elementpath", "lxml.builder", "lxml.etree", "lxml.objectify", "mako", "openerp", "poplib", "pychart", "pydot", "pyparsing", "reportlab", "select", "simplejson", "smtplib", "uuid", "vatnumber", "vobject", "xml", "xml.dom", "yaml", ],
-- "excludes" : ["Tkconstants","Tkinter","tcl"],
-- }
-- }
-- }
-- else:
-- return {}
--
--execfile(join(os.path.dirname(__file__), 'openerp', 'release.py'))
--
- setuptools.setup(
- name = 'openerp',
- version = version,
- description = description,
- long_description = long_desc,
- url = url,
- author = author,
- author_email = author_email,
- classifiers = filter(None, classifiers.split("\n")),
- license = license,
- scripts = ['openerp-server'],
- data_files = data(),
- packages = setuptools.find_packages(),
- #include_package_data = True,
- install_requires = [
- # TODO the pychart package we include in openerp corresponds to PyChart 1.37.
- # It seems there is a single difference, which is a spurious print in generate_docs.py.
- # It is probably safe to move to PyChart 1.39 (the latest one).
- # (Let setup.py choose the latest one, and we should check we can remove pychart from
- # our tree.) http://download.gna.org/pychart/
- # TODO 'pychart',
- 'babel',
- 'feedparser',
- 'gdata',
- 'lxml',
- 'mako',
- 'psycopg2',
- 'pydot',
- 'python-dateutil < 2',
- 'python-ldap',
- 'python-openid',
- 'pytz',
- 'pywebdav',
- 'pyyaml',
- 'reportlab',
- 'simplejson',
- 'vatnumber',
- 'vobject',
- 'werkzeug',
- 'xlwt',
- 'zsi',
- ],
- extras_require = {
- 'SSL' : ['pyopenssl'],
- },
- **py2exe_options()
- )
-
-
- # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
-# Notes for OpenERP developer on windows:
-#
-# To setup a windows developer evironement install python2.7 then pip and use
-# "pip install <depencey>" for every dependency listed below.
-#
-# Dependecies that requires DLLs are not installable with pip install, for
-# them we added comments with links where you can find the installers.
-#
-# OpenERP on windows also require the pywin32, the binary can be found at
-# http://pywin32.sf.net
-#
-# Both python2.7 32bits and 64bits are known to work.
-
-setuptools.setup(
- name = 'openerp',
- version = version,
- description = description,
- long_description = long_desc,
- url = url,
- author = author,
- author_email = author_email,
- classifiers = filter(None, classifiers.split("\n")),
- license = license,
- scripts = ['openerp-server'],
- data_files = data(),
- packages = setuptools.find_packages(),
- dependency_links = ['http://download.gna.org/pychart/'],
- #include_package_data = True,
- install_requires = [
- 'pychart', # not on pypi, use: pip install http://download.gna.org/pychart/PyChart-1.39.tar.gz
- 'babel',
- 'docutils',
- 'feedparser',
- 'gdata',
- 'lxml < 3', # windows binary http://www.lfd.uci.edu/~gohlke/pythonlibs/
- 'mako',
- 'PIL', # windows binary http://www.lfd.uci.edu/~gohlke/pythonlibs/
- 'psutil', # windows binary code.google.com/p/psutil/downloads/list
- 'psycopg2',
- 'pydot',
- 'python-dateutil < 2',
- 'python-ldap', # optional
- 'python-openid',
- 'pytz',
- 'pywebdav',
- 'pyyaml',
- 'reportlab', # windows binary pypi.python.org/pypi/reportlab
- 'simplejson',
- 'vatnumber',
- 'vobject',
- 'werkzeug',
- 'xlwt',
- ],
- extras_require = {
- 'SSL' : ['pyopenssl'],
- },
- tests_require = ['unittest2'],
- **py2exe_options()
-)
-
-
-# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: