Ошибка типа: несвязанный метод __init __ () .... во время модульных тестов после переупаковки - PullRequest
1 голос
/ 02 августа 2010

Я только что переупаковал свою программу. Ранее все модули жили в пакете "Whyteboard", с пакетом "Fakewidgets", содержащим кучу фиктивных объектов тестирования GUI.

Теперь все мои модули находятся в пакетах, например whyteboard.gui, whyteboard.misc, whyteboard.test - вот где сейчас живут fakewidgets.

Теперь, когда я запускаю мои тесты, я получаю исключение,

  File "/home/steve/Documents/whyteboard/whyteboard/gui/canvas.py", line 77, in __init__
    wx.ScrolledWindow.__init__(self, tab, style=wx.NO_FULL_REPAINT_ON_RESIZE | wx.CLIP_CHILDREN)
TypeError: unbound method __init__() must be called with ScrolledWindow instance as first argument (got Canvas instance instead)

здесь рассматриваемый класс

class Canvas(wx.ScrolledWindow):
    def __init__(self, tab, gui, area):
        wx.ScrolledWindow.__init__(self, tab, style=wx.NO_FULL_REPAINT_ON_RESIZE | wx.CLIP_CHILDREN)

Однако моя программа загружается и работает правильно, за исключением тестов модулей. Код такой же, только код для импорта моих тестов отличается от новых пакетов.

До:

import os
import wx

import fakewidgets
import gui
import lib.mock as mock

from canvas import Canvas, RIGHT, DIAGONAL, BOTTOM
from fakewidgets.core import Bitmap, Event, Colour

from lib.configobj import ConfigObj
from lib.pubsub import pub
from lib.validate import Validator

сейчас:

import os
import wx

import whyteboard.test
import whyteboard.gui.frame as gui

from whyteboard.lib import ConfigObj, mock, pub, Validator
from whyteboard.gui.canvas import Canvas, RIGHT, DIAGONAL, BOTTOM
from whyteboard.test.fakewidgets.core import Bitmap, Event, Colour, PySimpleApp

Возможно, стоит отметить, что пакет fakewidgets заставляет мою программу думать, что она использует классы wxPython, хотя они и являются ложными. Это из модуля, который импортирован whyteboard.test.fakewidgets '__init__

class Window(object):
    def __init__(self, parent, *args, **kwds):
        self.parent = parent
        self.Enabled = True
        self.calls = []
        self.size = (0, 0)
        self.captured = False

    def GetClientSizeTuple(self):
        return (0, 0)
        self.captured = True

    def GetId(self):
        pass

    def Fit(self):
        pass

    def SetFocus(self):
        pass

    def PrepareDC(self, dc):
        pass

    def Destroy(self):
        pass

...


class ScrolledWindow(Window):
    def SetVirtualSize(self, *size):
        pass

    def SetVirtualSizeHints(self, *size):
        pass

import wx
wx.__dict__.update(locals())

Ответы [ 4 ]

3 голосов
/ 31 августа 2010

когда вы import whyteboard.test, автоматически ли запускается whyteboard.test.fakewidgets.core?Я думаю, что проблема в том, что Canvas создается до того, как запускается код проверки.Это объясняет переключение.

>>> import wx
>>> class Test1(wx.Window):
...    pass
... 
>>> wx.Window = object
>>> class Test2(wx.Window):
...    pass
... 
>>> dir(Test1)[:10]
['AcceleratorTable', 'AcceptsFocus', 'AcceptsFocusFromKeyboard', 
 'AddChild', 'AddPendingEvent', 'AdjustForLayoutDirection', 
 'AssociateHandle', 'AutoLayout', 'BackgroundColour', 'BackgroundStyle']
>>> dir(Test2)[:10]
['__class__', '__delattr__', '__dict__', '__doc__', '__format__', 
 '__getattribute__', '__hash__', '__init__', '__module__', '__new__']

В старом файле, который вы разместили, fakewidgets был импортирован до canvas.

Если это не сработает, поместите этот код непосредственно после import wx перед любымдругие операции импорта:

import inspect

class DummyMeta(type):
    def __new__(meta, clsname, bases, clsdict):
        if clsname == 'Canvas':
            lineno = inspect.stack()[1][2]
            print "creating Canvas with mro: {0}".format(inspect.getmro(bases[0]))
            print "file:{0}:{1}".format(__file__, lineno)
        return super(DummyMeta, meta).__new__(meta, clsname, bases, clsdict)

class ScrolledWindowDummy(wx.Window):
    __metaclass__ = DummyMeta

wx.ScrolledWindow = ScrolledWindowDummy

Это покажет, что класс Canvas создается до того, как наложено на насмешку, и даст вам номер файла и строки, где это происходит.по существу, для MRO вы не должны видеть ничего из wx.Если я не прав, то вы вообще ничего не увидите, потому что вы замените ScrolledWindowDummy классом, который не имеет типа DummyMeta, до того, как будет создан любой класс с именем Canvas.

1 голос
/ 03 сентября 2010

Убедитесь, что fakewidgets первым импортирует модуль wx. Это означает, что порядок импорта важен, например,

import fakewidgets
import wx

Кроме того, вместо трюка dict .update,замените имена явно, т.е.

import wx

wx.Window = Window
# for all other relevant widgets

Опять же, все равно убедитесь, что fakewidgets первым получил доступ к модулю wx.

1 голос
/ 31 августа 2010

Пожалуйста, напечатайте wx и wx.ScrolledWindow как до определения class Canvas, так и в качестве первой строки Canvas.__init__.Я сильно подозреваю, что они будут другими.

Вы делаете какие-то хитрости с __new__ или метаклассами или тому подобным?

1 голос
/ 02 августа 2010

Код такой же, только код для импорта моих тестов отличается от новых пакетов

Звучит так, как будто ваш импорт импортирует то, что вы не делалиожидать.Однажды я назвал один из моих файлов таким же, как системный модуль.Мне потребовались часы, чтобы понять, что пошло не так.

Посмотрите, что произойдет, когда вы измените sys.path.

...