Этот вопрос характерен для использования django-q
с Django ORM в качестве бэкэнда очереди, поскольку основной причиной, по-видимому, является использование pickle
в их модели Django. (Тем не менее, pickle
может использоваться для других бэкэндов в django-q
.)
Проблема
При портировании существующего приложения с использованием django-q
на Python 3, я заметил, что в строках регистрации появляются жалобы на следующее:
2019-05-06 09:52:12,859 ERROR django-q: invalid syntax (<unknown>, line 1) [in /usr/local/lib/python3.6/dist-packages/django_q/cluster.py:558, 140417530787648 (MainThread), 27943 (Process-1)]
Traceback (most recent call last):
File "/usr/local/lib/python3.6/dist-packages/django_q/cluster.py", line 506, in scheduler
args = ast.literal_eval(s.args)
File "/usr/lib/python3.6/ast.py", line 48, in literal_eval
node_or_string = parse(node_or_string, mode='eval')
File "/usr/lib/python3.6/ast.py", line 35, in parse
return compile(source, filename, mode, PyCF_ONLY_AST)
File "<unknown>", line 1
(320L,)
^
SyntaxError: invalid syntax
(Обратите внимание, что если вы используете django-q
, вы фактически не получите трассировку: я отредактировал строку регистрации в
django_q/cluster.py
до logger.exception
вместо logger.error
.)
Эта ошибка имеет смысл, потому что django-q
хранил длинные целые числа (в данном случае идентификаторы модели) с завершающим L
(pickle
снова наносит удар). Хотя в Python 2 работает следующее, в Python 3 не удается выполнить синтаксический анализ:
>>> import ast
>>> ast.literal_eval('(320L,)')
File "<unknown>", line 1
(320L,)
^
SyntaxError: invalid syntax
Возможные решения
Я думаю, что мои варианты:
- Написать миграцию для преобразования длинных целых
- Используйте регулярные выражения для преобразования целых чисел
- Используйте
2to3
для преобразования данных (которые будут обрабатывать другие типы данных в дополнение к целым числам)
- Патч
django-q
для отлова SyntaxError
и преобразования данных
- Используйте либо регулярное выражение или
2to3
для преобразования данных
В библиотеке lib2to3
есть предупреждения о нестабильном API, но что-то вроде этого работает для меня (на Python 3.6):
from lib2to3.refactor import RefactoringTool, get_fixers_from_package
refactoring_tool = RefactoringTool(fixer_names=get_fixers_from_package('lib2to3.fixes'))
def convert_data_2to3(pickled_data):
# Add new-line: refactoring tool requires lines of code.
data = pickled_data + '\n'
node = refactoring_tool.refactor_string(data, 'convert_data_2to3')
return str(node).rstrip() # Strip the newline added earlier
Вопрос
Ни один из вышеперечисленных вариантов не кажется отличным. Любые другие варианты?