Skip to content

Commit

Permalink
py3: all tests pass
Browse files Browse the repository at this point in the history
  • Loading branch information
lazka committed Mar 24, 2014
1 parent c1a4a41 commit 982914a
Show file tree
Hide file tree
Showing 9 changed files with 130 additions and 30 deletions.
2 changes: 1 addition & 1 deletion README.rst
Expand Up @@ -10,7 +10,7 @@ and cffi_ (optional). API compatible with PyGObject_.

**Requirements:**

- CPython_ 2.7 or PyPy_ 1.9
- CPython_ 2.7 or Python 3.3 or PyPy_ 1.9
- libgirepository_ 1.0
- cffi_ 0.6+ (optional)
- cairocffi_ 0.4+ (optional, for cairo support)
Expand Down
7 changes: 6 additions & 1 deletion benchmarks/__init__.py
@@ -1,14 +1,19 @@
# -*- coding: utf-8 -*-
# Copyright 2012 Christoph Reiter
# Copyright 2012-2014 Christoph Reiter
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.

import sys
import time


if sys.version_info[0] == 3:
xrange = range


def run(load_gi, backend=None):
if not load_gi:
import pgi
Expand Down
66 changes: 50 additions & 16 deletions pgi/codegen/cffi_backend.py
Expand Up @@ -5,8 +5,6 @@
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.

import __builtin__

from cffi import FFI

from pgi.clib.gir import GIRepository, GITypeTag, GIInfoType
Expand Down Expand Up @@ -135,14 +133,15 @@ def get_reference(self, value):
def free(self, name):
raise NotImplementedError


class BasicType(BaseType):

def pack_in(self, name):
return name
def __getattr__(self, attr):
if attr.endswith(("_py2", "_py3")):
raise AttributeError(attr)
if _compat.PY3:
return getattr(self, attr + "_py3")
return getattr(self, attr + "_py2")


class Boolean(BasicType):
class Boolean(BaseType):
GI_TYPE_TAG = GITypeTag.BOOLEAN

def check(self, name):
Expand All @@ -153,6 +152,9 @@ def check(self, name):
def pack(self, name):
return name

def pack_in(self, name):
return name

def unpack(self, name):
return self.parse("""
$bool = $_.bool($value)
Expand All @@ -164,7 +166,7 @@ def new(self):
""")["value"]


class Int32(BasicType):
class Int32(BaseType):
GI_TYPE_TAG = GITypeTag.INT32

def check(self, name):
Expand All @@ -185,6 +187,9 @@ def pack(self, valid):
$c_value = $ffi.cast("gint32", $value)
""", value=valid)["c_value"]

def pack_in(self, name):
return name

def unpack(self, name):
raise NotImplementedError

Expand All @@ -195,22 +200,43 @@ def new(self):
""")["value"]


class Utf8(BasicType):
class Utf8(BaseType):
GI_TYPE_TAG = GITypeTag.UTF8

def check(self, name):
def check_py3(self, name):
if self.may_be_null:
return self.parse("""
if $value is not None:
if isinstance($value, $_.str):
$string = $value.encode("utf-8")
else:
$string = $value
else:
$string = None
""", value=name)["string"]

return self.parse("""
if isinstance($value, $_.str):
$string = $value.encode("utf-8")
elif not isinstance($value, $_.bytes):
raise TypeError
else:
$string = $value
""", value=name)["string"]

def check_py2(self, name):
if self.may_be_null:
return self.parse("""
if $value is not $_.None:
if $value is not $none:
if isinstance($value, $_.unicode):
$string = $value.encode("utf-8")
elif not isinstance($value, $_.str):
raise $_.TypeError("%r not a string or None" % $value)
else:
$string = $value
else:
$string = $_.None
""", value=name)["string"]
$string = $none
""", value=name, none=None)["string"]

return self.parse("""
if $_.isinstance($value, $_.unicode):
Expand All @@ -221,14 +247,22 @@ def check(self, name):
$string = $value
""", value=name)["string"]

def pack(self, name):
def pack_py2(self, name):
return self.parse("""
if $value:
$c_value = $value
else:
$c_value = $ffi.cast("char*", 0)
""", value=name)["c_value"]

def pack_py3(self, name):
return self.parse("""
if $value is not None:
$c_value = $value
else:
$c_value = $ffi.cast("char*", 0)
""", value=name)["c_value"]

def dup(self, name):
raise NotImplementedError

Expand All @@ -252,7 +286,7 @@ def parse(self, code, **kwargs):
kwargs["ffi"] = self._ffi

assert "_" not in kwargs
kwargs["_"] = __builtin__
kwargs["_"] = _compat.builtins

block, var = parse_with_objects(code, self.var, **kwargs)
return block, var
Expand Down
40 changes: 32 additions & 8 deletions pgi/codegen/ctypes_backend.py
Expand Up @@ -699,14 +699,21 @@ def unpack(self, name):
param_type = self.type.get_param_type(0)
ctypes_type = typeinfo_to_ctypes(param_type)

p = self.get_type(param_type)
item_in = self.var()
item_out = p.unpack(item_in)

return self.parse("""
$out = []
$elm = $in_
while $elm:
$entry = $elm.contents
$out.append($ctypes_type($entry.data or 0).value)
$item_in = $ctypes_type($entry.data or 0).value
$item_unpack
$out.append($item_out)
$elm = $entry.next
""", in_=name, ctypes_type=ctypes_type)["out"]
""", in_=name, ctypes_type=ctypes_type, item_in=item_in,
item_out=item_out, item_unpack=p.block)["out"]

def free(self, name):
return self.parse("""
Expand Down Expand Up @@ -1227,24 +1234,41 @@ def unpack(self, name, length):

# fixme: do unpack with param type

p = self.get_type(param_type)
item_in = self.var()
item_out = p.unpack(item_in)

if self.type.array_length != -1:
return self.parse("""
$out = $array[:$length.value]
""", array=data, length=length)["out"]
$out = []
for $item_in in $array[:$length.value]:
$unpack_item
$out.append($item_out)
#$out = $array[:$length.value]
""", array=data, length=length, unpack_item=p.block,
item_in=item_in, item_out=item_out)["out"]

elif self.type.array_fixed_size != -1:
return self.parse("""
$out = $array[:$length]
""", array=data, length=self.type.array_fixed_size)["out"]
$out = []
for $item_in in $array[:$length]:
$unpack_item
$out.append($item_out)
""", array=data, length=self.type.array_fixed_size, unpack_item=p.block,
item_in=item_in, item_out=item_out)["out"]
else:
return self.parse("""
$list = []
$i = 0
$current = $array and $array[$i]
while $current:
$list.append($current)
$item_in = $current
$unpack_item
$list.append($item_out)
$i += 1
$current = $array[$i]
""", array=data)["list"]
""", array=data, unpack_item=p.block,
item_in=item_in, item_out=item_out)["list"]

def new(self, length_type):
if self.type.array_length != -1:
Expand Down
5 changes: 5 additions & 0 deletions pgi/enum.py
Expand Up @@ -5,6 +5,7 @@
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.

import sys
import ctypes

from .clib.gobject import GEnumClassPtr, GFlagsClassPtr
Expand Down Expand Up @@ -47,6 +48,8 @@ def value_name(self):
def __new__(cls, value):
if not isinstance(value, integer_types):
raise TypeError("int expected, got %r instead" % type(value))
if value > sys.maxsize:
raise OverflowError
instance = EnumBase.__new__(cls, value)
if value in cls._allowed:
return instance
Expand Down Expand Up @@ -114,6 +117,8 @@ def first_value_name(self):
def __new__(cls, value):
if not isinstance(value, integer_types):
raise TypeError("int expected, got %r instead" % type(value))
if value > sys.maxsize:
raise OverflowError
return FlagsBase.__new__(cls, value)

def __repr__(self):
Expand Down
2 changes: 2 additions & 0 deletions setup.py
Expand Up @@ -233,6 +233,8 @@ def run(self):
'Operating System :: OS Independent',
'Programming Language :: Python :: 2',
'Programming Language :: Python :: 2.7',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.3',
'Programming Language :: Python :: Implementation :: CPython',
'Programming Language :: Python :: Implementation :: PyPy',
],
Expand Down
5 changes: 5 additions & 0 deletions tests/tests_mixed/test_funcs.py
Expand Up @@ -32,6 +32,11 @@ def test_basic_argument(self):
self.assertEqual(GLib.basename("/omg/foo/test"), "test")
self.assertEqual(GLib.basename(u"/omg/foo/test"), "test")

def test_basic_utf8_arg(self):
b = Gtk.Button()
b.set_name("foobar")
self.assertEqual(b.get_name(), "foobar")

def test_return_guint(self):
self.assertTrue(isinstance(Gtk.get_binary_age(),
_compat.integer_types))
Expand Down
4 changes: 0 additions & 4 deletions tests/tests_mixed/test_objects.py
Expand Up @@ -18,10 +18,6 @@
except ImportError:
Clutter = None
else:
# FIXME: marshalling of string arrays is missing the decoding in PY3
# and the previous Gtk.init call changed sys.argv to bytes
if sys.version_info[0] == 3:
sys.argv = []
status, argv = Clutter.init(sys.argv)
if status == Clutter.InitError.SUCCESS:
sys.argv = argv
Expand Down
29 changes: 29 additions & 0 deletions tests/tests_pgi/test_pgi_codegen_backends.py
@@ -0,0 +1,29 @@
# Copyright 2014 Christoph Reiter
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.

import unittest

from pgi.codegen.cffi_backend import CFFIBackend
from pgi.codegen.ctypes_backend import CTypesBackend


class _TBackend(unittest.TestCase):

Backend = None

def test_misc(self):
backend = self.Backend()
lib = backend.get_library("GObject")
self.assertTrue(lib)


class TBackendCFFI(_TBackend):
Backend = CFFIBackend


class TBackendCTypes(_TBackend):
Backend = CTypesBackend

0 comments on commit 982914a

Please sign in to comment.