pyjs / pyjs

Pyjs canonical sources. Start here!
http://pyjs.org/
Apache License 2.0
1.14k stars 214 forks source link

declaring metaclass from "type" function #421

Open pyjsorg opened 12 years ago

pyjsorg commented 12 years ago

The following canonical example results in an error:

!/usr/bin/python

class MyMetaclass(type): pass

I run "pyjsbuild.py metatest" (pyjamas 0.6), then open output/ metatest.html in Firefox 3.5.3, which shows the following alert:

metatest TypeError bases[i].sub_classes is undefined

The Firebug Javascript debugger kindly shows me that the error is from the construction of the MyMetaclass type, specifically: (in _pyjs.js, function pyjs__class_function)

cls_fn.__sub_classes__ = new Array();
for (var i = 0; i < bases.length; i++) {
    (bases[i]).__sub_classes__.push(cls_fn);
}

Because "pyjslib.type" is defined without sub_classes.

Any ideas?

Original issue: http://code.google.com/p/pyjamas/issues/detail?id=298 (October 05, 2009 20:58:37)

pyjsorg commented 12 years ago

From cronos...@gmail.com on October 05, 2009 23:54:33: Regarding the utility of "class X(type)" syntax vs "X = type(...)": the former is much more natural. For example: class X(object): a = 1

is much more natural than: X = type('X', (object,), dict(a=1))

In particular, this is used by GAE schema definitions to replace the behavior of the "a = " assignment to trigger field registration, etc.

I will be adding a patch to LibTest/ClassTest.py for the former syntax.

For those finding this bug report first, the discussion started in: http://groups.google.com/group/pyjamas-dev/browse_thread/thread/0c0e5d5b2ac85282

pyjsorg commented 12 years ago

From cronos...@gmail.com on October 10, 2009 19:15:32: Luke, in the Groups thread you suggested the following workaround: MyMetaclass = type("class", [base class list], {dict of fns and props}).

This unfortunately results in the same error as "class MyMetaclass". They are in fact syntax for the same underlying mechanism. It is this class construction mechanism that breaks because the PyJS definition of "type" is as a function only and not as a class.

Attached is a patch to trunk's ClassTest.py that adds two unit tests in this direction.

pyjsorg commented 12 years ago

From luke.lei...@gmail.com on October 10, 2009 20:14:24: what? what? :) no, that can't be right. from ClassTest.py :

def testMetaClass(self):
    Klass = type('MyClass', (object,), {'method': method, 'x': 5})
    instance = Klass()
    self.assertEqual(instance.method(), 1)
    self.assertEqual(instance.x, 5)
pyjsorg commented 12 years ago

From luke.lei...@gmail.com on October 10, 2009 20:17:22: ok - thank you for the examples.

however, when i said "use type()" i meant, "use type() and DO NOT USE ANYTHING ELSE".

the two examples you've given make use of another feature which isn't supported: metaclass.

so - they're going in, but don't hold your breath.

and use type as shown in the ClassTest.py example, for now.

pyjsorg commented 12 years ago

From cronos...@gmail.com on October 10, 2009 20:18:29: Yes, testMetaClass indeed succeeds because it declares "object" as a base class. What I am saying is that "type" is not usable as a base class. "type" is not usable as a base class, whether through "class X(type)" or "type('X', (type,), {})".

pyjsorg commented 12 years ago

From cronos...@gmail.com on October 10, 2009 20:21:35: In my opinion, "testMetaClass" is a misnomer. There is no metaclass programming in that unit test. Rather, it is a test of dynamic class construction.

Can you give another example of what you consider metaclass programming under PyJS?

pyjsorg commented 12 years ago

From luke.lei...@gmail.com on October 10, 2009 20:24:16: ok i've added them and also put an exception catch around them because without the exception catching the entire LibTest application is terminated.

pyjsorg commented 12 years ago

From luke.lei...@gmail.com on October 10, 2009 20:25:42: no, because according to the definition you've given, there isn't any yet (until it's added).

pyjsorg commented 12 years ago

From cornelis...@gmail.com on October 12, 2009 07:23:16: Luke, I just added wrapping in try/except. Now I see you've done this too, but didn't commit. You'll probably get an conflict on git-svn rebase...