Если вы любите делать игры на Godot или хотите начать их делать, при этом разбираться с GDScript вам лень - вы можете попробовать использовать godot-python. Godot - это прекраснейший движок, чтобы начать разрабатывать игры. Как по мне выглядит получше Unity, особенно для всяких небольших мобильных игр (особенно на фоне последних новостей).
Ребята пытаются добавить поддержку скриптинга на Python в Godot, и судя по тому как развивается проект - получается это у них довольно неплохо.
Из минусов я бы выделил: странный механизм экспорта проекта, вместе с игрой вы экспортите интерпретатор питона (хотя для кого-то это не минус), отсутствие pip из под коробки - его ставить нужно отдельно.
#библиотека #gamedev
Ребята пытаются добавить поддержку скриптинга на Python в Godot, и судя по тому как развивается проект - получается это у них довольно неплохо.
Из минусов я бы выделил: странный механизм экспорта проекта, вместе с игрой вы экспортите интерпретатор питона (хотя для кого-то это не минус), отсутствие pip из под коробки - его ставить нужно отдельно.
#библиотека #gamedev
GitHub
GitHub - touilleMan/godot-python: Python support for Godot 🐍🐍🐍
Python support for Godot 🐍🐍🐍. Contribute to touilleMan/godot-python development by creating an account on GitHub.
Я всё чаще и чаще замечаю 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.
Очень надеюсь что с этого что-то вырастет.
#библиотека
Совершенно недавно я нашел вот такой 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.
Очень надеюсь что с этого что-то вырастет.
#библиотека
GitHub
GitHub - emmett-framework/granian: A Rust HTTP server for Python applications
A Rust HTTP server for Python applications. Contribute to emmett-framework/granian development by creating an account on GitHub.
Коробка с питоном
Я всё чаще и чаще замечаю 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 - делай что-то одно и делай это хорошо.
#библиотека
Это фреимворк с кучей полезностей и различными новыми подходами. Вот самое интересное:
1) ORM на pyDAl, которая умеет даже в Монгу и FireBird писать! Ну и миграции, каллбеки (похожи на сигналы в Django) и ещё огромная куча всего, почитайте.
2) Валидаторы, правда не такие красивые как c Pydantic.
3) Система авторизации с гибкой системой групп.
4) Даже различные бекенды для кеша есть!
5) Очень интересная система пайплайнов, чем-то похожая на middleware, но с возможностью делать различные действия в зависимости от состояния пайпа.
6) Не менее интересная система сервисов, которая позволяет отдавать ответ не только в html, а в каком-то json или xml.
7) Система расширений.
8) Ну и CLI.
9) А для тех кому нужен REST есть расширение.
Уверен, что почти каждый читающий не знал о существовании этого фреймворка, а жаль. К счастью или сожалению сейчас господствуют микрофреимворки испытывающие unix-way - делай что-то одно и делай это хорошо.
#библиотека
GitHub
GitHub - emmett-framework/emmett: The web framework for inventors
The web framework for inventors. Contribute to emmett-framework/emmett development by creating an account on GitHub.
Уже какую неделю подряд на Reddit (да и в англоязычных Python комьюнити) хайпит Flet.
Flet - это фреимворк который позволяет строить интерактивные десктопные/мобильные/веб приложения на различных ЯП (пока что увидел только поддержку Python), в итоге получаем SPA/PWA. Построено это всё на Flutter. Пример кода на скриншоте.
Подход с декларативным построением интерфейса вообще не новый - взгляните на Swift UI или же Jetpack Compose. Вопрос лишь в том, кто это использует?
Мне кажется, что:
1. Скорее всего подойдет для тех, кому нужно быстро накостылять MVP или взять замену tkinter.
2. Кейса, где это потащат в прод я не могу придумать по одной простой причине - множество гвоздей забивать микроскопом неудобно. Лучше взять молоток в виде React и спокойно с ним работать.
Во всяком случае - выглядит прикольно. Есть документация с примерами.
#библиотека
Flet - это фреимворк который позволяет строить интерактивные десктопные/мобильные/веб приложения на различных ЯП (пока что увидел только поддержку Python), в итоге получаем SPA/PWA. Построено это всё на Flutter. Пример кода на скриншоте.
Подход с декларативным построением интерфейса вообще не новый - взгляните на Swift UI или же Jetpack Compose. Вопрос лишь в том, кто это использует?
Мне кажется, что:
1. Скорее всего подойдет для тех, кому нужно быстро накостылять MVP или взять замену tkinter.
2. Кейса, где это потащат в прод я не могу придумать по одной простой причине - множество гвоздей забивать микроскопом неудобно. Лучше взять молоток в виде React и спокойно с ним работать.
Во всяком случае - выглядит прикольно. Есть документация с примерами.
#библиотека
Продолжаем смотреть на питоновские библиотеки! На этот раз снова не обойдется без влияния Rust - сегодня мы будем рассматривать библиотеки которые реализуют типы Result и Option.
В стандартной библиотеке Rust есть такой тип как Option - он позволяет, в случае если что-то пошло не так вернуть None, иначе вернуть само значение. Ещё есть Result, который позволяет вернуть либо значение, либо ошибку, которую далее уже должна обработать вызывающая функция.
Всё это нужно по причине того, что в Rust нет конструкции
Зачем это нужно в Python?А оно там не нужно Есть несколько причин:
1) Вы пишите на Rust
3) Такой подход вам ближе
2) Вы пишите в парадигме функционального программирования.
В остальном, как по мне, это просто не нужно. Множить подходы (особенно к обработке ошибок) - самое неприятное что можно сделать в языке.
Но мы продолжаем. Для реализации этих типов есть несколько питоновских библиотек. Вот они: safetywrap и option. Safetywrap мне показался более полным, поэтому будем рассматривать его.
Задача - написать функцию, которая будет проверять значение на отрицательность. Если оно отрицательное - выводим ошибку. С safetywrap это будет выглядеть следующим образом:
#библиотека
В стандартной библиотеке Rust есть такой тип как Option - он позволяет, в случае если что-то пошло не так вернуть None, иначе вернуть само значение. Ещё есть Result, который позволяет вернуть либо значение, либо ошибку, которую далее уже должна обработать вызывающая функция.
Всё это нужно по причине того, что в Rust нет конструкции
try... except
и господствует ФП, которое позволяет строить мощные функциональные конвейеры для обработки получаемых внутри программы данных.Зачем это нужно в Python?
1) Вы пишите на Rust
3) Такой подход вам ближе
2) Вы пишите в парадигме функционального программирования.
В остальном, как по мне, это просто не нужно. Множить подходы (особенно к обработке ошибок) - самое неприятное что можно сделать в языке.
Но мы продолжаем. Для реализации этих типов есть несколько питоновских библиотек. Вот они: safetywrap и option. Safetywrap мне показался более полным, поэтому будем рассматривать его.
Задача - написать функцию, которая будет проверять значение на отрицательность. Если оно отрицательное - выводим ошибку. С safetywrap это будет выглядеть следующим образом:
def check_value_not_negative(val: int) -> Result[int, str]:Как использовать эту функцию? Можно просто её вызвать и в зависимости от результата мы получим либо тип Ok, либо тип Err.
if val >= 0:
return Ok(val)
return Err(f"{val} is negative!")
print(check_value_not_negative(1)) # Ok(1)Но самый сок - это то, что Result содержит в себе кучу полезных функций. Например, в случае получения ошибки мы можем вернуть None или любое другое значение:
print(check_value_not_negative(-1)) # Err('-1 is negative!')
print(check_value_not_negative(-1).or_(None)) # NoneИли проверить, равно ли значение единице, и если нет - вывести сообщение об этом:
print(check_value_not_negative(2).and_then(Как видно, эти типы позволяют писать код, который будет эффективно обрабатывать ошибки, не прибегая к куче
lambda result: Result.ok_if(lambda x: x == 1, result).map_err(
lambda _: "Не равно единице"
)
)) # Err('Не равно единице')
if
и try...except...
Мне нравится такой подход, а вам?#библиотека
Когда-то давно, когда я только изучал Django, мне хотелось избавиться от бойлерплейта в темплейтах и вынести некоторые части шаблонов (например кнопки) в какие-то отдельные сущности которые можно переиспользовать - например в виде компонентов.
К счастью, в Django есть решение для этого и оно называется template tags. Но у него есть несколько проблем:
1) Необходимо пробрасывать руками js и css зависимости для конкретного тега там, где он используется.
2) Теги плохо кастомизируются, например нет возможности изменить поведение тега, обязательно нужно его переписывать.
Решением этих вопросов занимается пакет с названием django-components. Он предоставляет возможность делать простые, но в то же время мощные переиспользуемые компоненты. А как он справляется с проблемами выше?
1) При объявлении компонента будут грузиться только те js и css, которые указаны в классе компонента. Класс компонента выглядит как-то так:
2) Для изменения поведения компонента можно использовать слоты - это что-то вроде django-блоков внутри компонента. Например, мы можем сделать блок
#django #библиотека
К счастью, в Django есть решение для этого и оно называется template tags. Но у него есть несколько проблем:
1) Необходимо пробрасывать руками js и css зависимости для конкретного тега там, где он используется.
2) Теги плохо кастомизируются, например нет возможности изменить поведение тега, обязательно нужно его переписывать.
Решением этих вопросов занимается пакет с названием django-components. Он предоставляет возможность делать простые, но в то же время мощные переиспользуемые компоненты. А как он справляется с проблемами выше?
1) При объявлении компонента будут грузиться только те js и css, которые указаны в классе компонента. Класс компонента выглядит как-то так:
from django_components import componentСам js/css рендерится только там, где указаны теги
@component.register("calendar")
class Calendar(component.Component):
template_name = "calendar/calendar.html"
def get_context_data(self, date):
return {
"date": date,
}
class Media:
css = "calendar/calendar.css"
js = "calendar/calendar.js"
component_js_dependencies
и component_css_dependencies
.2) Для изменения поведения компонента можно использовать слоты - это что-то вроде django-блоков внутри компонента. Например, мы можем сделать блок
body
внутри компонента и изменять его вид тогда, когда нам нужно:<div class="calendar-component">А теперь импортируем компонент и меняем его body:
<div class="header">
{% slot "header" %}Заголовок календаря{% endslot %}
</div>
<div class="body">
{% slot "body" %}Сегодня <span>{{ date }}</span>{% endslot %}
</div>
</div>
{% component_block "calendar" date="2020-06-06" %}Github | PyPi
{% slot "body" %}А сегодня точно <span>{{ date }}</span>?{% endslot %}
{% endcomponent_block %}
#django #библиотека
Если вы хоть раз задумывались о том, можно ли фичи FastAPI (автогенерация OpenAPI, интеграция с Pydantic, поддержка асинхронности и т.д.) добавить в Django, то я пришел вас обрадовать - есть такой проект под названием django-ninja.
Из приятных фич, которые можно встретить здесь:
1) Версионирование и возможность создания нескольких API инстансов со своей авторизацией и т.д.
2) Класс схемы интегрирован с модельками Django, поэтому можно писать что-то вроде такого:
4) Пагинация! При чем в документации показано, как можно сделать собственный кастомный класс для неё.
5) Поддержка кастомных рендереров ответов, что позволяет перевести сериализацию на ORJSON или отдавать ответы в XML, например.
6) Работа с аутентификацией из под коробки.
7) Ну и асинхронность, тем более разработчики Django работают над ней.
А в остальном он очень похож на FastAPI, особенно когда речь идет о работе с аргументами, схемами и OpenAPI.
Как по мне, выглядит как достойная замена DRF, при чем довольно простая. И об этом я говорю не просто так - в последнее время я делал проекты на FastAPI и возвращаться на Django и тем более DRF было очень непривычно.
Github | Документация
#django #библиотека
Из приятных фич, которые можно встретить здесь:
1) Версионирование и возможность создания нескольких API инстансов со своей авторизацией и т.д.
2) Класс схемы интегрирован с модельками Django, поэтому можно писать что-то вроде такого:
@api.get("/tasks", response=List[TaskSchema])3) Можно делать схемы из моделей, прям как в DRF.
def tasks(request):
return Task.objects.all()
4) Пагинация! При чем в документации показано, как можно сделать собственный кастомный класс для неё.
5) Поддержка кастомных рендереров ответов, что позволяет перевести сериализацию на ORJSON или отдавать ответы в XML, например.
6) Работа с аутентификацией из под коробки.
7) Ну и асинхронность, тем более разработчики Django работают над ней.
А в остальном он очень похож на FastAPI, особенно когда речь идет о работе с аргументами, схемами и OpenAPI.
Как по мне, выглядит как достойная замена DRF, при чем довольно простая. И об этом я говорю не просто так - в последнее время я делал проекты на FastAPI и возвращаться на Django и тем более DRF было очень непривычно.
Github | Документация
#django #библиотека
django-ninja.dev
Django Ninja
Django Ninja - Django REST framework with high performance, easy to learn, fast to code.
Если обычного itertools вам мало, то можно использовать more-itertools.
Эта библиотека добавляет огромное количество функций для работы с итераторами. На практике всеми ими не всегда пользуются, поэтому я выделю некоторые из тех, которые сам использую часто.
Например, вот так можно разделить список на 3 части:
Решим самую частую проблему - перевести список с несколькими уровнями вложенностями в "плоский" список:
PyPI | Документация
#more_itertools #itertools #библиотека #рецепт
Эта библиотека добавляет огромное количество функций для работы с итераторами. На практике всеми ими не всегда пользуются, поэтому я выделю некоторые из тех, которые сам использую часто.
Например, вот так можно разделить список на 3 части:
data = ["first", "second", "third", "fourth", "fifth", "sixth", "seventh"]Вот еще задача. Надо разделить список с элементами по определенному условию. В этом нам поможет
[list(l) for l in divide(3, data)]
# [['first', 'second', 'third'], ['fourth', 'fifth'], ['sixth', 'seventh']]
bucket
:class Cat:По итогу кошки и собаки будут разделены по своему типу на 2 генератора.
pass
class Dog:
pass
shapes = [Cat(), Dog(), Cat(), Dog(), Cat(), Cat()]
result = more_itertools.bucket(shapes, key=lambda x: type(x))
len(list(result[Cat])) # 4
len(list(result[Dog])) # 2
Решим самую частую проблему - перевести список с несколькими уровнями вложенностями в "плоский" список:
iterable = [(1, 2), ([3, 4], [[5], [6]])]А если в плоский список нам нужно вытащить только элементы с первым уровнем вложенности?
list(more_itertools.collapse(iterable)) #[1, 2, 3, 4, 5, 6]
list(more_itertools.collapse(iterable, levels=1)) # [1, 2, [3, 4], [[5], [6]]]А вот так мы можем посмотреть, все ли элементы в коллекции уникальные:
more_itertools.all_unique([1, 2, 3, 4]) # TrueБиблиотека решает очень много типовых проблем, поэтому если научиться ей пользоваться - она сэкономит очень много времени. Возможно, я еще буду писать какие-то рецепты с ней, но это не точно 🌚...
more_itertools.all_unique([1, 2, 1, 4]) # False
PyPI | Документация
#more_itertools #itertools #библиотека #рецепт
PyPI
more-itertools
More routines for operating on iterables, beyond itertools
Как раз сегодня искал фреимворк для организации работы консьюмера RabbitMQ и на глаза попался Propan - декларативный фреимворк для работы с очередями сообщений.
Для чего это нужно? На базе очередей можно построить асинхронную коммуникацию сервисов, а это привет микросервисной архитектуре!
Для сравнения, вот столько кода нам нужно написать, чтобы сделать консьюмер при помощи aio_pika:
Что ещё умеет?
1) Кастить типы сообщений в модельки при помощи Pydantic.
2) Умеет работать с зависимостями (привет DI)
3) Имеет CLI утилитку, которая поможет сгенерировать проект, запустить несколько процессов воркеров, запустить хот-релоад для разработки.
4) А ещё есть огромное количество примеров, как им пользоваться.
5) Бонус - похоже у автора в планах прикрутить AsyncAPI (это как OpenAPI, только для очередей).
На данный момент стабильно работает с RabbitMQ, Redis и Nats. Kafka и SQS в бете, а NatsJs, MQTT, Redis Streams и Pulsar в планах.
Ну и накиньте звёзд автору, выглядит как то, что в будущем выстрелит :)
Github | Документация
#библиотека #propan
Для чего это нужно? На базе очередей можно построить асинхронную коммуникацию сервисов, а это привет микросервисной архитектуре!
Для сравнения, вот столько кода нам нужно написать, чтобы сделать консьюмер при помощи aio_pika:
import asyncioА вот столько с Propan:
import aio_pika
async def main():
connection = await aio_pika.connect_robust(
"amqp://guest:guest@127.0.0.1/"
)
queue_name = "test_queue"
async with connection:
channel = await connection.channel()
queue = await channel.declare_queue(queue_name)
async with queue.iterator() as queue_iter:
async for message in queue_iter:
async with message.process():
print(message.body)
asyncio.run(main())
from propan import PropanApp, RabbitBrokerЧистый кайф, не правда ли? Выглядит просто и понятно.
broker = RabbitBroker("amqp://guest:guest@localhost:5672/")
app = PropanApp(broker)
@broker.handle("test_queue")
async def base_handler(body):
print(body)
Что ещё умеет?
1) Кастить типы сообщений в модельки при помощи Pydantic.
2) Умеет работать с зависимостями (привет DI)
3) Имеет CLI утилитку, которая поможет сгенерировать проект, запустить несколько процессов воркеров, запустить хот-релоад для разработки.
4) А ещё есть огромное количество примеров, как им пользоваться.
5) Бонус - похоже у автора в планах прикрутить AsyncAPI (это как OpenAPI, только для очередей).
На данный момент стабильно работает с RabbitMQ, Redis и Nats. Kafka и SQS в бете, а NatsJs, MQTT, Redis Streams и Pulsar в планах.
Ну и накиньте звёзд автору, выглядит как то, что в будущем выстрелит :)
Github | Документация
#библиотека #propan
GitHub
GitHub - Lancetnik/Propan: Propan is a powerful and easy-to-use Python framework for building event-driven applications that interact…
Propan is a powerful and easy-to-use Python framework for building event-driven applications that interact with any MQ Broker - Lancetnik/Propan
Я знаю на опыте, как иногда не удобно работать с датами и временем в Питоне.
В стандартной библиотеке есть как и большое количество типов данных (date, time, tzinfo, timedelta, relativedelta, ...) так и куча модулей (datetime, time, calendar, dateutil, ...) которые помогают работать с ними. Но содержать в голове, да еще и уметь работать с ними иногда проблематично.
Одна из библиотек, которая облегчает работу с сабжем - arrow. Давайте покажу на практике, насколько с ней удобно работать:
1) Получение времени
Начнём с легкого - получим время по MSK и UTC:
Например, вот так можно заменить час в исходной дате:
Возьмем задачу. Нам нужно сказать, через сколько мы прибудем домой. Делается это так:
Как раз недавно решал следующую задачку: дается временной промежуток, для него нужно сделать почасовые интервалы. С arrow всё это делается вот так:
GitHub | Документация
#библиотека
В стандартной библиотеке есть как и большое количество типов данных (date, time, tzinfo, timedelta, relativedelta, ...) так и куча модулей (datetime, time, calendar, dateutil, ...) которые помогают работать с ними. Но содержать в голове, да еще и уметь работать с ними иногда проблематично.
Одна из библиотек, которая облегчает работу с сабжем - arrow. Давайте покажу на практике, насколько с ней удобно работать:
1) Получение времени
Начнём с легкого - получим время по MSK и UTC:
>>> arrow.now() # получаем текущее время по MSKА если нам надо текущее время с другой таимзоной?
2023-06-02T18:46:55.188882+03:00
>>> arrow.utcnow() # а теперь текущее, но в UTC
2023-06-02T15:46:55.188882+00:00
>>> arrow.get().to("US/Pacific")Это было просто. А что если нам нужно спарсить время из шаблона?
2023-06-02T08:49:39.794355-07:00
>>> arrow.get('2023/06-02|19:00:{00}', 'YYYY/MM-DD|HH:mm:{ss}') #обратите внимание на шаблон!Ещё arrow позволяет искать даты в строке по шаблону:
2023-06-02T19:00:00+00:00
>>>arrow.get('Он родился 16 Мая 2020 года', 'DD MMMM YYYY', locale="ru")2) Работа со временем
2020-05-16T00:00:00+00:00
Например, вот так можно заменить час в исходной дате:
>>>arrow.now().replace(hour=12)Или добавить к текущей дате +5 недель:
2023-06-02T12:00:29.180755+03:00
>>>arrow.now().shift(weeks=+5)Ну и в конце, давайте отформатируем текущее время в строку по шаблону:
2023-07-07T19:02:27.174819+03:00
>>>arrow.now().format('YYYY HH:mm:ss MM/DD')3) Очеловечивание времени
2023 19:05:04 06/02
Возьмем задачу. Нам нужно сказать, через сколько мы прибудем домой. Делается это так:
>>> start_time = arrow.now()А если мы хотим из человеческого формата перевести в машинночитаемый?
>>> arrive_time = start_time.shift(hours=+3, minutes=10, seconds=12)
>>> humanized = arrive_time.humanize(locale="ru", granularity=["hour", "minute", "second"])
>>> print(f"Вы прибудете домой {humanized}")
Вы прибудете домой через 3 часа 10 минут 12 секунд
>>> start_time.dehumanize(humanized, locale="ru")4) Работа с диапазонами
2023-06-02T22:28:08.141525+03:00
Как раз недавно решал следующую задачку: дается временной промежуток, для него нужно сделать почасовые интервалы. С arrow всё это делается вот так:
start = datetime(2023, 1, 1, 00, 00)В любом случае, рекомендую присмотреться, возможно для вас эта библиотека станет одним еще довольно удобным инструментом!
end = datetime(2023, 1, 1, 23, 00)
for r in arrow.Arrow.span_range('hour', start, end):
print(r)
(<Arrow [2023-01-01T00:00:00+00:00]>, <Arrow [2023-01-01T00:59:59.999999+00:00]>)
....
(<Arrow [2023-01-01T23:00:00+00:00]>, <Arrow [2023-01-01T23:59:59.999999+00:00]>)
GitHub | Документация
#библиотека
GitHub
GitHub - arrow-py/arrow: 🏹 Better dates & times for Python
🏹 Better dates & times for Python. Contribute to arrow-py/arrow development by creating an account on GitHub.
Yoyo
В текущих реалиях практически любой сервис использующий реляционную БД не может обойтись без миграций. Так уж сложилось, что в нашем питонячьем мире, в проектах почти всегда можно увидеть ORM (например SQLAlchemy) и пакет, который позволяет управлять миграциями, работающий с конкретной ORM (в случае с Алхимией это alembic).
Но иногда попадаются такие проекты, в которых нам не нужна ORM, по разным причинам. В этом случае, для миграций можно использовать yoyo.
Yoyo - это простой мигратор схем для нашей БД. Миграции здесь записываются в виде скриптов на SQL или на Python.
Сгенерировать папку для миграций и конфиг можно вот так:
Внутри базы yoyo создает таблицу с логом всех операций (
Вот такая вот простая и удобная библиотека :)
Сайт | Sourcehut | PyPI
#библиотека
В текущих реалиях практически любой сервис использующий реляционную БД не может обойтись без миграций. Так уж сложилось, что в нашем питонячьем мире, в проектах почти всегда можно увидеть ORM (например SQLAlchemy) и пакет, который позволяет управлять миграциями, работающий с конкретной ORM (в случае с Алхимией это alembic).
Но иногда попадаются такие проекты, в которых нам не нужна ORM, по разным причинам. В этом случае, для миграций можно использовать yoyo.
Yoyo - это простой мигратор схем для нашей БД. Миграции здесь записываются в виде скриптов на SQL или на Python.
Сгенерировать папку для миграций и конфиг можно вот так:
yoyo init --database sqlite:///mydb.sqlite3 migrationsА теперь создадим миграцию:
yoyo newОпишем SQL для применения миграции (apply) и для её отката (rollback):
from yoyo import stepТеперь можно применить миграцию командой
__depends__ = {}
steps = [
step(
"CREATE TABLE TEST (a int);",
"DROP TABLE TEST"
)
]
yoyo apply
и после откатить её командой yoyo rollback
. Внутри базы yoyo создает таблицу с логом всех операций (
_yoyo_log
), таблицу с применёнными миграциями (_yoyo_migration
), а так же таблицу yoyo_lock
, которая позволяет заблокировать миграции, которые будут идти с нескольких инстансов приложений. Вот такая вот простая и удобная библиотека :)
Сайт | Sourcehut | PyPI
#библиотека
Занимаюсь в рамках петпроекта обработкой текста, появилась потребность проверять на каком языке написан текст.
Сначала я попытался использовать langdetect, но он часто выдавал неправильные результаты. Как правило, плохие результаты выдавались по нескольким причинам:
1. Нет возможности ограничить языки, которые я хотел бы детектить. Мне надо определять всего четыре языка - украинский, русский, английский и немецкий.
2. Часто исследуемый мною текст слишком мал, из-за чего анализ ломался.
По итогу я пошел искать другую библиотеку и нашел lingua, которая успешно справляется с проблемами langdetect.
Важное отличие этой библиотеки от всех остальных в том, что она использует не только статистическую модель для определения языка, а ещё и механизмы, основанные на правилах - сначала определяется алфавит текста, ищутся символы которые уникальны для языка и после этого выбираются языки, на которых возможно написан текст.
Но есть возможность улучшить этот процесс. Можно самому ограничить языки, на которых возможно будет написан текст, а это как раз то, что мне и нужно:
Из-за ограничения языков вероятность совершить ошибку на небольших предложениях сокращается многократно. В добавок ко всему, ребята используют не только триграммы, которые очень часто используют для таких задач, а n-граммы от 1 до 5, из-за чего вероятность предсказания повышается.
Причина такого решения проста - чем короче входной текст, тем меньше n-грамм доступно, а если мы будем проверять триграммами короткие заголовки - будут случаться ошибки.
Ну и база - ограничение количества языков ускоряет работу и уменьшает потребление памяти, а при исследовании огромных текстов - это несомненный плюс.
#nlp #библиотека
Сначала я попытался использовать langdetect, но он часто выдавал неправильные результаты. Как правило, плохие результаты выдавались по нескольким причинам:
1. Нет возможности ограничить языки, которые я хотел бы детектить. Мне надо определять всего четыре языка - украинский, русский, английский и немецкий.
2. Часто исследуемый мною текст слишком мал, из-за чего анализ ломался.
По итогу я пошел искать другую библиотеку и нашел lingua, которая успешно справляется с проблемами langdetect.
Важное отличие этой библиотеки от всех остальных в том, что она использует не только статистическую модель для определения языка, а ещё и механизмы, основанные на правилах - сначала определяется алфавит текста, ищутся символы которые уникальны для языка и после этого выбираются языки, на которых возможно написан текст.
Но есть возможность улучшить этот процесс. Можно самому ограничить языки, на которых возможно будет написан текст, а это как раз то, что мне и нужно:
from lingua import Language, LanguageDetectorBuilder
languages = [Language.ENGLISH, Language.RUSSIAN, Language.GERMAN, Language.UKRAINIAN]
detector = LanguageDetectorBuilder.from_languages(*languages).build()
print(detector.detect_language_of("Hello from box with python!")) # Language.ENGLISH
print(detector.detect_language_of("Привет от коробки с питоном!")) # Language.RUSSIAN
Из-за ограничения языков вероятность совершить ошибку на небольших предложениях сокращается многократно. В добавок ко всему, ребята используют не только триграммы, которые очень часто используют для таких задач, а n-граммы от 1 до 5, из-за чего вероятность предсказания повышается.
Причина такого решения проста - чем короче входной текст, тем меньше n-грамм доступно, а если мы будем проверять триграммами короткие заголовки - будут случаться ошибки.
Ну и база - ограничение количества языков ускоряет работу и уменьшает потребление памяти, а при исследовании огромных текстов - это несомненный плюс.
#nlp #библиотека
PyPI
langdetect
Language detection library ported from Google's language-detection.
Немного девопсовский пост, так как на предыдущем месте работы я много админил линукса.
Автоматизация - один из столпов работы любого админа, так как подготавливать сервера руками - занятие тяжелое и трудозатратное.
Для этого я всегда выбирал Ansible - это довольно простой инструмент, который позволяет настраивать сервера из специальных yaml конфигов, которые называются плейбуками.
Но какой бы вы инструмент не выбрали, рано или поздно конфигурация будет усложняться, а плейбуков/скриптов станет много. В какой-то момент всё это может сломаться, поэтому любую автоматизацию надо тестировать.
Когда я админил, команда не хотела полностью завязываться на Ansible (соответственно Molecule отпадает), решено было искать инструмент, который позволял бы тестировать состояние сервера после работы любой автоматизации.
И я нашел такой инструмент, имя ему - testinfra. Это плагин для pytest, который позволяет лаконично описывать тесты проверяющие состояние сервера.
Например, мы написали автоматизацию, которая устанавливает nginx. Проверим, что он установлен:
Напоследок, вот вам еще кейс использования: одно время при помощи testinfra я тестировал правильность сборки контейнеров - все ли есть права, запустился ли сервис, в порядке ли конфиги и так далее.
#devops #библиотека
Автоматизация - один из столпов работы любого админа, так как подготавливать сервера руками - занятие тяжелое и трудозатратное.
Для этого я всегда выбирал Ansible - это довольно простой инструмент, который позволяет настраивать сервера из специальных yaml конфигов, которые называются плейбуками.
Но какой бы вы инструмент не выбрали, рано или поздно конфигурация будет усложняться, а плейбуков/скриптов станет много. В какой-то момент всё это может сломаться, поэтому любую автоматизацию надо тестировать.
Когда я админил, команда не хотела полностью завязываться на Ansible (соответственно Molecule отпадает), решено было искать инструмент, который позволял бы тестировать состояние сервера после работы любой автоматизации.
И я нашел такой инструмент, имя ему - testinfra. Это плагин для pytest, который позволяет лаконично описывать тесты проверяющие состояние сервера.
Например, мы написали автоматизацию, которая устанавливает nginx. Проверим, что он установлен:
def test_nginx_is_installed(host):А теперь проверим, что сервис с ним запущен:
nginx = host.package("nginx")
assert nginx.is_installed
def test_nginx_running_and_enabled(host):Самое важное - для него существует много connection backend'ов, которые позволяют подключаться к серверам для теста как по SSH (через paramiko), так и используя инвентарь Ansible. Так же есть бекенды для docker/podman/salt/kubectl/openshift/winrm/lxc - обо всём этом можно почитать здесь.
nginx = host.service("nginx")
assert nginx.is_running
assert nginx.is_enabled
Напоследок, вот вам еще кейс использования: одно время при помощи testinfra я тестировал правильность сборки контейнеров - все ли есть права, запустился ли сервис, в порядке ли конфиги и так далее.
#devops #библиотека
Если вам приходилось работать с bash, например парсить логи, вы наверняка видели или использовали команды следующего вида:
Символ
В Elixir есть оператор конвейера
Согласитесь, так удобнее работать с коллекциями, особенно там где данных много и их хочется как-то отфильтровать. В случае использования конвейеров нам больше не надо строить громоздкие циклы, а код прост и понятен.
Если вам интересно. как можно сделать такое в Python, то для вас есть библиотека Pipe. Реализация очень простая - библиотека добавляет класс Pipe который переопределяет оператор
Например, вот так мы можем получить сумму товаров, цена которых больше тысячи:
cat app.log | grep 'exception' | awk '{ print $2 }'
Здесь мы последовательно считываем содержимое файла app.log
, фильтруем по подстроке exception
и выводим вторую колонку. Символ
|
, которая разделяет команды называется "пайпом" - он перенаправляет вывод из одной команды в другую, а вся эта конструкция в целом называется конвейером, и она очень часто используется в функциональном программировании.В Elixir есть оператор конвейера
|>
который позволяет передавать результат выполнения левого выражения в правое. Это позволяет делать вот такие штуки:1..10Здесь мы генерируем список от 1 до 10, умножаем каждый элемент на 2 и фильтруем только те, которые больше 10.
|> Enum.map(fn x -> x * 2 end)
|> Enum.filter(fn x -> x > 10 end)
[12, 14, 16, 18, 20]
Согласитесь, так удобнее работать с коллекциями, особенно там где данных много и их хочется как-то отфильтровать. В случае использования конвейеров нам больше не надо строить громоздкие циклы, а код прост и понятен.
Если вам интересно. как можно сделать такое в Python, то для вас есть библиотека Pipe. Реализация очень простая - библиотека добавляет класс Pipe который переопределяет оператор
|
. Далее мы оборачиваем наши функции в этот класс и можем строить конвейеры!Например, вот так мы можем получить сумму товаров, цена которых больше тысячи:
from typing import NamedTuple
from pipe import select, where
class Product(NamedTuple):
name: str
price: int
products = [Product("choco", 123), Product("auto", 10000), Product("photo", 1200)]
sum(
products
| select(lambda product: product.price)
| where(lambda x: x > 1000)
) # 11200
#библиотекаGitHub
GitHub - JulienPalard/Pipe: A Python library to use infix notation in Python
A Python library to use infix notation in Python. Contribute to JulienPalard/Pipe development by creating an account on GitHub.
Коробка с питоном
Как раз сегодня искал фреимворк для организации работы консьюмера RabbitMQ и на глаза попался Propan - декларативный фреимворк для работы с очередями сообщений. Для чего это нужно? На базе очередей можно построить асинхронную коммуникацию сервисов, а это…
Помните, я рассказывал про такой фреимворк как Propan? В общем, программа Propan удаляется на смену Propan пришел FastStream, и весь новый функционал будет попадать в него.
Первой моей реакцией было "што" и "зачем", ведь на первый взгляд может показаться, что поменялись только орга и название. Давайте разбираться.
Во-первых, за фреимворком стоит не только сам Lancetnik, а целая команда из AirtAI, что является очень сильным усилением со стороны как разработки, так и поддержки.
Второе, FastKafka переходит в такой же статус как и Propan. Всё по той же причине - новый функционал будут добавлять в FastStream.
В свою очередь FastStream - это фреимворк, базированный на идеях FastKafka и Propan, который хочет взять от них самое лучшее и создать единый способ для написания сервисов, работающих с очередями.
Третье, что показалось мне важным, разработчик Propan признаётся, что сделать унифицированный RPC для всех брокеров (например для Kafka) - задача сложная, особенно когда брокер by design плохо рассчитан на такую функциональность. Всё сводилось к тому, что тот самый простой высокоуровневый интерфейс плохо скрывал недостатки реализации, поэтому в FastStream от него отказались.
Ещё генерацию темплейтов удалили, теперь проект можно генерировать при помощи cookiecutter.
А что нового уже принёс FastStream?
В первую очередь, мне понравился механизм фильтров. Ещё добавили кастомную сериализацию - по умолчанию FastStream работает с Json, но если у вас Protobuf, Avro или msgpack - больше никаких проблем нет, можно добавить собственную логику для сериализации.
Отдельно хотел бы выделить систему мидлварей - теперь трассировку, логи, обогащение сообщений метаинформацией делать намного проще.
Очень надеюсь, что проект будет развиваться семимильными шагами, ведь идеи FastKafka и Propan мне очень сильно понравились, а сам Propan я очень часто рекомендовал знакомым.
P.S. Оказывается кастомная сериализация уже была.
#библиотека
Первой моей реакцией было "што" и "зачем", ведь на первый взгляд может показаться, что поменялись только орга и название. Давайте разбираться.
Во-первых, за фреимворком стоит не только сам Lancetnik, а целая команда из AirtAI, что является очень сильным усилением со стороны как разработки, так и поддержки.
Второе, FastKafka переходит в такой же статус как и Propan. Всё по той же причине - новый функционал будут добавлять в FastStream.
В свою очередь FastStream - это фреимворк, базированный на идеях FastKafka и Propan, который хочет взять от них самое лучшее и создать единый способ для написания сервисов, работающих с очередями.
Третье, что показалось мне важным, разработчик Propan признаётся, что сделать унифицированный RPC для всех брокеров (например для Kafka) - задача сложная, особенно когда брокер by design плохо рассчитан на такую функциональность. Всё сводилось к тому, что тот самый простой высокоуровневый интерфейс плохо скрывал недостатки реализации, поэтому в FastStream от него отказались.
Ещё генерацию темплейтов удалили, теперь проект можно генерировать при помощи cookiecutter.
А что нового уже принёс FastStream?
В первую очередь, мне понравился механизм фильтров. Ещё добавили кастомную сериализацию - по умолчанию FastStream работает с Json, но если у вас Protobuf, Avro или msgpack - больше никаких проблем нет, можно добавить собственную логику для сериализации.
Отдельно хотел бы выделить систему мидлварей - теперь трассировку, логи, обогащение сообщений метаинформацией делать намного проще.
Очень надеюсь, что проект будет развиваться семимильными шагами, ведь идеи FastKafka и Propan мне очень сильно понравились, а сам Propan я очень часто рекомендовал знакомым.
P.S. Оказывается кастомная сериализация уже была.
#библиотека
GitHub
GitHub - airtai/faststream: FastStream is a powerful and easy-to-use Python framework for building asynchronous services interacting…
FastStream is a powerful and easy-to-use Python framework for building asynchronous services interacting with event streams such as Apache Kafka, RabbitMQ, NATS and Redis. - airtai/faststream
Недавно пришлось писать конвертор который транслировал Markdown в довольно специфичный формат.
Была следующая идея - мне нужен парсер, который перегонит Markdown в синтаксическое дерево, которое я буду обходить.
С обычным python-markdown в этом плане банально неудобно работать - у него нет простого и расширяемого API (как минимум), который бы позволял решить мою задачу.
А вот у mistletoe такое API есть. Например, вот так выглядит рендерер markdown в jira:
#библиотека
Была следующая идея - мне нужен парсер, который перегонит Markdown в синтаксическое дерево, которое я буду обходить.
С обычным python-markdown в этом плане банально неудобно работать - у него нет простого и расширяемого API (как минимум), который бы позволял решить мою задачу.
А вот у mistletoe такое API есть. Например, вот так выглядит рендерер markdown в jira:
class JiraRenderer(BaseRenderer):Ещё mistletoe можно использовать как утилиту. Например, вот так markdown-файл можно перевести в тот же формат Jira:
def render_strong(self, token):
template = '*{}*'
return template.format(self.render_inner(token))
def render_emphasis(self, token):
template = '_{}_'
return template.format(self.render_inner(token))
mistletoe foo.md --renderer mistletoe.contrib.jira_renderer.JiraRendererПоэтому, если вам нужна небольшая, но расширяемая библиотека для работы с markdown - берите её, не прогадаете.
#библиотека
Коробка с питоном
Если обычного itertools вам мало, то можно использовать more-itertools. Эта библиотека добавляет огромное количество функций для работы с итераторами. На практике всеми ими не всегда пользуются, поэтому я выделю некоторые из тех, которые сам использую часто.…
На сегодня расскажу ещё пару рецептов с
1)
2) Получить последний элемент можно при помощи
Ещё есть
3)
4) Ну и в конце про
#itertools #more_itertools #библиотека #рецепт
more_itertools
.1)
map_if
работает как обычный map
, но применяет функцию на элемент только если оно попадает под условие. Например, вот так мы можем возвести в квадрат только те числа, которые делятся на 2 нацело:example = [1, 2, 3, 4, 5, 6, 7, 8]
list(map_if(example, lambda x: x % 2 == 0, lambda x: x * x)) # [1, 4, 3, 16, 5, 36, 7, 64]
2) Получить последний элемент можно при помощи
last
. Возникает вопрос а зачем он существует, если можно указать sequence[-1]
? Ответом является то, что last
позволяет указать, что ему возвращать, если элементов в коллекции нет:last([1, 2, 3]) # Очевидно получим 3
last([], 0) # Список пустой, но получим 0
[][-1] # Получим IndexError
Ещё есть
first
- как понятно из названия, он получает первый элемент.3)
map_except
тоже работает как map
, но умеет игнорировать ошибки. Например, мы хотим получить только те элементы, которые получилось привести к целому числу:example = [1, "1", "2", "test", "three", object, 4.0]
list(map_except(int, example, ValueError, TypeError)) # [1, 1, 2, 4]
4) Ну и в конце про
take
- он просто берет N элементов из итерируемого объекта:example = range(10)
take(3, example) # [0, 1, 2]
take(20, example) # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] - если больше, возьмет доступные
#itertools #more_itertools #библиотека #рецепт
В одном чатике встретил проект fakeredis, реализующий Redis-сервер на питоне, который можно использовать для тестов. Очевидно, чтобы не таскать для тестов настоящий Redis.
Поддерживаются практически все стандартные команды, которые я встречал для работы с типами/коллекциями (список здесь). Есть не полная поддержка JSON, поиска, time series.
Если каких-то команд не хватает, автор оставил гайд, как её сделать. Ну а если сделаете - законтрибутьте в опенсорс, полезное дело всё таки!
#библиотека
Поддерживаются практически все стандартные команды, которые я встречал для работы с типами/коллекциями (список здесь). Есть не полная поддержка JSON, поиска, time series.
Если каких-то команд не хватает, автор оставил гайд, как её сделать. Ну а если сделаете - законтрибутьте в опенсорс, полезное дело всё таки!
#библиотека
GitHub
GitHub - cunla/fakeredis-py: Implementation of Redis in python without having a Redis server running. Fully compatible with using…
Implementation of Redis in python without having a Redis server running. Fully compatible with using redis-py. - cunla/fakeredis-py
Автор Pydantic совершенно недавно начал разрабатывать ещё один проект... И на этот раз он решил сделать UI фронтенд-фреимворк который назвал FastUI.
Если отвечать на вопрос "зачем", то в readme изложены вот такие поинты:
1) Если не хочется разбираться в JS/фронтенд фреимворках и всей их экосистеме;
2) Если хочется декларативно писать фронтенд на питоне, с переиспользуемыми компонентами;
3) FastUI - противоположность GraphQL, но у них одинаковые цели: когда GraphQL позволяет расширять фронтенд без расширения бекенда, FastUI предлагает расширять бекенд без разработки фронтенда;
Под капотом у нас:
- Сам пакет FastUI, который содержит утилиты и сами компоненты. Cами компоненты описаны с использованием Pydantic.
- Так как это всё это работает на react, есть npm пакет @pydantic/fastui, который позволяет повторно использовать механизмы и типы FastUI при реализации собственных компонентов.
- Bootstrap компоненты для FastUI.
- @pydantic/fastui-prebuilt который предоставляет пребилд основной части фронтенда.
Вкратце, как это работает - при помощи Pydantic моделей описываются интерфейсы React компонентов, а дальше их описания отправляются на фронтенд, где по ним отрисовываются компоненты.
Само описание небольшой страницы выглядит как-то так:
Простенько, лаконично, декларативно. Но такой же подход использует Flet, Dash и ещё куча других фреимворков. Очень интересно, взлетит ли это или нет?
Забавно, что мы не кодим на Rust, но всё у нас "fast" - FastAPI, FastUI, FastStream :D
#библиотека
Если отвечать на вопрос "зачем", то в readme изложены вот такие поинты:
1) Если не хочется разбираться в JS/фронтенд фреимворках и всей их экосистеме;
2) Если хочется декларативно писать фронтенд на питоне, с переиспользуемыми компонентами;
3) FastUI - противоположность GraphQL, но у них одинаковые цели: когда GraphQL позволяет расширять фронтенд без расширения бекенда, FastUI предлагает расширять бекенд без разработки фронтенда;
Под капотом у нас:
- Сам пакет FastUI, который содержит утилиты и сами компоненты. Cами компоненты описаны с использованием Pydantic.
- Так как это всё это работает на react, есть npm пакет @pydantic/fastui, который позволяет повторно использовать механизмы и типы FastUI при реализации собственных компонентов.
- Bootstrap компоненты для FastUI.
- @pydantic/fastui-prebuilt который предоставляет пребилд основной части фронтенда.
Вкратце, как это работает - при помощи Pydantic моделей описываются интерфейсы React компонентов, а дальше их описания отправляются на фронтенд, где по ним отрисовываются компоненты.
Само описание небольшой страницы выглядит как-то так:
c.Page(
components=[
c.Heading(text=user.name, level=2),
c.Link(components=[c.Text(text='Back')], on_click=BackEvent()),
c.Details(data=user),
]
)
Простенько, лаконично, декларативно. Но такой же подход использует Flet, Dash и ещё куча других фреимворков. Очень интересно, взлетит ли это или нет?
#библиотека
GitHub
GitHub - pydantic/FastUI: Build better UIs faster.
Build better UIs faster. Contribute to pydantic/FastUI development by creating an account on GitHub.
С наступившим 2024 вас! Сегодня расскажу про dirty-equals.
Этот пакет используется для реализации более читаемых и декларативных проверок на равенство/соответствие, но в полной мере он себя раскрывает при написании тестов.
Как обычно, приведу несколько примеров:
Рекомендую заглянуть в документацию, там таких удобных штук ещё очень много! Ну и изучите исходники - написано не сложно, под капотом используется чуток метаклассов, для изучения темы - самое то!
#библиотека
Этот пакет используется для реализации более читаемых и декларативных проверок на равенство/соответствие, но в полной мере он себя раскрывает при написании тестов.
Как обычно, приведу несколько примеров:
from dirty_equals import *
>>> assert 1 == IsPositive # Всё ок, число положительное
>>> assert -2 == IsPositive # AssertionError
>>> # Проверки можно комбинировать при помощи булевой логики
>>> assert ['a', 'b', 'c'] == HasLen(3) & Contains('a') # Ок, список на 3 элемента, содержит 'a'
>>> # Есть проверка словарей
>>> assert {'a': 1, 'b': 2} == IsDict(a=1, b=2)
>>> # Словари можно проверять частично
>>> assert {'a': 1, 'b': 2, 'c': 3} == IsDict(a=1, b=2).settings(partial=True)
>>> # Или вот так
>>> assert {'a': 1, 'b': 2, 'c': 3} == IsPartialDict(a=1, b=2)
>>> Можно проверять соответствие регуляркам
>>> assert 'test@kiriha.ru' == IsStr(regex=r'^[^@]+@[^@]+\.[^@]+$')
>>> # И так далее...
Рекомендую заглянуть в документацию, там таких удобных штук ещё очень много! Ну и изучите исходники - написано не сложно, под капотом используется чуток метаклассов, для изучения темы - самое то!
#библиотека