Как изменить строку документации класса TestCase в Python?

В Python 2.5 (на самом деле Jython) для класса UnitTest TestCase - нет метода SetUpClass, и __init__ на самом деле неприемлемо (без ссылки на себя). Когда я пытаюсь изменить строку документации внутри TestCase:

import os
fileName = os.path.split(__file__)[1]
testCaseName = os.path.splitext(fileName)[0]
setattr(__name__, '__doc__', testCaseName)

Я собираюсь:

setattr(__name__, '__doc__', testCaseName)
TypeError: readonly attribute

Я попытался изменить строку документации, превратив ее в объект (где self.__doc__ доступен для записи).

ОБНОВЛЕНО: но я хочу избежать дополнительного кодирования в подклассе (т.е. наследования функции суперкласса для установки строки документации подкласса), например:

Файл DynamicTestCase.py включает:

class DynamicTestCase(unittest.TestCase):
    def setDocstring(self, testCaseDocstring=None):
        if not testCaseDocstring:
            fileName = os.path.split(__file__)[1]
            testCaseDocstring = os.path.splitext(fileName)[0]
        setattr(self, '__doc__', testCaseDocstring)

Файл MyTestCase.py включает:

class MyTestCase(DynamicTestCase):
    def test_print_docstring(self):
        self.setDocstring()
        print 'MyTestCase Docstring = ', self.__doc__

Но тем не менее, результат запуска unittest:

MyTestCase Docstring = DynamicTestCase

Когда я ожидал MyTestCase Docstring = MyTestCase


person Noam Manos    schedule 01.05.2011    source источник


Ответы (2)


Обновлено – __file__ – это путь, по которому был загружен текущий модуль, поэтому, естественно, использование __file__ внутри DynamicTestCase.py приведет к получению пути DynamicTestCase.py. Однако вы можете просто передать путь в setDocstring() из подклассов следующим образом:

DynamicTestCase.py:

class DynamicTestCase(unittest.TestCase):
    def setDocstring(self, docstring=None):
        if docstring is None:
            docstring = __file__
        if os.path.exists(docstring):
            name = os.path.split(docstring)[1]
            docstring = os.path.splitext(name)[0]
        setattr(self, '__doc__', docstring)

MyTestCase.py:

class MyTestCase(DynamicTestCase):
    def __init__(self, *args, **kwargs):
        DynamicTestCase.__init__(self, *args, **kwargs)
        self.setDocstring(__file__)

    def test_print_docstring(self):
        print 'MyTestCase Docstring = ', self.__doc__

    def test_new_docstring(self):
        self.setDocstring('hello')
        print 'MyTestCase Docstring = ', self.__doc__

Выход:

MyTestCase Docstring =  MyTestCase
MyTestCase Docstring =  hello

Остальная часть ответа

В вашем исходном коде выше __name__ - это строка, а не класс. Jython справедливо отвергает изменение атрибута __doc__ для типа str.

Не могли бы вы немного объяснить, почему вы хотите изменить строку документации TestCase? Например, вы можете создать подкласс TestCase и указать свою собственную строку документации:

class MyTestCase(unittest.TestCase):
    "Docstring of MyTestCase"

Не уверен, пробовали ли вы его, но в TestCase пакета unittest2 есть setUpClass, tearDownClass методов класса. Это бэкпорт улучшений Python 2.7 для работы с Python 2.6 и более ранними версиями.

Jython позволяет вам установить __doc__ классов нового стиля, а CPython — нет. По этой причине вы можете найти другой способ достижения своей цели, если хотите, чтобы ваш код был переносимым:

Jython 2.2.1 on java1.6.0_24
>>> unittest.TestCase.__doc__ = 'foo bar'
>>> unittest.TestCase.__doc__
'foo bar'

Python 2.6.6 (r266:84292, Feb 12 2011, 01:07:21)
>>> unittest.TestCase.__doc__ = 'foo bar'
AttributeError: attribute '__doc__' of 'type' objects is not writable
person samplebias    schedule 01.05.2011
comment
Спасибо Samplebias, я попытался изменить строку документации TestCase, прежде чем добавлять ее модуль в testLoader: code(unittest.defaultTestLoader.loadTestsFromName(testCase)) - person Noam Manos; 02.05.2011
comment
Но поскольку TestCase doc недоступен для записи, сейчас я пытаюсь сделать это, как вы предложили, в подклассе: def setDocstring(self): fileName = os.path.split(__file__)[1] testCaseDocstring = os.path.splitext(fileName)[0] setattr(self, '__doc__', testCaseDocstring) Однако эта функция тоже не работает, потому что при ее использовании подкласс -class docstring всегда получает имя файла суперкласса вместо текущего имени файла подкласса. - person Noam Manos; 02.05.2011
comment
Я обновлю ответ тем, что я имел в виду, изменив его в подклассе TestCase. Можете ли вы привести пример проблемы, которую вы пытаетесь решить, изменив строку документации класса? - person samplebias; 02.05.2011
comment
Обновлен вопрос: установка строки документации подкласса с текущим именем файла, что тоже не работает - person Noam Manos; 03.05.2011
comment
@Noam Проверьте мое последнее обновление выше - я изменил ваш метод DynamicTestCase.setDocstring для работы либо со строкой, либо с путем. - person samplebias; 04.05.2011
comment
Отличный сэмплбиас, два зайца в одном кадре! Вы также решили мою старую неприятную ошибку, когда я пытался использовать обычную функцию def __init__ (self) внутри подкласса TestCase, которая всегда терпела неудачу с: TypeError: __init__() takes exactly 1 argument (2 given). Но теперь не более :) - person Noam Manos; 04.05.2011
comment
@samplebias К сожалению, на самом деле не работает, так как я пытался избежать ввода в каждый из моих подклассов TestCase функции Docstring. есть ли способ сделать это без объявления в MyTestCase.py? - person Noam Manos; 04.05.2011

Вы захватываете имя файла DynamicTestCase, а не файл, который вызывает функцию. Чтобы получить это, вам нужно войти в его кадр стека:

  import inspect

  class DynamicTestCase(unittest.TestCase):
    def setDocstring(self, testCaseDocstring=None):
        if not testCaseDocstring:
            fileName = 'unknown.py'

            # Go up one stack frame and grab the file name
            stack = inspect.stack()
            try:
                frame = stack[1][0]
                fileName = frame.f_code.co_filename        
            finally:
                del stack

            testCaseDocstring = os.path.splitext(fileName)[0]
person Joseph Lisee    schedule 03.05.2011