Коробка с питоном
531 subscribers
49 photos
128 links
Заметки от Python-разработчика: сниппеты, обзоры пакетов, новости и другая полезная информация.
Download Telegram
Тут сборки PyPy для Python 3.8 и 3.9 зарелизили под маковский M1 (а если быть точнее - macOS ARM64). Отличная новость для разработчиков которые пользуются новыми макбуками!

#новости
2👏1
Django 4.1 вышел! Список изменений, из интересного:

1) Асинхронный интерфейс к ORM. Под капотом выполняет sync_to_async(), про лимиты и подводные камни можно почитать тут. Сделали как и предполагал, чтобы сделать асинхронный get нужно добавить букву a в начало - aget, afirst и т.д.
2) В CBV можно делать асинхронные методы. Подробнее тут.
3) То, чего мне не хватало - ограничения Check, unique и exclusion проверяются во время валидации модели.
4) Добавили команду optimizemigration которая попытается оптимизировать миграции.

#новости #django
3
Давно как-то искал как можно поднять свой pypi сервер, в итоге остановился на комплексном решении от Sonatype Nexus. На testdriven.io вышла замечательная статья, как это сделать при помощи pypiserver. Всё разворачивается в нашем с вами любимом докере :)

Github сервера

#статья
1
Нашел свежий доклад со сравнением использования CTE и SFW в Django ORM и SQLAlchemy, спойлер: джанга в такие штуки не умеет, пишите raw sql.

Ещё внезапно для себя узнал насколько алхимия мощная в плане рефлексии и как с ней легко работать используя уже существующую базу.

#посмотреть #sqlalchemy #django
Нашел прекрасную утилиту которая позволяет модернизировать питонячий код - refurb.

Есть у нас вот такой код:
for filename in ["file1.txt", "file2.txt"]:
with open(filename) as f:
contents = f.read()

lines = contents.splitlines()

for line in lines:
if not line or line.startswith("# ") or line.startswith("// "):
continue

for word in line.split():
print(f"[{word}]", end="")

print("")

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

$ refurb main.py
main.py:3:17 [FURB109]: Use `in (x, y, z)` instead of `in [x, y, z]`
main.py:4:5 [FURB101]: Use `y = Path(x).read_text()` instead of `with open(x, ...) as f: y = f.read()`
main.py:10:40 [FURB102]: Replace `x.startswith(y) or x.startswith(z)` with `x.startswith((y, z))`
main.py:16:9 [FURB105]: Use `print() instead of `print("")`

Refurb не является тайп- или стаилчекером. Его задача - делать код лучше и не более того.

#утилиты
👏73
СТО из ДомКлик разобрал в своём докладе такую, казалось бы, банальную вещь как обработка ошибок. Доклад очень интересен структурно - в нём рассмотрены как и сами конструкции (ну а в друг кто забыл?), так и байткод создания исключений, рассмотрено их поведение на примере исходников интерпретатора.

А дальше - глубже! Автор так же затронул потоки, асинхронщину и неявные raise (например как с ZeroDivisionError).

#посмотреть #exceptions
🔥5👏2
Я заметил, что редко использую функции из itertools, в основном когда нужно произвести какие-то "красивые" шаманства. Теперь будем вспоминать саму библиотеку вместе, естественно с примерами :)
Сам модуль itertools это набор из эффективных и быстрых по памяти инструментов, возвращающие итераторы. Сами по себе итераторы можно комбинировать с такими функциями как map(), list() лямбдами или же использовать их с помощью цикла for.

А сегодня мы начнем c самых простых - c бесконечных итераторов. Всего по документации их три: count(), cycle() и repeat().
Ниже я буду указывать аргументы по умолчанию и возможные передаваемые типы как тайп-хинты. Надеюсь ни у кого не возникнет проблем с пониманием.

#itertools #std
Коробка с питоном
Я заметил, что редко использую функции из itertools, в основном когда нужно произвести какие-то "красивые" шаманства. Теперь будем вспоминать саму библиотеку вместе, естественно с примерами :) Сам модуль itertools это набор из эффективных и быстрых по памяти…
count(start: int | float = 0, step: int | float = 1) -> Iterator[int | float]

Создает итератор, который возвращает равномерно распределенные значения, начиная с числа, указанного в аргументе start. Само значение-шаг указывается в переменной step:

>>> first = count(10, 2)
>>> next(first)
10
>>> next(first)
12
>>> next(first)
14
>>> second = count(0.1, 0.1)
>>> next(second)
0.1
>>> next(second)
0.2
>>> next(second)
0.30000000000000004
>>> next(second)
0.4

Небольшая загадка для вас - почему вместо 0.3 получили такое число? Пишите в комменты :)

#itertools #std
Коробка с питоном
Я заметил, что редко использую функции из itertools, в основном когда нужно произвести какие-то "красивые" шаманства. Теперь будем вспоминать саму библиотеку вместе, естественно с примерами :) Сам модуль itertools это набор из эффективных и быстрых по памяти…
cycle(p: Iterable) -> Iterator

Создает итератор, который возвращает элементы из переданного итератора поштучно и сохраняет их. После того как элементы закончились, он начинает возвращать сохранённые элементы и так до тех пор, пока мы сами не прервем его работу:

>>> first = cycle([1, 2])
>>> next(first)
1
>>> next(first)
2
>>> next(first)
1
>>> next(first)
2

Например, вот так при помощи функций islice и cycle мы можем сгенерировать список из 20 элементов из необходимой нам коллекции:

>>> list(islice(cycle([1, 2, 3, 4]), None, 20))
[1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4]

#itertools #std
1
Коробка с питоном
Я заметил, что редко использую функции из itertools, в основном когда нужно произвести какие-то "красивые" шаманства. Теперь будем вспоминать саму библиотеку вместе, естественно с примерами :) Сам модуль itertools это набор из эффективных и быстрых по памяти…
repeat(object: T, times: Optional[int] = None) -> Iterable[T]

Создает итератор который возвращает объект снова и снова. Можно указать параметр times, который вернет объект заданное количество раз и завершит работу итератора:

>>> first = repeat("hehe", 3)
>>> next(first)
'hehe'
>>> next(first)
'hehe'
>>> next(first)
'hehe'
>>> next(first)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration

Очень часто repeat используют чтобы по быстрому сгенерировать коллекцию из элементов:

>>> list(repeat(10, 10))
[10, 10, 10, 10, 10, 10, 10, 10, 10, 10]

#itertools #std
1
Там у Python 3.11 сегодня релиз, пройдемся по изменениям. Разделю пост на 2 части, сначала расскажу про всё остальное, а потом про typing, который снова прокачали.

1) Теперь Питон быстрее на 10-60% чем предыдущая версия. Почему такой разброс и где что ускорилось можно почитать здесь.
2) Exception Groups и *except. За это отвечает PEP 654, теперь есть возможность возбуждать и обрабатывать группы исключений. Судя по PEP сделано в основном для асинхронщины (asyncio.gather), колбеков и операций с несколькими попытками.
3) Для Exception появилась возможность добавлять примечания (notes). Теперь можно после обработки исключения добавить какую-то дополнительную информацию. Почитать подробно можно в PEP 678
4) Многие ждали и дождались - теперь в стандартной библиотеке есть tomllib, который позволяет работать с форматом TOML. Мотивация - его использует куча инструментов (black, mypy, pytest и т.д.), при чем каждый либо использует свою наколеночную реализацию, либо какую-то другую библиотеку. А тут решили стандартизировать, теперь это PEP 680.
5) Трейсбеки снова улучшили, теперь интерпретатор умеет показывать где именно находится ошибка, а не писать строку, где она произошла. Посмотреть на то как это выглядит можно в PEP 657.
6) Объявлены устаревшими следующие модули: aifc, audioop, cgi (за что?) и cgitb, chunk, crypt, imghdr (пользуйтесь PIL), mailcap, msilib, nis, nntplib, ossaudiodev, pipes (давно есть subprocess), sndhdr, spwd, sunau, telnetlib (вот этого я точно не могу понять), uu, xdrlib. Их удалят в 3.13.

А самому почитать об изменениях можно здесь.
1
Коробка с питоном
Там у Python 3.11 сегодня релиз, пройдемся по изменениям. Разделю пост на 2 части, сначала расскажу про всё остальное, а потом про typing, который снова прокачали. 1) Теперь Питон быстрее на 10-60% чем предыдущая версия. Почему такой разброс и где что ускорилось…
Немного с запозданием, но поговорим про новые фичи в typing.

1) NotRequired и Required поля в TypedDict.
Есть такой специальный класс как TypedDict - он позволяет добавить тайпхинты к словарю.
Теперь для описания полей в нём добавили три вещи:
1. NotRequired - показывает, что данного поля может и не быть в словаре.
2. Required - показывает, что данное поле обязательно должно быть в словаре
3. Аргумент total - если его значение ложно, то все поля в этом классе будут отмечены как NotRequired. По умолчанию оно истинно.

Почитать подробнее о нём можно вот тут

2) Self.
Ликуйте, господа, мы дождались! Больше никаких костылей с TypeVar!
Аннотация Self показывает что мы хотим вернуть инстанс текущего класса. Выглядит это как-то так:

class MyLock:
def __enter__(self) -> Self:
self.lock()
return self

Простенько и лаконично. Вот PEP 673.

3) LiteralString.
Относительно этого тайпхинта строки бывают двух типов - литеральные строки и произвольные строки. К литеральным строкам относятся константы, к произвольным - всё остальное. Данный тип указывает, что строка должна быть первого типа, на остальное оно будет ругаться. Вот пример:

def run_query(sql: LiteralString) -> ...
...

def caller(
arbitrary_string: str,
query_string: LiteralString,
table_name: LiteralString,
) -> None:
run_query("SELECT * FROM students") # ok
run_query(query_string) # ok
run_query("SELECT * FROM " + table_name) # ok
run_query(arbitrary_string) # type checker error
run_query( # type checker error
f"SELECT * FROM students WHERE name = {arbitrary_string}"
)

Исходя из примера видно, что использоваться это будет во всяких функциях, которые выполняют, например, SQL запросы или CLI-утилитах не давая на уровне тайпчекера засунуть в функцию очередной rm -rf. А PEP 675 можно почитать здесь.

4) Data class transforms
Декоратор который декорирует класс, метакласс или функцию которые являются декоратором. Получившийся декоратор умеет показывать тайпчекеру что декорируемый объект имеет фичи как у датакласса. Причина создания такой штуки проста - нет стандартного пути обозначения, что какой-то объект имеет свойства, присущие датаклассу. Привет Pydantic! PEP 681 читать здесь.

5) Вариативные дженерики.
Есть такая штука как TypeVar - она позволяет создавать дженерик параметризированный одним типом. А если нам нужно параметризировать произвольное количество типов? Теперь появился TypeVarTuple, который решает эту проблему.

Зачем это нужно: мы все знаем, что всякие датасотонисты любят наш питон из-за обилия всяких инструментов по типу NumPy или Pandas. Вариативные дженерики позволяют параметризировать структуры, которые подобны массивам, что в свою очередь позволяет находить ошибки при операции с этими структурами тайпчекеру.
PEP 646 читать здесь.

#pep
4
О работе с PostgreSQL JSONB в SQLAlchemy

JSON поля в PostgreSQL - это действительно удобный способ хранения данных, наряду с реляционной моделью. Они могут понадобиться там, где нужно произвести денормализацию данных для ускорения работы или для хранения гетерогенных данных.

Алхимия поддерживает работу с JSON-полями нативно, поэтому мы можем добавлять эти поля в свои модельки. Но есть пара нюансов, связанных с тем, каким образом алхимия проверяет изменения в этих полях.

Допустим, есть у нас вот такой класс:

class Config(Base):
id = Column(Integer, primary_key=True)
config = Column(JSONB)
tablename = 'config'

А теперь попытаемся добавить запись и изменить её:

cfg = Config(
id=1,
config={'some_const': 1}
)

session.add(cfg)
session.commit()

cfg.config['test'] = 2

session.add(cfg)
session.commit()

# упадёт с assertion error
assert cfg.config['test'] == 2

Почему оно упадёт с assertion error?
Внимательно прочитаем документацию SQLAlchemy и найдем вот такой забавный пункт: The JSON type, when used with the SQLAlchemy ORM, does not detect in-place mutations to the structure. То есть, при изменения структуры нашего объекта Алхимия не понимает, произошло ли какое-то изменение или нет.
Есть 2 решения этой проблемы:

1) Использовать класс MutableDict, если у нас нет вложенности в JSONB объектах:
Просто оборачиваем этой штукой наш тип в модели и радуемся жизни. Выглядит это как-то так:
...
config = Column(MutableDict.as_mutable(JSONB))

2) Используем библиотеку sqlalchemy-json, если у нас есть вложенность:
В данном случае наше поле будет выглядить как-то так:
from sqlalchemy_json import mutable_json_type
...
config = Column(mutable_json_type(dbtype=JSONB, nested=True))

Ссылочки:
1) Adding mutability to json
2) Mutation tracking
3) Mutation tracking in nested JSON structures using SQLAlchemy

#sqlalchemy #рецепт
5
Ежегодный опрос питонистов от JetBrains начался!

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

Опрос занимает 10-15 минут, а для дополнительной мотивации джеты подарят 20 случайным респондентам 100$ Amazon Gift Card!

Пройти можно тут.
4
Обнаружил у одного Python core developer репозиторий с названием python-horror-show.
В репозитории куча взрывающих мозг примеров с объяснением, почему что-то работает именно так как показано. Один из забавных примеров называется "Enter the void":

>>> all([])
True
>>> all([[]])
False
>>> all([[[]]])
True


#ссылочки
7
Большое интервью Гвидо ван Россума час назад вышло у Лекса Фридмана

https://www.youtube.com/watch?v=-DVyjdw4t9I

0:00 - Introduction
0:48 - CPython
6:01 - Code readability
10:22 - Indentation
26:58 - Bugs
38:26 - Programming fads
53:37 - Speed of Python 3.11
1:18:31 - Type hinting
1:23:49 - mypy
1:29:05 - TypeScript vs JavaScript
1:45:05 - Best IDE for Python
1:55:05 - Parallelism
2:12:58 - Global Interpreter Lock (GIL)
2:22:36 - Python 4.0
2:34:53 - Machine learning
2:44:35 - Benevolent Dictator for Life (BDFL)
2:56:11 - Advice for beginners
3:02:43 - GitHub Copilot
3:06:10 - Future of Python

#IT #Python
6
Я всё чаще и чаще замечаю Rust рядом с Python...

Совершенно недавно я нашел вот такой HTTP сервер на Rust для приложений на Python - Granian.

Разработчики ставят перед собой следующие цели:
+ Поддержка HTTP версий 1, 2 и 3
+ Один пакет для всех платформ
+ Сервер должен заменить Gunicorn/Uvicorn
+ Обеспечение большей производительности по сравнению с конкурентами.

Сейчас оно умеет в:
+ ASGI/3 и RSGI
+ HTTP/1 и HTTP/2
+ Вебсокеты над HTTP/1 и HTTP/2
+ Поддержка SSL

К сожалению проект пока что в состоянии разработки, поддерживает Питон 3.7 и выше на Unix-платформах и 3.8 и выше на Windows.
Очень надеюсь что с этого что-то вырастет.

#библиотека
4🔥3
Коробка с питоном
Я всё чаще и чаще замечаю Rust рядом с Python... Совершенно недавно я нашел вот такой HTTP сервер на Rust для приложений на Python - Granian. Разработчики ставят перед собой следующие цели: + Поддержка HTTP версий 1, 2 и 3 + Один пакет для всех платформ…
К слову, эти же чуваки сделали довольно известный в узких кругах фреимворк emmett.

Это фреимворк с кучей полезностей и различными новыми подходами. Вот самое интересное:

1) ORM на pyDAl, которая умеет даже в Монгу и FireBird писать! Ну и миграции, каллбеки (похожи на сигналы в Django) и ещё огромная куча всего, почитайте.
2) Валидаторы, правда не такие красивые как c Pydantic.
3) Система авторизации с гибкой системой групп.
4) Даже различные бекенды для кеша есть!
5) Очень интересная система пайплайнов, чем-то похожая на middleware, но с возможностью делать различные действия в зависимости от состояния пайпа.
6) Не менее интересная система сервисов, которая позволяет отдавать ответ не только в html, а в каком-то json или xml.
7) Система расширений.
8) Ну и CLI.
9) А для тех кому нужен REST есть расширение.

Уверен, что почти каждый читающий не знал о существовании этого фреймворка, а жаль. К счастью или сожалению сейчас господствуют микрофреимворки испытывающие unix-way - делай что-то одно и делай это хорошо.

#библиотека
3
Уже какую неделю подряд на Reddit (да и в англоязычных Python комьюнити) хайпит Flet.

Flet - это фреимворк который позволяет строить интерактивные десктопные/мобильные/веб приложения на различных ЯП (пока что увидел только поддержку Python), в итоге получаем SPA/PWA. Построено это всё на Flutter. Пример кода на скриншоте.

Подход с декларативным построением интерфейса вообще не новый - взгляните на Swift UI или же Jetpack Compose. Вопрос лишь в том, кто это использует?

Мне кажется, что:
1. Скорее всего подойдет для тех, кому нужно быстро накостылять MVP или взять замену tkinter.
2. Кейса, где это потащат в прод я не могу придумать по одной простой причине - множество гвоздей забивать микроскопом неудобно. Лучше взять молоток в виде React и спокойно с ним работать.

Во всяком случае - выглядит прикольно. Есть документация с примерами.

#библиотека
4