Уведомления

Группа в Telegram: @pythonsu

#1 Янв. 29, 2018 18:34:01

paradox81ru
Зарегистрирован: 2017-03-26
Сообщения: 27
Репутация: +  0  -
Профиль   Отправить e-mail  

Проблема с Pillow

Код изменил, но результат пока тот же. Вот измененный код:

 import os
import random
from PIL import Image, ImageDraw, ImageFont, ImageChops, ImageColor, ImageFilter
from django.conf import settings
class Captcha:
    def __init__(self, destination,
                 trash_range=15,
                 code_range=5,
                 offset=50,
                 font_size=40,
                 base_size=(250, 50)):
        self._destination = destination
        self._trash_range = trash_range
        self._code_range = code_range
        self._offset = offset
        self._font_size = font_size
        self._base_size = base_size
        self._letters = self._letters()
        self._font_path = self._font_path()
    @classmethod
    def _random_fill(cls, red=255, green=255, blue=255):
        """ Случайный цвет RGB """
        fill = (random.randrange(red),
                random.randrange(green),
                random.randrange(blue))
        return fill
    @classmethod
    def _random_font(cls, path='fonts', s1=12, s2=35, main=None):
        """ Случайный шрифт """
        if main is None:
            size = random.randrange(s1, s2)
        else:
            size = main
        font_files = os.listdir(path)
        r_font = os.path.join(path, random.choice(font_files))
        font = ImageFont.truetype(r_font, size)
        return font
    @classmethod
    def _random_coords(cls, coords=(250, 50)):
        """ Случайные координаты """
        coords = (random.randrange(0, coords[0]),
                  random.randrange(0, coords[1]))
        return coords
    @classmethod
    def _letters(cls):
        """ Создает и возвращает кортеж символов """
        letters = (
            'a', 'b', 'c', 'd', 'e', 'f',
            'g', 'h', 'j', 'k', 'm', 'n',
            'p', 'q', 'r', 's', 't', 'u',
            'v', 'w', 'x', 'y', 'z',
            '0', '1', '2', '3', '4', '5',
            '6', '7', '8', '9'
        )
        # или, лучше воспользуемся готовыми наборами:
        # letters = tuple(string.ascii_lowercase + string.digits)
        return letters
    @classmethod
    def _font_path(cls):
        """ Возвращает папку со шрифтами"""
        return os.path.join(settings.BASE_DIR, r'common\helpers\fonts')
    # Не используется
    def _draw_trash_letters(self, img_drw):
        """ Рисует мусор из светных символов """
        for i in range(self._trash_range):
            img_drw.font = self._random_font(self._font_path)
            img_drw.text(self._random_coords(self._base_size), random.choice(self._letters), self._random_fill())
    def _draw_trash_lines(self, img_drw):
        """
        Рисуте мусор из прямых линий
        :type img_drw: ImageDraw.Draw
        :return:
        """
        img_drw.line(self._rand_line('h'), ImageColor.getrgb("Black"), 2)
        img_drw.line(self._rand_line('h'), ImageColor.getrgb("Black"), 2)
        img_drw.line(self._rand_line('v'), ImageColor.getrgb("Black"), 2)
        img_drw.line(self._rand_line('v'), ImageColor.getrgb("Black"), 2)
    def _rand_line(self, direction):
        """
        Возвращает случайные линии горизонтальные или вертикальные
        :param direction: направление линии 'h' или 'v'
        :return:
        """
        direction = direction.lower()
        if direction not in ('h', 'v'):
            raise ValueError("Координаты могут быть только 'h' или 'v'")
        if direction == 'h':
            max_size = self._base_size[1]
            cord1 = random.randint(1, max_size-2)
            cord2 = random.randint(1, max_size-2)
            line_coord = [0, cord1, 250, cord2]
        else:
            max_size = self._base_size[0]
            cord1 = random.randint(1, max_size-2)
            cord2 = random.randint(1, max_size-2)
            line_coord = [cord1, 0, cord2, 50]
        return line_coord
    def _draw_code_img(self, img_drw, code):
        """ Создает и возвращает изображение с кодом капчи"""
        x = 0
        offset = random.randrange(30, self._offset)
        for c in code:
            img_drw.text((x, 0), c, 'black', font=self._random_font(self._font_path, main=self._font_size))
            x += offset
    def captcha(self):
        # Если установлен режим отладки и отключена капча,
        if settings.DEBUG and settings.NO_CAPTCHA:
            # то сделаем капчу равной "12345".
            code = list('12345')
        else:
            # Иначе генерируем случайный набор символов из списка символов в пределах.
            code = [random.choice(self._letters) for i in range(self._code_range)]
        img = Image.new("RGBA", self._base_size, 'white')
        img_drw = ImageDraw.Draw(img)
        # Создаем первое изображение с мусором — случайными символами
        self._draw_trash_lines(img_drw)
        self._draw_code_img(img_drw, code)
        # Сохраняем изображение
        img.save(self._destination, 'PNG')
        # И возвращаем строку
        return ''.join(code)
    def __call__(self, *args, **kwargs):
        return self.captcha()
Хотя реакция как раз на создание Image, если раньше ошибка появлялась парно, то после того как создается один Image, ошибка стала выходить по одному разу.

Отредактировано paradox81ru (Янв. 29, 2018 18:36:41)

Офлайн

#2 Янв. 29, 2018 19:06:31

Rodegast
От: Пятигорск
Зарегистрирован: 2007-12-28
Сообщения: 2750
Репутация: +  184  -
Профиль   Отправить e-mail  

Проблема с Pillow

Странно у меня этой ошибки нет. Попробуй избавится от virtual event. Но перед этим зайди на сервер, запусти python и попробуй ввести что-то вроде hasattr(“”, “upper”).



С дураками и сектантами не спорю, истину не ищу.
Ели кому-то правда не нравится, то заранее извиняюсь.

Отредактировано Rodegast (Янв. 29, 2018 19:07:19)

Офлайн

#3 Янв. 30, 2018 02:28:45

scidam
Зарегистрирован: 2016-06-15
Сообщения: 288
Репутация: +  35  -
Профиль   Отправить e-mail  

Проблема с Pillow

У вас вероятно этот случай..

И еще, после img.save() целесообразно вызвать img.close().

Офлайн

#4 Янв. 30, 2018 06:25:06

paradox81ru
Зарегистрирован: 2017-03-26
Сообщения: 27
Репутация: +  0  -
Профиль   Отправить e-mail  

Проблема с Pillow

scidam

У вас вероятно этот случай..

И еще, после img.save() целесообразно вызвать img.close().
Да, я видел этот пост, действительно ситуация точно как моя, но решение проблемы там не указано. Там ссылаются на то, что код питона работающий в отдельном потоке, продолжает работать после того, как уничтожается интерпретатор питона при завершении основного. Но, во первых я никакие потоки не создаю, если только они не создаются в пакете Pillow, да и мало чего-то мне вериться, что интерпретатор питона будет уничтожаться, если все еще работает хотя бы один поток, который управляется этим интерпретатором, это уже тогда скорее будет довольно серьезная ошибка интерпретатора. Хотя, как я читал, многопоточность действительно не самая сильная сторона питона. Но, по любому, я сам никакие потоки не создавал.

Офлайн

#5 Янв. 30, 2018 08:35:50

scidam
Зарегистрирован: 2016-06-15
Сообщения: 288
Репутация: +  35  -
Профиль   Отправить e-mail  

Проблема с Pillow

Вот пример
как в подобной ситуации переписали __del__ функцию, чтобы она не содержала hasattr.

Я не призываю, однако, изменять Image.py, но попробовать стоит, и если это решит проблему, вполне можно и предложить pull request для __del__ в Image.py, там __del__ небольшой.

Более глубже, почему так, т.е. почему builtins функции недоступны (уже очищены), когда выполняется __del__ , не разбирался.





Офлайн

#6 Янв. 30, 2018 19:12:29

paradox81ru
Зарегистрирован: 2017-03-26
Сообщения: 27
Репутация: +  0  -
Профиль   Отправить e-mail  

Проблема с Pillow

scidam
ДА-ДА-ДА!!! Scidam, я Вам премного благодарен, благодаря Вам я все таки решил проблему. Но, все по порядку.
Я попробовал изменить код, как Вы посоветовали, чтобы убрать hasattr. Капча так и не работает, а ошибка в логе стала немного другая:

 Exception ignored in: <object repr() failed>
Traceback (most recent call last):
  File "/var/pyprojects/paradox-portal/pythonProject/venv3.6/lib/python3.6/site-packages/PIL/Image.py", line 593, in __del__
NameError: name 'AttributeError' is not defined
Но принципиально ничего не изменилось. Раньше терял встроенную функцию, теперь теряет встроенный класс исключения.
Но я на этом не остановился, и решил вообще убрать все из __del__, закрыл его просто pass, после чего ошибка в логе пропала, но капча так появляться и не стала. Тогда я решил все таки еще раз запустить рабочий сайт в режиме debug (да, я знаю что этого ни в коем случае делать нельзя, но, во первых сайт у меня в разработке, во вторых он закрыт режимом MAINTENANCE_MODE, т.е. выдает только одну страницу о том что сайт в разработке, а в третьих, зачем вообще этот сайт нужен, если он адекватно не работает ), и наконец то увидел реальную ошибку, оказалось что я просто неправильно указал путь к шрифтам для отображения символьных кодов в капче, слэши поставил не в ту сторону, в сырой строке они экранировались что ли, двойными становились, и если винды это как-то переваривали, то для ubuntu оказалось смертельно. А ведь раньше сайт в debug режиме тоже мне показывал эту лабуду про отсутствующий hasattr. Блин, с института ведь еще помню, что если 2+2=5, то виноват не компьютер, а сам дурак, ищи ошибку. Но с другой стороны, как вот ее искать, если ошибка одна, а показывает совсем другое.
Спасибо большое Scidam, проблема решена.

Отредактировано paradox81ru (Янв. 30, 2018 19:39:46)

Офлайн

Board footer

Модераторировать

Powered by DjangoBB

Lo-Fi Version