28 сентябрь 2018 Python


#!/usr/bin/env python
# $ID$ #
import sys
import subprocess


try:

    IIDD = "$I"+"D: {}  $".format(
        subprocess.check_output(['git', 'log', '-1', '--format=%ae / %an / %cd']).decode("utf-8")[:-1]
    )

    if IIDD:
        for line in sys.stdin:
            sys.stdout.write( line.replace("$I"+"D$", IIDD ) )

except:
    pass

А вот настройки git для работы с этим скриптом

файл .git/config


[filter "idder"]
    smudge = python iidd.py
    clean = perl -pe \"s/\\\\\\$ID[^\\\\\\$]*\\\\\\$/\\\\\\$ID\\\\\\$/\"

файл .gitattributes


*.js filter=idder
*.py filter=idder
*.css filter=idder
*.html filter=idder


01 апрель 2018 Python


После миграции на более новую версию Django при изменении любой модели может вылезать вот такая ошибка

django.db.utils.IntegrityError: null value in column "name" violates not-null constraint
DETAIL:  Failing row contains (101, null, history, historymodel).

Это связано с тем что в старой версии для хранения имени модуля использовалось поле name а в новой app_label, при этом поле name является обязательным к заполнению и не учавствует в работе миграции, отсюда и происходит ошибка

Для решения проблемы достаточно удалить поле name из таблицы django_content_type


23 январь 2018 29 январь 2018 Python Nginx Angular | решать тесты


Чтобы сайт работал быстро, необходимо чтобы быстро загружалась статика сайта, для этого используется сжатие ccs и js файлов (Настройка расширения gulp-clean-css для сжати css), а так же кеширование на уровне веб-сервера nginx c помощью опции expires и gzip, например вот так:

    location /static/ {
        alias /home/python/static/;
        expires 30d;
        gzip on;
        gzip_types text/css application/x-javascript application/javascript;
    }

тут задаёт 30 дневный период хранения кеша статики и включается поточное сжатие статики в архив. Таким образом на продакшене образуется ситуация когда настроенный сайт очень быстро получает статику и при повторных запросах использует кеш на уровне веб-серера и веб-браузера. В случае когда присходит редкое обновление фронта требуется чтобы клиенты обновили кеши со статикой сайта. Принудить клиентов обновить кеш можно добавив номер коммита в урлы к статике. Я делаю это так: в моё конфиге я объявил переменную VERSION и инициализирую её при запуске Flask приложения следующим образом:

import os
import subprocess
import datetime
basedir = os.path.abspath(os.path.dirname(__file__))
 
 
class Config(object):
    PROJECT_DIR = basedir
    DEBUG = False
    TESTING = False
    CSRF_ENABLED = not True
    ENABLED_PRODUCTMARKUP = True
    VERSION = '{}.{}'.format(
            str(subprocess.check_output(['git', 'describe', '--tags']),'utf-8').strip(),
            int( subprocess.check_output(['git', 'rev-list', '--all', '--count']) )
        )

И подключить это вот так:

{% extends "base.html" %}

{% block container %}
    <span ng-include="'/static/js/vendor.min.js?v={ { config.VERSION } }'" ng-controller="ProductCtrl"></span>
{% endblock %}

это даст вот такую ссылку

<script src="/static/js/vendor.min.js?v=0.0-235-g1ced510.825" type="text/javascript"></script>

То-есть, после каждого обновления продакшена у клиентов будет обновляться статика, а значит и фронт

Но бывает необходимо чтобы статика закачивалась при каждом новом запросе, это необходимо бывает для верстальщикам. Для решения этой задачи можно подменить значение переменной VERSION текущим значением времени. Я делаю переопределив в DevelopmentConfig аттрибут VERSION следующим образом:

class classproperty(property):
    def __get__(self, cls, owner):
            return classmethod(self.fget).__get__(None, owner)()


class DevelopmentConfig(Config):
    DEVELOPMENT             = True
    DEBUG                   = True
    #~ SQLALCHEMY_ECHO         = True
    UPLOAD_FOLDER           = 'media/'
   
    @classproperty
    def VERSION(self):
        return str(datetime.datetime.now())

тут я создаю специальный класс, который декорирует функцию VERSION, которая возращает каждый раз новую дату и время и представляет эту функцию в виде статического аттрибута класса, таким образом в ссылках на статику при каждой генерации страницы будет новый, уникальный хешь и статика будет всегда самой свежей


19 январь 2018 Python datetime RFC1123 Last-Modified


Использование даты в этом формате необходимо для обработки HTTP заголовка Last-Modified. Это когда сервер отдаёт дату изменения страницы в заголовке Last-Modified а затем клиет отправляе HEAD запрос с этим заголовком и датой и если страница не менялась, то ваш сервер отвечает 200 и отправляет пустое тело страницы. Это экономит и трафик и ресурсы процессора, а так же ускоряет повторную индексацию сайта и просто более технологично чем просто отдават страницы на каждый запрос.

Итак настроить дату обновления страницы в таком формате очень легко и делается это вот так:

class BaseClass(SQLAModel):
    __abstract__ = True
...
    updated_on =    Column(DateTime, default=func.now(), onupdate=func.now(), doc=_('дата редактирования'))
...

    def get_last_modified(self):
        return self.updated_on.strftime("%a, %d %B %Y %H:%M:%S GMT")

И всё будет прекрасно работать до тех пор пока вам не потребуется локализовать даты (это когда месяцы на русском). Для этого вы сделаете вот так где в __init__.py

...
import locale
...

locale.setlocale(locale.LC_ALL, 'ru_RU.UTF-8')

Возможно, раз вы используете babel, то у вас будет сменная локаль, это всё круто. Но этот системный вызов изменит поведение вашей get_last_modified и все ваши усилия по обработке Last-Modified приведут к тому, что появится вот такая ошибка

    TypeError: http header must be encodable in latin1

По-этому, формировать дату в RFC формате формате необходимо правильным образом, а именно вот так

from time import mktime
from wsgiref.handlers import format_date_time


class BaseClass(SQLAModel):
    __abstract__ = True
....
    updated_on =    Column(DateTime, default=func.now(), onupdate=func.now(), doc=_('дата редактирования'))

    def get_last_modified(self):
        stamp = mktime(self.updated_on.timetuple())
        return format_date_time(stamp)

Вот так вот всё просто.


08 январь 2018 29 январь 2018 Python | решать тесты


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

# начальная версия кода
def вычисление_значения(a, b):
    return a+b

# код после добавления новых требований
def вычисление_значения(a, b):
    if проверка_пользователя:
        учёт_результатов
    результат = a+b
    учёт_результатов(результат)
    печать_результатов(результат)

Более эфектным и эффективным будет поместить созданный ранее код внутрь другого кода, который будет предварять или завершать ваш код по новым задачам. И сделать это можно с помощью декораторов.

В программировании декоратор это обёртка функционального кода применяемая относительно другого функционального кода

Можно декорировать любой функциональный код

Можно использовать цепочки декораторов, подобно конфетам которые завёрнуты в фантики, упакованны в коробке и лежат в сумке

Декораторам можно передавать параметры для использования текущего контекста

Использование декораторов позволяет создавать более абстрактный и менее зависящий от контекста код.

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

Вот так будет выглядеть необходимые нам декораторы

def проверка_пользователя(декорируемая_функция):
    if пользователь.авторизован == True:
        декорируемая_функция()
    генерация исключения авторизации

def печать_результатов(декорируемая_функция):
   печать( "шапка бланка печати" )
   печать( декорируемая_функция() )
   печать( "подвал бланка печати" )

def учёт_результатов(декорируемая_функция):
   try:
      декорируемая_функция()
      журнал("положительное вычисление")
   except:
      журнал("неудачное вычисление")

Схематично использование декораторов можно представить в виде:

@проверка_пользователя
@печать_результатов_вычисление_значения
@учёт_результатов_вычисление_значения
def вычисление_значения(a, b):
    return a+b

Функционально декораторы это простой функциональный код который запускается на этапе интерпретации и в качестве входных аргументов получив имя декорируемой функции (в даннам случае указатель на функцию) манипулирует аргументами и результатами декорируемой функции


07 январь 2018 Python variables


Переменная в программе это объект с именем в оперативной памяти компьютера.

Оперативная память компьютера это множество пронумерованных ячеек в которых хранится информация в виде 0 и 1.

Объект в оперативной памяти это участок памяти который интерпретируется процессором в зависимости от типа объекта.

Самый простой тип объекта это бит, бит может принимать только два значений 0(ноль) или 1(единица).

Бит может использоваться в качестве индикаторов состояния включено или выключено.

Если объединить несколько бит то можно интерпретировать состояние бит в виде числа, так например в с помощью 8 бит можно преставить последовательность и 256 цифр (2 значения в 8 степени).

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

С помощью 1 байта из 8 бит можно представить последовательность из цифр 256 либо последовательность из 256 символов алфавита и технических символов.

Последовательность символов составляет ещё один тип данных — строка символов. Строки могут объединяться в массивы строк.

С помощью последовательности бит можно сформировать активный код выполняеымй процессором, это называет код функции. Код функций это последовательность бит, который выполняется процессором в командном режиме, что приводит к изменению состояния процессора, а следовательно и к изменению состояния объектов в оперативной памяти.

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

Для обращения к объекту необходимо знать адерес объекта в оперативной компьютера, так как работать с адресам для человека не удобно, существую таблицы имён созданых человеком и связанных с именами адресов объектов в оперативной памяти. При этом адрес объекта в оперативной памяти может постоянно меняться но связь с именем всегда позволяет обратиться к объекту.

Так как объекты бывают составными, то существуют иерархически составные названия объектов по аналогии с реальным миром, например: дом, улица, квартира, стул номер 3, ножка стула номер 2, длинна ножки стула.

Таким образом:

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

Типы объектов крайне важны в программировании. Так например, можно изготовить из пластилина молоток на 100% похожий на настоящий молоток, только забивать гвозди им не получится.


04 январь 2018 08 январь 2018 Python variables


Первое с чем сталкивает человек изучающий программирование это концепция переменных(Что такое переменные). Это сложная тема абстрактных понятий очень часто является барьером в изучении компьютерных наук. У новичков сразу возникают вопросы что такое перменные, какие типы переменных существуют, как правильно и не правильно использовать переменные, почему всё устроенно именно так. Если не разобраться с этим понятием то невозможно продолжить изучение программирования, а если углубиться в изучение концепции переменнных, то очень многие абстракции в программировании станут понятны сами по себе, по крайней мере интуиция будет подсказывать почему всё устроено именно так, а не иначе.

Понимание концепции переменных является ключевым пунктом к изучению программирования. Компьютерные переменные это абстракция которую придумали инженеры и окружили её аурой загадачного жаргона. Но если немного отвлечься от программирования и поглядеть на нашу жизнь со стороны то можно увидеть следующее: когда человек рождается то его память пуста, он не знает ни одного слова и даже не знает своего имени. Но постепенно общаясь с родителями, с другими людьми он учится связывать объекты реального мира со звуками которые произносят люди. Так он узнат что женщина которая его кормит и ухаживает за ним это мама, что когда мама произносит некоторое имя, например Вова, то это значит, что она обращается к нему, он начинает различать интонации в произношении различных слов учится работать с контекстом. Этот процесс можно назвать загрузкой сознания человека. В сознании ребёнка образы различных объектов начинают связываются с их названиями. Когда он впервые слышит слово "ты" то для него это слово ничего не означает, но в результате многократного повторения слова и связанного действия в памяти ребёнка закрепляется связь слова "ты" с набором объектов и ощущений. Все прекрасно помнят те моменты когда ребёнок начинает спрашивать у родителей "что это такое?" показывая на различные предметы и родители, отвечая на это вопросы, загружают в сознание ребёнка названия объектов и тем самым формируют его сознание и направление развития. Получается, что в этой ситуции ребёнок выступает в роли своеобразного компьтера, а родители в роли программистов которые составляют программу с помощью которой этот компьютер будет развиваться и взаимодействовать с другими живыми системами. А в компьютерном понимании это выглядит следующим образом: существует реальность в которой существуют различные объекты и явления с которыми необходимо воздействовать и название этих объектов и явлений необходимы для того чтобы к ним можно было обращаться с помощью речевых команд. Так например простой вопрос "где бобо" подразумевает, что ребёнок должен понять что от него хотят чтобы он указал на то место которое у него болит, то-есть происходит обращение к двум алгоритмам:

Если родители уже успели заложить в него связи между этими словами и алгоритмами то ребёнок сумеет выполнить команду. Этот пример наглядно показывает, что названия крайне необходимы для выполнения любых разумных и осмысленных действий. Если эти связи не установлены и для ребёнка слова родителей ничего не значат, то не возможно и управлять действиями ребёнка. Тут я ввожу понятие: алгоритм это набор действий приводящий к определённом результату, очевидно что алгоритмы так же должны иметь название и по сути так же являются объектами к которым можно обратиться через название.

Получается, что процесс воспитания ребёнка является программированием сознания ребёнка с помощью выстраивания связей между объектами и явлениями реального мира с названиями объектов и явлений в нашей речи, на нашем языке. В компьютерной среде происходит тоже самое программист работает в среде оперативной памяти компьютера, а в этой памяти располагаться объекты которые создаёт сам программист или которые там были созданы другими программистами. Например, программист создаёт внутри оперативной памяти список учеников и даёт ему некоторое название (можно сказать даёт ему кличку) которое существует в контексте этой программы и для того чтобы повторно обратиться к этому списку программа использует название которое программист присвоил ему при создании. По сути, вся работа программиста заключается в том, что он создаёт объекты в оперативной памяти компьютера, даёт названия объектам и создаёт алгоритмы взаимодействия объектов с помощью названий. От того насколько эффективно он создаёт эти объект и насколько то что он создаёт понятно другим людям зависит профессионализм программиста. Для сравнения можно взять Льва Толстого и его роман "Война и Мир". В этой книге, писатель с помощью правильных связей с названий и удачных конструкций определяющих конекст создал программу которая вызывает практически во всех людях одинаковые эмоции -- именно по этому этот писатель считается Великим, такое могут далеко не все, чаще всего люди собственной речью не могут выразить то что хотят сказать и тем более у них не получается вызывать те же образы что и самого автора.

Я использовал аналогию с обучением ребёнка для того, чтобы стало очевидно то, что для нашей разумной деятельность крайне важно то что мы знаем названия того с чем мы взаимодействуем, без этого невозможно выполнение разумной и упорядоченной деятельности и точно так же в программирование без знания названий сущностей внутри оперативной памяти невозможно делать что либо разумное. Таким образом получается, что на самом деле самос компьютерные "переменные" это всего лишь объекты и названия объектов внутри оперативной памяти. Но очевидно что использование слова "переменные" более удобно и наглядно чем выражение "объекты и названия объектов" для тех понимает о чём речь.

Поняв вышеизложенное становится очевидно, что когда программист говорит, что он создал переменную то он всего лишь создал объект в оперативной памяти компьютера и дал название этому объекту, когда программист говорит что он обратился к  переменной то это означает что он заставил программу обратиться к объекту по его имени. В этом смысле программисты подобны творцам, которые создают объекты, дают им названия, учат эти объекты взаимодействовать друг с другом, создают целые миры из объектов подчняющихся действию алгоримов взаимодействия и даже общению с объектами из миров созданных другими творцами. Так что на самом деле программирование это очень простое и увлекательное творчество, посоревноваться с которым может лишь творчество которое вызывает у людей сильные эмоции, это я сейчас про кино, музыку и всякую прочую живопись, только в программировании гораздо меньше возможностей для субъективизма и больше логики.


... статья в разработке, продолжение следует

Так же с помощью этого примера можно понять что названия не являются постоянными(константыми), например, объект реального мира "яблоко" может иметь название "яблоко" или "apple" так как это зависит от того в какой семье воспитывается ребёнок, это явление назвается контекст, то-есть одно и тоже явление может называться по разному в зависимости от контекста.

И так в нашем собственном сознании присутвтвуют переменные. Среди них можно выделить переменные долгосрочные и короткосрочные. Например, слово мама почти у каждого человека связыватся с одним единственным человеком на свете, то-есть в сознании этого человека есть конкретная связь между этим названием и конкретным объектом реального мира. Связь с составными названиеми "моя машина", "твоя машина" и реальным объектом реального мира показывает, что переменные бывают не постоянными, а с деньгами понимание недолговременности существования переменных становится ещё очевиднее.