diff options
| author | Xavier Morel <xmo@openerp.com> | 2012-08-06 13:06:38 +0200 |
|---|---|---|
| committer | Xavier Morel <xmo@openerp.com> | 2012-08-06 13:06:38 +0200 |
| commit | 6a23c24da13f5907d4c407e919bff187a3a0ae1d (patch) | |
| tree | 498a2cad11a787ba063d6eecd8a895751225a1b7 /addons/web/static/lib/py.js | |
| parent | 6f4abdfbd519e8f8a416e24fdb541a88ef3104c6 (diff) | |
[UP] py.js, old != operator and basic dict handling
bzr revid: xmo@openerp.com-20120806110638-1m4rg205sb3vjvm5
Diffstat (limited to 'addons/web/static/lib/py.js')
| -rw-r--r-- | addons/web/static/lib/py.js/.hg_archival.txt | 4 | ||||
| -rw-r--r-- | addons/web/static/lib/py.js/README.rst | 26 | ||||
| -rw-r--r-- | addons/web/static/lib/py.js/lib/py.js | 32 | ||||
| -rw-r--r-- | addons/web/static/lib/py.js/test/test.js | 28 |
4 files changed, 75 insertions, 15 deletions
diff --git a/addons/web/static/lib/py.js/.hg_archival.txt b/addons/web/static/lib/py.js/.hg_archival.txt index 35e98c8501d..2aa926eb56a 100644 --- a/addons/web/static/lib/py.js/.hg_archival.txt +++ b/addons/web/static/lib/py.js/.hg_archival.txt @@ -1,5 +1,5 @@ repo: 076b192d0d8ab2b92d1dbcfa3da055382f30eaea -node: 1758bfec1ec1dcff95dcc4c72269cc0e3d000afd +node: 87e977311edbbb5f281b87390a9a304eb194ce89 branch: default latesttag: 0.5 -latesttagdistance: 11 +latesttagdistance: 15 diff --git a/addons/web/static/lib/py.js/README.rst b/addons/web/static/lib/py.js/README.rst index 046db7153d1..eea1cbbf963 100644 --- a/addons/web/static/lib/py.js/README.rst +++ b/addons/web/static/lib/py.js/README.rst @@ -60,7 +60,7 @@ Builtins Same as tuple (``list`` is currently an alias for ``tuple``) ``dict`` - Implements just about nothing + Implements trivial getting and setting, nothing beyond that. Note that most methods are probably missing from all of these. @@ -72,14 +72,14 @@ sub-protocols) of the `Python 2.7 data model <http://docs.python.org/reference/datamodel.html>`_: Rich comparisons - Roughly complete implementation but for two limits: ``__eq__`` and - ``__ne__`` can't return ``NotImplemented`` (well they can but it's - not going to work right), and the behavior is undefined if a - rich-comparison operation does not return a ``py.bool``. + Pretty much complete (including operator fallbacks), although the + behavior is currently undefined if an operation does not return + either a ``py.bool`` or ``NotImplemented``. - Also, a ``NotImplemented`` result does not try the reverse - operation, not sure if it's supposed to. It directly falls back to - comparing type names. + ``__hash__`` is supported (and used), but it should return **a + javascript string**. ``py.js``'s dict build on javascript objects, + reimplementing numeral hashing is worthless complexity at this + point. Boolean conversion Implementing ``__nonzero__`` should work. @@ -93,6 +93,12 @@ Descriptor protocol As with attributes, ``__delete__`` is not implemented. Callable objects + Work, although the handling of arguments isn't exactly nailed + down. For now, callables get two (javascript) arguments ``args`` + and ``kwargs``, holding (respectively) positional and keyword + arguments. + + Conflicts are *not* handled at this point. Collections Abstract Base Classes Container is the only implemented ABC protocol (ABCs themselves @@ -119,8 +125,8 @@ implementation: ``py.js`` types. When accessing instance methods, ``py.js`` automatically wraps - these in a variant of ``py.def`` automatically, to behave as - Python's (bound) methods. + these in a variant of ``py.def``, to behave as Python's (bound) + methods. Why === diff --git a/addons/web/static/lib/py.js/lib/py.js b/addons/web/static/lib/py.js/lib/py.js index a8c952679af..79a0ace1995 100644 --- a/addons/web/static/lib/py.js/lib/py.js +++ b/addons/web/static/lib/py.js/lib/py.js @@ -433,7 +433,8 @@ var py = {}; if (this._hash) { return this._hash; } - return this._hash = hash_counter++; + // tagged counter, to avoid collisions with e.g. number hashes + return this._hash = '\0\0\0' + String(hash_counter++); }, __eq__: function (other) { return (this === other) ? py.True : py.False; @@ -597,6 +598,9 @@ var py = {}; throw new Error('TypeError: __str__ returned non-string (type ' + v.constructor.name + ')'); }, py.object, { + __hash__: function () { + return '\1\0\1' + this._value; + }, __eq__: function (other) { if (other instanceof py.str && this._value === other._value) { return py.True; @@ -654,12 +658,33 @@ var py = {}; } }); py.list = py.tuple; - py.dict = py.type(function dict() { + py.dict = py.type(function dict(d) { this._store = {}; + for (var k in (d || {})) { + if (!d.hasOwnProperty(k)) { continue; } + var py_k = new py.str(k); + var val = PY_ensurepy(d[k]); + this._store[py_k.__hash__()] = [py_k, val]; + } }, py.object, { + __getitem__: function (key) { + var h = key.__hash__(); + if (!(h in this._store)) { + throw new Error("KeyError: '" + key.toJSON() + "'"); + } + return this._store[h][1]; + }, __setitem__: function (key, value) { this._store[key.__hash__()] = [key, value]; }, + get: function (args) { + var h = args[0].__hash__(); + var def = args.length > 1 ? args[1] : py.None; + if (!(h in this._store)) { + return def; + } + return this._store[h][1]; + }, toJSON: function () { var out = {}; for(var k in this._store) { @@ -700,6 +725,7 @@ var py = {}; var PY_operators = { '==': ['eq', 'eq', function (a, b) { return a === b; }], '!=': ['ne', 'ne', function (a, b) { return a !== b; }], + '<>': ['ne', 'ne', function (a, b) { return a !== b; }], '<': ['lt', 'gt', function (a, b) {return a.constructor.name < b.constructor.name;}], '<=': ['le', 'ge', function (a, b) {return a.constructor.name <= b.constructor.name;}], '>': ['gt', 'lt', function (a, b) {return a.constructor.name > b.constructor.name;}], @@ -782,7 +808,7 @@ var py = {}; return b.__contains__(a); case 'not in': return b.__contains__(a) === py.True ? py.False : py.True; - case '==': case '!=': + case '==': case '!=': case '<>': case '<': case '<=': case '>': case '>=': return PY_op(a, b, operator); diff --git a/addons/web/static/lib/py.js/test/test.js b/addons/web/static/lib/py.js/test/test.js index c1f92c44d81..f09245a38c8 100644 --- a/addons/web/static/lib/py.js/test/test.js +++ b/addons/web/static/lib/py.js/test/test.js @@ -117,6 +117,11 @@ describe('Comparisons', function () { expect(py.eval('foo != bar', {foo: 'qux', bar: 'quux'})) .to.be(true); }); + it('should accept deprecated form', function () { + expect(py.eval('1 <> 2')).to.be(true); + expect(py.eval('"foo" <> "foo"')).to.be(false); + expect(py.eval('"foo" <> "bar"')).to.be(true); + }); }); describe('rich comparisons', function () { it('should work with numbers', function () { @@ -377,6 +382,29 @@ describe('numerical protocols', function () { }); }); }); +describe('dicts', function () { + it('should be possible to retrieve their value', function () { + var d = new py.dict({foo: 3, bar: 4, baz: 5}); + expect(py.eval('d["foo"]', {d: d})).to.be(3); + expect(py.eval('d["baz"]', {d: d})).to.be(5); + }); + it('should raise KeyError if a key is missing', function () { + var d = new py.dict(); + expect(function () { + py.eval('d["foo"]', {d: d}); + }).to.throwException(/^KeyError/); + }); + it('should have a method to provide a default value', function () { + var d = new py.dict({foo: 3}); + expect(py.eval('d.get("foo")', {d: d})).to.be(3); + expect(py.eval('d.get("bar")', {d: d})).to.be(null); + expect(py.eval('d.get("bar", 42)', {d: d})).to.be(42); + + var e = new py.dict({foo: null}); + expect(py.eval('d.get("foo")', {d: e})).to.be(null); + expect(py.eval('d.get("bar")', {d: e})).to.be(null); + }); +}); describe('Type converter', function () { it('should convert bare objects to objects', function () { expect(py.eval('foo.bar', {foo: {bar: 3}})).to.be(3); |
