summaryrefslogtreecommitdiff
path: root/addons/web/static/lib/py.js
diff options
context:
space:
mode:
authorXavier Morel <xmo@openerp.com>2012-08-06 13:06:38 +0200
committerXavier Morel <xmo@openerp.com>2012-08-06 13:06:38 +0200
commit6a23c24da13f5907d4c407e919bff187a3a0ae1d (patch)
tree498a2cad11a787ba063d6eecd8a895751225a1b7 /addons/web/static/lib/py.js
parent6f4abdfbd519e8f8a416e24fdb541a88ef3104c6 (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.txt4
-rw-r--r--addons/web/static/lib/py.js/README.rst26
-rw-r--r--addons/web/static/lib/py.js/lib/py.js32
-rw-r--r--addons/web/static/lib/py.js/test/test.js28
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);