Skip to content

Scope bug and generators #10

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Aug 10, 2014
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
Clarify that we're only doing PY2 classes, and add tests
In PY3, we're falling back to the builtin implementation by relying on __build_class__.

Add tests that show that something is going wrong with attribute lookup.
  • Loading branch information
akaptur committed Jun 12, 2014
commit 46055b59a88f7d08da62a5f846733db0831297d7
94 changes: 47 additions & 47 deletions byterun/pyobj.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ def __call__(self, *args, **kwargs):
try:
callargs = inspect.getcallargs(self._func, *args, **kwargs)
except Exception as e:
import pudb;pudb.set_trace() # -={XX}=-={XX}=-={XX}=-
# import pudb;pudb.set_trace() # -={XX}=-={XX}=-={XX}=-
raise
frame = self._vm.make_frame(
self.func_code, callargs, self.func_globals, self.func_locals
Expand All @@ -86,55 +86,55 @@ def __call__(self, *args, **kwargs):
retval = self._vm.run_frame(frame)
return retval

if PY2:
class Class(object):
def __init__(self, name, bases, methods):
self.__name__ = name
self.__bases__ = bases
self.locals = dict(methods)

class Class(object):
def __init__(self, name, bases, methods):
self.__name__ = name
self.__bases__ = bases
self.locals = dict(methods)
def __call__(self, *args, **kw):
return Object(self, self.locals, args, kw)

def __call__(self, *args, **kw):
return Object(self, self.locals, args, kw)
def __repr__(self): # pragma: no cover
return '<Class %s at 0x%08x>' % (self.__name__, id(self))

def __repr__(self): # pragma: no cover
return '<Class %s at 0x%08x>' % (self.__name__, id(self))

def __getattr__(self, name):
try:
val = self.locals[name]
except KeyError:
raise AttributeError("Fooey: %r" % (name,))
# Check if we have a descriptor
get = getattr(val, '__get__', None)
if get:
return get(None, self)
# Not a descriptor, return the value.
return val


class Object(object):
def __init__(self, _class, methods, args, kw):
self._class = _class
self.locals = methods
if '__init__' in methods:
methods['__init__'](self, *args, **kw)

def __repr__(self): # pragma: no cover
return '<%s Instance at 0x%08x>' % (self._class.__name__, id(self))

def __getattr__(self, name):
try:
val = self.locals[name]
except KeyError:
raise AttributeError(
"%r object has no attribute %r" % (self._class.__name__, name)
)
# Check if we have a descriptor
get = getattr(val, '__get__', None)
if get:
return get(self, self._class)
# Not a descriptor, return the value.
return val
def __getattr__(self, name):
try:
val = self.locals[name]
except KeyError:
raise AttributeError("Fooey: %r" % (name,))
# Check if we have a descriptor
get = getattr(val, '__get__', None)
if get:
return get(None, self)
# Not a descriptor, return the value.
return val


class Object(object):
def __init__(self, _class, methods, args, kw):
self._class = _class
self.locals = methods
if '__init__' in methods:
methods['__init__'](self, *args, **kw)

def __repr__(self): # pragma: no cover
return '<%s Instance at 0x%08x>' % (self._class.__name__, id(self))

def __getattr__(self, name):
try:
val = self.locals[name]
except KeyError:
raise AttributeError(
"%r object has no attribute %r" % (self._class.__name__, name)
)
# Check if we have a descriptor
get = getattr(val, '__get__', None)
if get:
return get(self, self._class)
# Not a descriptor, return the value.
return val


class Method(object):
Expand Down
34 changes: 19 additions & 15 deletions byterun/pyvm2.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@

PY3, PY2 = six.PY3, not six.PY3

from .pyobj import Frame, Block, Method, Object, Function, Class, Generator
from .pyobj import Frame, Block, Method, Function, Generator
if PY2:
from .pyobj import Class, Object

log = logging.getLogger(__name__)

Expand Down Expand Up @@ -910,12 +912,12 @@ def byte_CALL_FUNCTION_VAR_KW(self, arg):
return self.call_function(arg, args, kwargs)

def isinstance(self, obj, cls):
if isinstance(obj, Object):
return issubclass(obj._class, cls)
elif isinstance(cls, Class):
return False
else:
return isinstance(obj, cls)
if PY2:
if isinstance(obj, Object):
return issubclass(obj._class, cls)
elif isinstance(cls, Class):
return False
return isinstance(obj, cls)

def call_function(self, arg, args, kwargs):
lenKw, lenPos = divmod(arg, 256)
Expand Down Expand Up @@ -983,16 +985,18 @@ def byte_EXEC_STMT(self):
stmt, globs, locs = self.popn(3)
six.exec_(stmt, globs, locs)

def byte_BUILD_CLASS(self):
name, bases, methods = self.popn(3)
self.push(Class(name, bases, methods))
if PY2:
def byte_BUILD_CLASS(self):
name, bases, methods = self.popn(3)
self.push(Class(name, bases, methods))

def byte_LOAD_BUILD_CLASS(self):
# New in py3
self.push(__build_class__)
elif PY3:
def byte_LOAD_BUILD_CLASS(self):
# New in py3
self.push(__build_class__)

def byte_STORE_LOCALS(self):
self.frame.f_locals = self.pop()
def byte_STORE_LOCALS(self):
self.frame.f_locals = self.pop()

if 0: # Not in py2.7
def byte_SET_LINENO(self, lineno):
Expand Down
34 changes: 34 additions & 0 deletions tests/test_basic.py
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,40 @@ class SubThing(Thing):
print(st.foo())
""")

def test_subclass_attribute(self):
self.assert_ok("""\
class Thing(object):
def __init__(self):
self.foo = 17
class SubThing(Thing):
pass
st = SubThing()
print(st.foo)
""")

def test_subclass_attributes_not_shared(self):
self.assert_ok("""\
class Thing(object):
foo = 17
class SubThing(Thing):
foo = 25
st = SubThing()
t = Thing()
assert st.foo == 25
assert t.foo == 17
""")

def test_subclass_attributes_dynamic(self):
self.assert_ok("""\
class Foo(object):
pass
class Bar(Foo):
pass
b = Bar()
Foo.baz = 3
assert b.baz == 3
""")

def test_attribute_access(self):
self.assert_ok("""\
class Thing(object):
Expand Down