#python #pickle
Вопрос:
Рассмотрим следующий тестовый код, выполняемый с python -m unittest discover
:
#!/usr/bin/python
"""
Tests for the mappings module.
"""
#Unittest module.
import unittest
#Module to test.
import eeep.lib.collections.mappings as mappings
#Standard library imports.
import pickle
class TestPicklingPointInstances(unittest.TestCase):
"""Test pickling of Point instances."""
@classmethod
def setUpClass(cls):
cls.Point = mappings.makeRecord(["x", "y"],
name = "Point",
doc = "The Point record class.",
qualname = "TestPicklingPointInstances.Point",
module = "eeep.tests.lib.collections.test_mappings")
def setUp(self):
self.point = self.Point(x = 0, y = 1)
def testClassAttributes(self):
self.assertEqual(self.Point.__qualname__, "TestPicklingPointInstances.Point")
self.assertEqual(self.Point.__module__, "eeep.tests.lib.collections.test_mappings")
def testPickling(self):
self.assertEqual(self.point, pickle.loads(pickle.dumps(self.point)))
#Run tests.
if __name__ == "__main__":
unittest.main()
Выше приведен код тестирования для фабрики классов makeRecord
. Точные детали на самом деле не имеют значения, но это фабрика классов перед классами, напоминающими ваниль namedtuple
. Поскольку это класс, который создается во время выполнения, чтобы сделать его экземпляры доступными для маринования, он реализует __getstate__
и __setstate__
. Чтобы охватить случаи, когда класс не находится на уровне модуля, makeRecord
имеет qualname
и module
параметры. Фабрика подбирает их и устанавливает магические атрибуты __qualname__
и __module__
. Это проверено, testClassAttributes
и тест проходит с честью. Все остальные функциональные тесты (опущенные для краткости) также проходят. Пока все хорошо.
Однако, когда дело доходит до самого маринования, последний тест заканчивается (путь к файлу переписан с родительским корнем проекта, замененным корнем):
Traceback (most recent call last):
File "root/eeep/tests/lib/collections/test_mappings.py", line 173, in testPickling
self.assertEqual(self.point, pickle.loads(pickle.dumps(self.point)))
_pickle.PicklingError: Can't pickle <class 'eeep.tests.lib.collections.test_mappings.TestPicklingPointInstances.Point'>: attribute lookup TestPicklingPointInstances.Point on eeep.tests.lib.collections.test_mappings failed
Я не понимаю, что здесь происходит. Похоже, что при поиске класса механизм травления пытается найти TestPicklingPointInstances.Point
(правильный) в eeep.tests.lib.collections.test_mappings
(правильно; это также соответствует текущему тестируемому файлу-здесь, по-моему, нет проблем с самостоятельной ссылкой). Файл доступен для импорта (есть __init__.py
вход eeep/tests/lib/collections
). Должно быть, я где-то что-то упускаю, скорее всего, во взаимодействии между травильным и импортным оборудованием, но я просто не могу понять, что именно.