• Зачем нужен celery?

    ri_gilfanov
    @ri_gilfanov
    Web- and desktop-developer
    Например, очередь заданий по конвертации видео для веб-приложения на Django.

    Попытка выполнять такую задачу в Django непосредственно при обработке запросов по-умолчанию будет приводить к 504 Gateway Timeout (слишком долгий запрос) со стороны Nginx или иного HTTP-сервера.

    Попытка делать это с помощью Cron и произвольных команд Django -- немного неудобна. Допустим, Cron выполняет произвольную команду Django раз в 1 минуту:
    python3 path/manage.py convert_next_video
    , при этом первый видео файл будет конвертироваться 5 минут, после этого будет помечен в базе данных как is_converted (конвертирован) и команда на этом завершится. Через минуту cron снова запустит команду для конвертации следующего файла.

    Но за 5 минут файл ещё не будет помечен как конвертированный, поэтому cron за 5 минут создаст 4-5 процессов, которые будут конвертировать один и тот же файл.

    Ладно, тогда при начале конвертирования файл сразу будем помечать как конвертируемый, чтобы другие процессы брали другие файлы.

    Но что будет если процесс упадёт? Отмечать время начала конвертирования в базе данных и если прошло больше n часов, конвертировать повторно -- так себе решение.

    И что если пользователи загрузят 10 файлов каждый из которых будет конвертироваться 30 минут? Через 10-11 минут на сервере будут работать 10 процессов конвертирующих видео. Большая нагрузка на сервер. Можно завести в базе данных таблицу в которой отмечается сколько файлов конвертируется в данный момент.

    Решив использовать cron для долгих по выполнении задач, нам придётся решать целый ряд проблем.
    Ответ написан
    3 комментария
  • Как найти частичное совпадение строк?

    ri_gilfanov
    @ri_gilfanov
    Web- and desktop-developer
    Без дополнительных библиотек и с использованием расстояния Дамерау-Левенштейна можно примерно так:
    import re
    
    
    def get_substrings(string):
        """Функция разбивки на слова"""
        return re.split('\W+', string)
    
    
    def get_distance(s1, s2):
        """Расстояние Дамерау-Левенштейна"""
        d, len_s1, len_s2 = {}, len(s1), len(s2)
        for i in range(-1, len_s1 + 1):
            d[(i, -1)] = i + 1
        for j in range(-1, len_s2 + 1):
            d[(-1, j)] = j + 1
        for i in range(len_s1):
            for j in range(len_s2):
                if s1[i] == s2[j]:
                    cost = 0
                else:
                    cost = 1
                d[(i, j)] = min(
                    d[(i - 1, j)] + 1,
                    d[(i, j - 1)] + 1,
                    d[(i - 1, j - 1)] + cost)
                if i and j and s1[i] == s2[j - 1] and s1[i - 1] == s2[j]:
                    d[(i, j)] = min(d[(i, j)], d[i - 2, j - 2] + cost)
        return(d[len_s1 - 1, len_s2 - 1])
    
    
    def check_substring(search_request, original_text, max_distance):
        """Проверка нечёткого вхождения одного набора слов в другой"""
        substring_list_1 = get_substrings(search_request)
        substring_list_2 = get_substrings(original_text)
    
        not_found_count = len(substring_list_1)
    
        for substring_1 in substring_list_1:
            for substring_2 in substring_list_2:
                if get_distance(substring_1, substring_2) <= max_distance:
                    not_found_count -= 1
    
        if not not_found_count:
            return True
    
    
    search_request = 'трубок использовали для прожигания'
    original_text = 'трубок использовали для прожигания стальковша.Замена воронки 18м 8сл. Разлита полностью'
    
    result = check_substring(search_request, original_text, max_distance=2)
    
    print(result)  # True если найдено, иначе None


    Можете доработать под свои задачи. Но учтите, нахождение расстояния Дамерау-Левенштейна в принципе ресурсоёмкая операция, тем более с реализацией на чистом Python. Например, искать вхождение подстроки в нескольких мегабайтах текста -- может быть довольно долго.

    Чтобы ускорить нахождение расстояния ДЛ, можно использовать реализацию для Python на языке Си: https://github.com/gfairchild/pyxDamerauLevenshtein

    Так же существуют менее точные, но более быстрые алгоритмы сравнения двух строк:
    https://habr.com/ru/post/114997/
    В PyPI и на GitHub должны быть библиотеки с готовыми реализациями наиболее востребованных из них.
    Ответ написан
    7 комментариев
  • Как разделить реализацию различных типов модели?

    ri_gilfanov
    @ri_gilfanov
    Web- and desktop-developer
    Может быть django-polymorphic подойдёт:
    https://django-polymorphic.readthedocs.io/en/stabl...

    При многотабличном наследовании, Django ORM по-умолчанию позволяет получать все записи родительской и дочерних моделей только как объекты класса родительской модели.

    Библиотека django-polymorphic позволяет, делая запрос объектов родительской модели, получать объекты разных классов (как родительской, так и дочерних моделей).

    Плюс там реализованы классы, позволяющие адаптировать админку Django к удобной работе с полиморфными данными.

    Например, иметь в админке единый подраздел для родительской и дочерних моделей с фильтром записей по типу, при создании проходить через промежуточную страницу с выбором типа, а так же скажем выбирать тип при создании записей в инлайн-полях. Причём, всё достаточно опционально.
    Ответ написан
    2 комментария
  • Почему функция и переменная не могут одинаково называться?

    ri_gilfanov
    @ri_gilfanov
    Web- and desktop-developer
    Более-менее корректный ответ мог бы выглядеть так.

    Большинство "слов" в коде на Python -- это имена-ссылки на объекты Python.

    И функции, и "переменные" -- это объекты Python.

    В любом пространстве имён могут хранится имена-ссылки как на функции, так и на "переменные".

    Имена в каждом пространстве имён уникальны, поэтому нельзя одинаково назвать и функцию, и переменную. При попытке так сделать, что-то новое займёт имя-ссылку чего-то старого.

    То же самое относится к классам, к объектам классов, к полям и методам классов и пр. Все объекты Python либо занимают уникальные имена в неком пространстве имён, либо не занимают вовсе (например, числа в списке доступны не по имени, а по индексу).

    P.S. Спасибо, вопрос поднял настроение.
    Ответ написан
    Комментировать
  • Способы построения API на Flask?

    ri_gilfanov
    @ri_gilfanov
    Web- and desktop-developer
    Читайте документацию к Flask-Restfull, там по английски написано, что они планируют удалить весь функционал, отвечающий за парсинг REST-запросов и планируют заменить соответствующий раздел документации на описание интеграции с другими библиотеками (например, с marshmallow).

    Warning

    The whole request parser part of Flask-RESTful is slated for removal and will be replaced by documentation on how to integrate with other packages that do the input/output stuff better (such as marshmallow). This means that it will be maintained until 2.0 but consider it deprecated. Don’t worry, if you have code using that now and wish to continue doing so, it’s not going to go away any time too soon.


    Я использовал связку Flask + Flask-Restfull + Webargs. Webargs -- это библиотека на основе marshmallow, упрощающая интеграцию marshmallow с различными Python веб-фреймворками, в том числе интеграцию с Flask.
    Ответ написан
    Комментировать
  • Как сделать datetime.timedelta в нужном формате?

    ri_gilfanov
    @ri_gilfanov
    Web- and desktop-developer
    Одним выражением:
    result = ' '.join([
        pattern.format(value) for value, pattern in zip(
            (x.days, x.seconds//3600, (x.seconds//60)%60, x.seconds),
            ('{} д.', '{} час.', '{} мин.', '{} сек.'),
        )
        if value
    ])


    Падежи русского и других флективных языков (например, 1 час, но 2 часа и 8 часов) -- отдельный вопрос. Проще всего использовать сокращения: д., час., мин. и сек.
    Ответ написан
    1 комментарий
  • Что такое '-m' в командах в работе с Python?

    ri_gilfanov
    @ri_gilfanov
    Web- and desktop-developer
    В последних версиях Ubuntu установленные пакеты Python не прописываются как команды оболочки. А прописывать это ручками не каждый умеет.

    Таким образом, привычное:
    pyvenv .venv
    из коробки работает не во всех операционных системах.

    И в гайдах стали писать более универсальное:
    python3 -m venv .venv

    А что это такое, можно посмотреть в справке к Python:
    python3 --help

    Где можно увидеть описание опции:
    -m mod : run library module as a script (terminates option list)


    То есть, запуск установленный библиотеки в качестве скрипта. Хотя, очевидно, не все библиотеки имеют какой-то полезный функционал, который можно так запустить.
    Ответ написан
    2 комментария
  • Как достать нужные данные?

    ri_gilfanov
    @ri_gilfanov
    Web- and desktop-developer
    Ознакомьтесь с основными коллекциями Python.

    Списки (тип list):
    https://pythonworld.ru/tipy-dannyx-v-python/spiski...

    Словари (тип dict):
    https://pythonworld.ru/tipy-dannyx-v-python/slovar...

    Особенно по части обращения к элементу списка/словаря по индесу.

    Тогда можно будет делать так:
    ...
    response = api.users.get(access_token = token, user_ids = id)
    first_name = response[0]['first_name']
    print(first_name)
    Ответ написан
    1 комментарий
  • Как автоматизировать создание списка?

    ri_gilfanov
    @ri_gilfanov
    Web- and desktop-developer
    Я чуть мозг не сломал, пытаясь понять задачу.

    Решение же простое:
    [(i+1,2,i+3,4) for i in range(1000)]
    Ответ написан
    1 комментарий
  • Почему при отправке данных в MongoDB она ругается?

    ri_gilfanov
    @ri_gilfanov
    Web- and desktop-developer
    Попробуйте заменить вложенные словари на объекты SON:
    from bson.son import SON
    
    pool['tags'] = [SON([(k, d[k]) for k in d]) for d in pool['tags']]
    Ответ написан
  • PyQt5 или PySide 2?

    ri_gilfanov
    @ri_gilfanov
    Web- and desktop-developer
    Основное отличие -- это лицензии под которыми распространяются эти две обёртки над Qt.

    PyQt5 распространяется под GPL и коммерческой лицензией.

    PySide2 распространяется как Qt под GPL, LGPL и коммерческой лицензией.

    Пишите открытое/свободное ПО -- можно использовать как PyQt5, так и PySide 2.o

    Пишите закрытое/коммерческое ПО -- бесплатно можно использовать только PySide 2, а для использования PyQt5 потребуется покупать коммерческую лицензию.

    И если Вы живёте, работаете на компанию или имеете клиентов в США и Евросоюзе -- различие существенное, судебные иски там бывают.

    На постсоветском пространстве, я не припоминаю, чтобы кто-то подавал в суд из-за использования библиотек под лицензией GPL в коммерческих продуктах.

    Если Вам непринципиально на каком современном GUI-тулките писать десктом-приложение. С Python, помимо обёрток над GUI-тулкитом Qt5 (PyQt5, PySide 2), можно использовать обёртку для GUI-тулкита Gtk3 -- см. документацию тут Python GTK+ 3 и тут PyGObject -- код GTK и необходимых для Python библиотек лицензирован под LGPL, что позволяет использовать их в коммерческих продуктах.

    ДОПОЛНЕНО исходя из комментария автора вопроса

    Но меня интерисовала скорее производительность.


    Старайтесь формулировать вопрос так, чтобы он отражал то, что Вас интересует.

    В июне был открыт и в июле уже закрыт багрепорт по производительности одного из классов PySide2 в сравнении с тем же классом в PyQt5:
    https://bugreports.qt.io/browse/PYSIDE-727

    Если говорить о производительности в целом, то вопрос не имеет особого смысла.

    Производительность обеих обёрток упирается в производительность компонентов Qt5.

    Сравнивать производительность обеих обёрток надо по одинаковым кейсам.

    Большая разница в производительности PySide2 и PyQt5 на одном и том же кейсе будет причиной для багрепорта и исправления в PySide2 или в PyQt5, соответственно.

    Вы можете перестраховаться и 6-12 месяцев не трогать PySide2 со дня первого стабильного релиза (16.07.2018). Вдруг ещё остались недоработки, так пусть другие разработчики и компании используют PySide2 в продакшене на свой страх и риск сейчас, попишут разработчикам PySide2 багрепорты, а Вы получите от сообщества более стабильный и проверенный, не на Вас и не на ваших пользователях, продукт.

    Так как один проект официальный, а второй нет.


    Не совсем понятно, что такое официальный проект.

    На сайте Qt есть раздел Qt для Python, сейчас там написано про PySide2:
    doc.qt.io/qtforpython/index.html

    Это при том, что PyQt5 вышла давно, а PySide2 после многих лет разработки стабилизировали недавно.

    Возможно, лицензионная политика PySide2 больше устраивает разработчиков Qt5 и поэтому они решили продвигать PySide2.

    В таком случае, PySide2 можно считать "официальным" проектом, а PyQt5 стало быть "кустарщиной".
    Ответ написан
    4 комментария
  • Как собрать с такой код для конфиг файла?

    ri_gilfanov
    @ri_gilfanov
    Web- and desktop-developer
    Roman Ratkin, для генерации кода, конфигов и разметки можно использовать шаблонизаторы.

    Например, шаблонизатор jinja2 ( jinja.pocoo.org/docs/2.10 ).

    Так поступили разработчики утилиты cookiecutter ( https://cookiecutter.readthedocs.io/en/latest/ ) для генерации кода и конфигов проектов по шаблонам. Пример такого шаблона для Django ( https://github.com/pydanny/cookiecutter-django ).

    В вашем случае, можно так же взять Jinja2, сделать файл-шаблон под конфиг, скармливать джинже нужные значения и получать готовые конфиги. Если какие-то значения конфига зависят от других значений -- можно использовать условия. Если нужно засунуть в конфиг последовательность значений и каждое завернуть в какой-то текст -- есть циклы. Нужно вставить в конфиг какую-то дату и время -- можно пробрасывать в шаблон функцию высчитывающую нужную дату и время.
    Ответ написан
    1 комментарий
  • Как осуществить полноэкранный запуск приложения на Python GTK3 в Debian 9.5 (i386) без установленной среды рабочего стола?

    ri_gilfanov
    @ri_gilfanov Автор вопроса
    Web- and desktop-developer
    Пробовал поставить и настроить openbox в качестве менеджера окон, но запарился с конфигами.

    Проще оказалось не использовать зависящий от менеджеров окон метод fullscreen():
    self.fullscreen()
    А получить текущую ширину и высоту дисплея у Gdk.Screen и задать с помощью метода resize():
    self.resize(Gdk.Screen.width(), Gdk.Screen.height())

    Результат:
    YvkZsPd_fns.jpg
    Ответ написан
    Комментировать
  • Как отслеживать быструю подмену RFID-карты с Pyscard?

    ri_gilfanov
    @ri_gilfanov Автор вопроса
    Web- and desktop-developer
    Переписал кастомный CardObserver таким образом:
    from smartcard.CardConnectionObserver import ConsoleCardConnectionObserver
    from smartcard.CardMonitoring import CardObserver
    from smartcard.util import toHexString
    from smartcard.Exceptions import CardConnectionException, NoCardException
    from time import sleep
    
    
    class CardObserver(CardObserver):
        def __init__(self, app):
            self.app = app
            self.connection_observer = ConsoleCardConnectionObserver()
            self.has_card = False
            self.rfid_tag = None
            self.card = None
    
        def update(self, observable, actions):
            connected_cards, disconnected_cards = actions
            if connected_cards:
                self.card = connected_cards[0]
                self.get_rfid_tag()
    
            for card in disconnected_cards:
                self.rfid_tag = None
                self.has_card = False
                self.card = None
    
        def get_rfid_tag(self):
            try:
                self.card.connection = self.card.createConnection()
                self.card.connection.connect()
                self.card.connection.addObserver(self.connection_observer)
                data, sw1, sw2 = self.card.connection.transmit([255, 202, 0, 0, 0])
                data.reverse()
                self.rfid_tag = toHexString(data, format=1)
                self.has_card = True
            except NoCardException as error:
                print(error)
            except AttributeError as error:
                print(error)
            except CardConnectionException as error:
                print(error)
    
        def rfid_tag_check_worker(self):
            while True:
                if self.card:
                    self.get_rfid_tag()
                sleep(5)


    И при запуске приложения, создаю дополнительный поток, вызывающий функцию rfid_tag_check_worker.

    rfid_tag_check_thread = Thread(target=self.rfid_card_observer.rfid_tag_check_worker)
    rfid_tag_check_thread.start()


    Пока вроде работает корректно, хотя к картридеру обращаются два потока.

    Потестирую с меньшими интервалами проверки, надеюсь это стабильное в работе решение.
    Ответ написан
    Комментировать
  • Как правильно вывести меню с использованием django-mptt?

    ri_gilfanov
    @ri_gilfanov
    Web- and desktop-developer
    Место в документации:
    https://django-mptt.readthedocs.io/en/latest/tutor...

    Пример использования в Интернет-магазине для вывода выпадающего каталога товаров:
    https://github.com/ri-gilfanov/python-t/blob/maste...

    Если лень вчитываться в весь шаблон, вот вкратце:
    {% load static mptt_tags %}
    
    {% recursetree category_tree %}
        <li>
            <a class="btn btn__light" href="{% url 'category' node.pk %}">
                <span style="flex: 1 1 auto;">{{ node.name }}</span>{% if not node.is_leaf_node %}
                <span>&nbsp;</span><span class="fa fa-angle-right"></span>{% endif %}
            </a>
            {% if not node.is_leaf_node %}
                <ul  class="site_nav_primary__submenu ul__column white_box">
                    {{ children }}
                </ul>
            {% endif %}
        </li>
    {% endrecursetree %}


    Переменная шаблона category_tree -- это дерево категорий, формируемое в контекст-процессоре, посмотреть его можно тут:
    https://github.com/ri-gilfanov/python-t/blob/maste...

    А модель категорий можно найти тут:
    https://github.com/ri-gilfanov/python-t/blob/maste...

    В разметке из шаблона выше, каждый элемент дерева категорий именуется node (т.е. узел). В общем-то, это обычный объект модели Django ORM.

    Скажем, формирование ссылки:
    <a class="btn btn__light" href="{% url 'category' node.pk %}"></a>


    В одном из urls.py есть route (маршрут) с именем category, принимающий id категории. Обычно, node.pk и node.id -- это одно и то же, но я предпочитаю брать .pk, чтобы независеть от реального названия первичного ключа.

    А вот этот фрагментик из фрагмента выше:
    {% if not node.is_leaf_node %}
        <ul  class="site_nav_primary__submenu ul__column white_box">
            {{ children }}
        </ul>
    {% endif %}


    ...значит следующее. Если узел (node) верхнего уровня содержит дочерние узлы, то мы делаем вложенные маркерованные списки (ul) с особыми стилями CSS, а переменная {{ children }} означает, что внутри тегов с каждым дочерним элементом будет происходить всё то же самое, что и с узлами верхнего уровня.

    Если псевдокодом на русском:
    {% рекурсивное_дерево дерева_категорий %}
        Открываем HTML-теги для узлов верхнего уровня
        и что-то делаем с узлами верхнего уровня.
            {% если узел верхнего уровня содержит дочерние узлы %}
                открываем html-теги, в которые хотим завернуть дочерние узлы
                    {{ дети }}
                закрываем html-теги
            {% конец если про детей %}
        Если нужно, ещё что-то делаем с узлами верхнего уровня
        и закрываем HTML-теги.
    {% конец рекурсивного дерева %}


    Правда, в примере из интернет-магазина, я делаю проверку на наличие дочерних узлов дважды.

    Первый раз, я использую её чтобы добавить "небездетным" узлам иконку со стрелочкой, чтобы пользователь знал, что можно навести мышкой и выпадут дочерние категории.

    Таким образом, эту проверку можно использовать в разных местах, если нужно по-разному оформить узды с детьми и узлы без детей.

    Извиняюсь, если изложил немного путанно. Однако, разобраться во всех возможностях django-mptt можно за один вечер. Документация есть, а при сложностях с английским можно воспользоваться онлайн-переводчиками.
    Ответ написан
  • CSS препроцессоры и сборщики для Flask Python?

    ri_gilfanov
    @ri_gilfanov
    Web- and desktop-developer
    Flask-Assets (обёртка над Webassets), документация ниже:
    flask-assets.readthedocs.io/en/latest

    Документация Webassets:
    https://webassets.readthedocs.io/en/latest/

    Поддержка Sass и SCSS имеется, причём можно использовать разные реализации Sass/SCSS:
    • libsass -- самая производительная реализация на C/C++ (ставится через pip/pip3),
    • sass -- обычная реализация на Ruby (ставится через gem),
    • pyscss -- реализация на Python (ставится через pip/pip3).


    Поддержки Stylus вроде нет. Зато есть поддержка Less, PostCSS и всяких минимизаторы CSS/JS.

    Естественно, сборка CSS/JS файлов в библиотеках Flask-Assets/Webassets предусмотрена.
    Ответ написан
    Комментировать
  • Как организовать удобную разработку Django пакета (батарейки)?

    ri_gilfanov
    @ri_gilfanov Автор вопроса
    Web- and desktop-developer
    Сергей Горностаев предложил использовать tox, а в документации этого инструмента я наткнулся на более простое и удобное решение.

    В документации setuptools есть раздел Development mode.

    Если вместо команды install использовать команду develop
    python3 setup.py develop
    пакет не будет собран и полноценно установлен в глобальное или виртуальное окружение.

    Вместо этого, в глобальном или виртуальном окружении будет создана ссылка на исходники пакета (ссылка представляет собой файл с расширением .egg-link).

    После этого, пакет становится доступен для импорта.

    Если импортировать такой пакет в Django-проект, сделать manage.py runserver и начать редактировать исходники пакета -- встроенный в Django сервер для разработки как обычно перезапускается при каждом сохранении исходников пакета. Хотя импортированный пакет может лежать где угодно в файловой системе.

    Таким образом, работая над батарейкой для Django -- можно тут же видеть изменения в запущенном Django-проекте, без необходимости переустанавливать батарейку после каждой правки её исходников.

    Спасибо, проблема решена просто, дёшево и элегантно.

    P.S. Предложенная Сергеем библиотека tox больше подходит для автоматизации тестирования Python проекта во множестве разных рабочих окружений. Например, если Вы гарантируете пользователям поддержку разных версий требуемых библиотек, разных версий интерпретатора, разных интерпретаторов и т.д. -- tox может серьёзно облегчить Вам жизнь.

    P.P.S. Если кто-то не знает как пользоваться setuptools и создавать установочные файлы для своих Python пакетов -- есть статьи и даже видео на русском языке. Например:
    Ответ написан
    Комментировать
  • Возможно ли корректное переопредение свойства _meta.app_label у моделей contrib.auth в Django?

    ri_gilfanov
    @ri_gilfanov Автор вопроса
    Web- and desktop-developer
    Понял, при каких обстоятельствах это работает.

    Если провести все миграции и только потом переопределить app_label для Group и Permission -- всё работает как надо. Имена таблиц остаются с префиксом auth_, но в админке модели группируются в одном разделе.

    Если закомментировать это переопределение -- можно создавать и делать миграции.

    В иных случаях, будет либо изложенное в вопросе, либо поломанная миграция:
    AttributeError: 'ManyToManyField' object has no attribute 'm2m_reverse_field_name'


    В общем, сомнительное решение. Надёжнее переопределить вьюхи/шаблоны админки или поставить соответствующую батарейку (например, django-admin-tools, django-suit или django-grappelli).
    Ответ написан
    Комментировать
  • Зачем Flask использует систему расширений?

    ri_gilfanov
    @ri_gilfanov
    Web- and desktop-developer
    mako и WTForms библиотеки, что не заточены специально под Flask.

    flask_mako, flask_wtforms -- не реализуют ту же функциональность, а должны упрощать работу с mako и WTForms внутри Flask приложения, а так же упрощать взаимодействие mako и WTForms с другими библиотеками в рамках Flask-приложения.

    То есть, смысл расширений:
    1. нам не писать одно и то же в каждом проекте,
    2. разработчикам Flask не набивать фреймворк классами, сигналами, шаблонными тегами для каждой Python библиотеки.


    О первой причине прямо сказано в документации Flask ( flask.pocoo.org/docs/0.12/extensiondev ):
    Flask, being a microframework, often requires some repetitive steps to get a third party library working. Because very often these steps could be abstracted to support multiple projects the Flask Extension Registry was created.


    Например, flask_mako состоит из 1 файла ( https://github.com/benselme/flask-mako/blob/master... ) и судя по описанию --
    Extension implementing Mako Templates support in Flask with support for flask-babel

    -- расширение решает две задачи:
    1. интеграция с самим фреймворком Flask;
    2. интеграция с расширением flask-babel (обёртка вокруг python-библиотеки для интернационализации babel).

    Далее мы видим множественные импорты из Flask, werkzeug и mako.

    Например, из werkzeug импортируются инструменты для отладки, а из mako исключения:
    from werkzeug.debug.tbtools import Traceback, Frame, Line
    ...
    from mako import exceptions
    from mako.exceptions import RichTraceback, text_error_template

    Очевидно, это для того, чтобы в интерактивном отладчике Flask видеть внятные ошибки в html-шаблонах (в духе, "после такой-то строки ожидалось закрытие цикла через тег % endfor"). Подробнее, можно посмотреть ниже по коду в классе TemplateError.

    Внутри flask_mako я насчитал всего 6 одиночных функций и 3 класса -- можно в сжатые сроки разобраться и в назначении остальных.

    С документацией, комментированием исходников и именованием сущностей во Flask и его популярных расширениях -- всё очень даже неплохо, можно легко найти ответы на большинство вопросов.
    Ответ написан
    1 комментарий
  • Можно ли написать антивирус на python?

    ri_gilfanov
    @ri_gilfanov
    Web- and desktop-developer
    1. Теоретически, антивирус написать можно. Но для более-менее вменяемого антивируса нужны производительность и доступ к более низкоуровневым вещам, чем Python позволяет из коробки.

    Многие библиотеки Python -- это обёртки над библиотеками на C/C++. А в коде на C/C++ вообще могут использоваться ассемблерные вставки. В этом смысле, в Python можно прокинуть вызов любого низкоуровневого кода.

    Всё, что необходимо для написания антивируса давно должно иметь свободную реализацию на C/C++ и лежать в открытом доступе. Многое уже может иметь обёртки или биндинги для Python, а что не имеет -- так со знанием C/C++ их можно сделать.

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

    Основные недостатки разработки настольных программ на Python:
    • трудно скрыть исходники от любопытных;
    • не очень удобно собирать и распространять под разные ОС;
    • для низкоуровневых вещей и/или высокой производительности может потребоваться знание C/C++.


    2. Для специалиста по информационной безопасности, Python -- несущественный язык программирования.

    Специалист по информационной безопасности должен знать низкоуровневые языки -- ассемблер и Си.

    Помимо этого, полезно знать:
    • архитектуру ЭВМ (особенно, как работает процессор и оперативная память -- тема пересекается со знанием ассемблера),
    • архитектуру операционных систем (близко к архитектуре ЭВМ, но тема больше пересекается с языками программирования C/C++),
    • технологии компьютерных сетей,
    • алгоритмизацию,
    • криптографию.
    Ответ написан
    1 комментарий