✳️ Телеграм боти. Dependency Injection
Доопрацюємо нашого бота: зробимо різні привітання для звичайних користувачів та адміністраторів.
ID адміністраторів у нас міститься в об’єкті Settings, і виникає проблема — як його отримати у функції обробника.
Це можна зробити кількома способами:
1️⃣ Створити об’єкт Settings як глобальну змінну.
2️⃣ Використати Middleware для Dependency Injection.
3️⃣ Використати Dispatcher для Dependency Injection.
Dependency Injection (DI) — це підхід у програмуванні, який допомагає відокремити створення сутності від її використання.
Глобальні змінні — це не дуже добре. Використання Middleware — більш складний варіант. Тому давайте зосередимося на останньому варіанті.
🔗 aiogram documentation: Dependency Injection
У Dispatcher можна, як у словник, додати власні об'єкти-залежності, щоб потім отримати їх у обробнику як додаткові параметри:
На жаль, Router такої можливості не має. Якщо потрібно ізолювати дані одного роутера від іншого, варто використати Middleware.
#tg_bots
Доопрацюємо нашого бота: зробимо різні привітання для звичайних користувачів та адміністраторів.
ID адміністраторів у нас міститься в об’єкті Settings, і виникає проблема — як його отримати у функції обробника.
Це можна зробити кількома способами:
1️⃣ Створити об’єкт Settings як глобальну змінну.
2️⃣ Використати Middleware для Dependency Injection.
3️⃣ Використати Dispatcher для Dependency Injection.
Dependency Injection (DI) — це підхід у програмуванні, який допомагає відокремити створення сутності від її використання.
Глобальні змінні — це не дуже добре. Використання Middleware — більш складний варіант. Тому давайте зосередимося на останньому варіанті.
🔗 aiogram documentation: Dependency Injection
async def main():
settings = Settings(
_env_file=".env",
_env_nested_delimiter='__'
)
async with Bot(token=settings.bot.token.get_secret_value()) as bot:
storage = MemoryStorage()
dp = Dispatcher(storage=storage)
dp.startup.register(startup)
dp.include_router(router)
# Use Dependency Injection
dp["settings"] = settings
await dp.start_polling(bot)
У Dispatcher можна, як у словник, додати власні об'єкти-залежності, щоб потім отримати їх у обробнику як додаткові параметри:
@router.message(Command("start"), F.from_user.as_("from_user"))
async def start_handler(message: Message, from_user: User, settings: Settings):
if from_user.id in settings.bot.admins:
text = f"<i>Hello admin</i> {html.unparse(from_user.first_name)}!"
else:
text = f"<i>Hello</i> {html.unparse(from_user.first_name)}!"
await message.answer(text=text, parse_mode=ParseMode.HTML)На жаль, Router такої можливості не має. Якщо потрібно ізолювати дані одного роутера від іншого, варто використати Middleware.
#tg_bots
👍1
Що має вертати при виклику фільтр aiogram3
Anonymous Quiz
31%
bool
6%
dict
13%
None або dict
0%
bool або dict
0%
list або dict
6%
list або bool
0%
list aбо dict або bool
0%
list
44%
Хочу подивитись правильну відповідь
❇️ Телеграм-боти. Власний клас-фільтр.
Ми має код обробника у якому є if-else для визначення логіки звичайний користувач/адміністратор.
Але це не дуже добре:
1️⃣ Якщо в нас таких обробників буде багато, то if-else буде дублюватися і ускладнювати читання коду.
2️⃣ Ми не зможемо розділити логіку звич.користувачів і адміністраторів на різні файли-модулі.
Написання власного фільтра дозволить розбити логіку на два обробника.
Ми вже ознайомились з використанням готового бібліотечного фільтра Command та магічних фільтрів,
давайте напишемо тепер свій клас-фільтр:
Як бачимо фільтр це клас який містить метод
⚠️ Тип першого параметру
При виклику фільтр вертає:
▪️ вертає False якщо при цьому оновленні не треба викликати обробник — воно не підходить
▪️ вертає dict якщо треба викликати обробник і підставити у нього додатковий аргумент from_user
🔗 aiogram documentation: Writing own filters
👉Фільтр у aiogram:
1️⃣ Визначає чи буде викликаний вказаний обробник подій
2️⃣ Може додавати параметри у обробник, вертаючи їх у словнику
#tg_bots
Ми має код обробника у якому є if-else для визначення логіки звичайний користувач/адміністратор.
Але це не дуже добре:
1️⃣ Якщо в нас таких обробників буде багато, то if-else буде дублюватися і ускладнювати читання коду.
2️⃣ Ми не зможемо розділити логіку звич.користувачів і адміністраторів на різні файли-модулі.
Написання власного фільтра дозволить розбити логіку на два обробника.
Ми вже ознайомились з використанням готового бібліотечного фільтра Command та магічних фільтрів,
давайте напишемо тепер свій клас-фільтр:
from aiogram.filters import BaseFilter
class BotAdminFilter(BaseFilter):
async def __call__(
self,
message: Message,
settings: Settings
) -> bool | dict[str, Any]:
if message.from_user and message.from_user.id in settings.bot.admins:
return {"from_user": message.from_user}
return False
Як бачимо фільтр це клас який містить метод
__call__ , отже об'єкти цього класу можуть викликатись як функції. ⚠️ Тип першого параметру
__call__ буде залежати від типу події на яку підписуємось. При виклику фільтр вертає:
▪️ вертає False якщо при цьому оновленні не треба викликати обробник — воно не підходить
▪️ вертає dict якщо треба викликати обробник і підставити у нього додатковий аргумент from_user
🔗 aiogram documentation: Writing own filters
@router.message(Command("start"), BotAdminFilter())
async def start_admin_handler(message: Message, from_user: User):
await message.answer(
f"<i>Hello admin</i> {html.unparse(from_user.first_name)}!",
parse_mode=ParseMode.HTML
)
@router.message(Command("start"), F.from_user.as_("from_user"))
async def start_handler(message: Message, from_user: User):
await message.answer(
f"<i>Hello</i> {html.unparse(from_user.first_name)}!",
parse_mode=ParseMode.HTML
)👉Фільтр у aiogram:
1️⃣ Визначає чи буде викликаний вказаний обробник подій
2️⃣ Може додавати параметри у обробник, вертаючи їх у словнику
#tg_bots
❤1👍1
🔰 Телеграм-боти. Функція як фільтр.
Класи, об’єкти яких можна викликати, — це добре: можна передавати додаткові налаштування через їхній ініціалізатор.
Але в нашому випадку це не потрібно — список ID адміністраторів ми отримуємо через механізм DI.
Тому ми можемо спростити код, написавши просто функцію, яка буде фільтром:
#tg_bots
Класи, об’єкти яких можна викликати, — це добре: можна передавати додаткові налаштування через їхній ініціалізатор.
Але в нашому випадку це не потрібно — список ID адміністраторів ми отримуємо через механізм DI.
Тому ми можемо спростити код, написавши просто функцію, яка буде фільтром:
async def is_bot_admin(message: Message, settings: Settings) -> bool | dict[str, Any]:
if message.from_user and message.from_user.id in settings.bot.admins:
return {"from_user": message.from_user}
return False
@router.message(Command("start"), is_bot_admin)
async def start_admin_handler(message: Message, from_user: User):
... # код обробника#tg_bots
👍1
🔵 Консольні аргументи (Command-line Arguments). Приклад
Повернемось до теми Корисні речі, які варто знати про процес
Консольні аргументи, також відомі як аргументи командного рядка, — це параметри або значення, які передаються програмі під час її запуску через інтерфейс командного рядка (CLI) або термінал
main.py
А тепер запустимо наш скрипт таким чином:
Отримаємо
Це список рядків який містить назву скрипта та аргументи які ми передали. Аргументи розділяються між собою пробілам. Щоб аргумент що містить пробіли правильно сприймався треба його обрамляти у лапки. Це особливо важливо коли ми передаємо шлях до файлів як аргумент.
👉 Консольні аргументи дають додаткову можливість задавати деякі налаштування та хід виконання програми.
Повернемось до теми Корисні речі, які варто знати про процес
Консольні аргументи, також відомі як аргументи командного рядка, — це параметри або значення, які передаються програмі під час її запуску через інтерфейс командного рядка (CLI) або термінал
main.py
import sys
print(sys.argv)
А тепер запустимо наш скрипт таким чином:
python main.py a b "c d"
Отримаємо
['main.py', 'a', 'b', 'c d']
Це список рядків який містить назву скрипта та аргументи які ми передали. Аргументи розділяються між собою пробілам. Щоб аргумент що містить пробіли правильно сприймався треба його обрамляти у лапки. Це особливо важливо коли ми передаємо шлях до файлів як аргумент.
👉 Консольні аргументи дають додаткову можливість задавати деякі налаштування та хід виконання програми.
👍1
🟣 Консольні аргументи (Command-line Arguments). Теорія.
Терміни з якими варто розібратись:
▪️ Опції/прапорці/ключи (Options/Flags/Keys): часто аргументи починаються з дефісів (наприклад,
▪️ Значення (Values): опції можуть супроводжуватися значеннями (наприклад,
▪️ Позиційні аргументи (Positional Arguments): аргументи без певних прапорців часто вважаються позиційними — тобто їхній порядок має значення, і вони призначаються змінним відповідно до своєї позиції у команді.
▪️ Підкоманди (Subcommands) або іноді просто команди: деякі програми підтримують ієрархічну структуру команд, де основна команда має кілька підкоманд, кожна з яких виконує окрему дію або функцію. Наприклад, у команді
(
Підкоманди дозволяють організовувати складні CLI-програми у логічні модулі та покращують їхню зручність використання.
Терміни з якими варто розібратись:
▪️ Опції/прапорці/ключи (Options/Flags/Keys): часто аргументи починаються з дефісів (наприклад,
-l, --long) і позначають певні параметри або прапорці, що змінюють поведінку програми. Один дефіс за звичай використовується у скорочених назвах, два для більш повних. Під Windows також може використовуватись слеш / замість дефісу ▪️ Значення (Values): опції можуть супроводжуватися значеннями (наприклад,
--output file.txt), що надають конкретні дані для цієї опції.▪️ Позиційні аргументи (Positional Arguments): аргументи без певних прапорців часто вважаються позиційними — тобто їхній порядок має значення, і вони призначаються змінним відповідно до своєї позиції у команді.
▪️ Підкоманди (Subcommands) або іноді просто команди: деякі програми підтримують ієрархічну структуру команд, де основна команда має кілька підкоманд, кожна з яких виконує окрему дію або функцію. Наприклад, у команді
git commit -m "msg" слово commit є підкомандою, яка визначає конкретну операцію, тоді як -m "msg" — аргументи, що належать до цієї підкоманди. (
-m - опція "msg" — її значення)Підкоманди дозволяють організовувати складні CLI-програми у логічні модулі та покращують їхню зручність використання.
👍1
🟢 Консольні аргументи (Command-line Arguments). Практика.
У python для розбору консольних аргументів використовується стандартна бібліотека argparse
Вона бере на себe:
1️⃣ Розбір аргументів на підкоманди, опції, позиційні аргументи, значення.
2️⃣ Конвертацію аргументів у заданий тип
3️⃣ Обробку помилок неправильного застосування консольних аргументів
4️⃣ Об'єднання позиційних аргументів у одну змінну-список
5️⃣ Генерацію довідки по консольним аргументам.
Напишемо просту програму яка має дві підкоманди для суми та добутку чисел:
Приклад виводу:
argparse по замовченню додає опцію
Виклик методу
🔗 Переклад офіційної документації python: argparse
У python для розбору консольних аргументів використовується стандартна бібліотека argparse
Вона бере на себe:
1️⃣ Розбір аргументів на підкоманди, опції, позиційні аргументи, значення.
2️⃣ Конвертацію аргументів у заданий тип
3️⃣ Обробку помилок неправильного застосування консольних аргументів
4️⃣ Об'єднання позиційних аргументів у одну змінну-список
5️⃣ Генерацію довідки по консольним аргументам.
Напишемо просту програму яка має дві підкоманди для суми та добутку чисел:
import argparse
import enum
import math
class SubCommand(enum.StrEnum):
SUM = enum.auto()
MULT = enum.auto()
def main():
parser = argparse.ArgumentParser()
subparsers = parser.add_subparsers(
dest='subcommand',
title='subcommands',
required=True,
)
sum_parser = subparsers.add_parser(
SubCommand.SUM.value,
help="sum float values",
)
sum_parser.add_argument('values', type=float, nargs='+')
mult_parser = subparsers.add_parser(
SubCommand.MULT.value,
help="multiply float values",
)
mult_parser.add_argument('values', type=float, nargs='+')
args = parser.parse_args()
match args.subcommand:
case SubCommand.SUM:
result = sum(args.values)
case SubCommand.MULT:
result = math.prod(args.values)
print(result)
if __name__ == '__main__':
main()
Приклад виводу:
python main.py sum 3 4 5
12.0
python main.py mult 3 4 5
60.0
python main.py mult a b
usage: main.py mult [-h] values [values ...]
main.py mult: error: argument values: invalid float value: 'a'
argparse по замовченню додає опцію
—-help по якій виводиться довідка по консольним аргументам:python main.py --help
usage: main.py [-h] {sum,mult} ...
options:
-h, --help show this help message and exit
subcommands:
{sum,mult}
sum sum float values
mult multiply float values
Виклик методу
sum_parser.add_argument('values', type=float, nargs='+') вказує парить позиційні аргументи зі збереженням їх у атрибут args.values у вигляді списку. Якщо ми вказуємо тип type=float відбувається конвертацію аргументів і вказаний тип. Вказання nargs='+' дає нам упаковку декількох аргументів у один список, в даному випадку має бути що найменше один аргумент🔗 Переклад офіційної документації python: argparse
👍1
Яка з команд буде правильно працювати як під Windows так і під Linux ?
Anonymous Quiz
9%
python -c print('Hello world!')
12%
python -c "print("Hello world!")"
21%
python -c print("Hello world!")
6%
python -c "print(\"Hello world!\")"
9%
python -c "print('Hello world!')"
12%
python -c 'print("Hello world!")'
30%
Хочу лише подивитись правильну відповідь
♻️ Телеграм боти. Використання консольних аргументів.
Іноді зручно мати кілька .env-файлів із різними налаштуваннями та мати змогу запускати проєкт, указуючи, з яким файлом його запускати. Ми можемо мати, наприклад, два файли —
Ми можемо запукати проєкт вказуючи шлях/ім'я до файлу опцією --env-file
Або
Якщо запускати без зазначення опції — значення братимуться лише з системного оточення; якщо їх немає, виникне помилка валідації.
#tg_bots
Іноді зручно мати кілька .env-файлів із різними налаштуваннями та мати змогу запускати проєкт, указуючи, з яким файлом його запускати. Ми можемо мати, наприклад, два файли —
.env.dev та .env.prod, тобто два профілі налаштувань: для розробки та для роботи на сервері.import argparse
async def main():
parser = argparse.ArgumentParser()
parser.add_argument(
"--env-file",
type=str,
default=None,
help="Path to the dotenv-file",
)
args = parser.parse_args()
settings = Settings(
_env_file=args.env_file,
_env_nested_delimiter='__',
)
async with Bot(token=settings.bot.token.get_secret_value()) as bot:
storage = MemoryStorage()
dp = Dispatcher(storage=storage)
dp["settings"] = settings
dp.startup.register(startup)
dp.include_router(router)
await dp.start_polling(bot)
Ми можемо запукати проєкт вказуючи шлях/ім'я до файлу опцією --env-file
python main.py --env-file .env.devАбо
python main.py --env-file .env.prodЯкщо запускати без зазначення опції — значення братимуться лише з системного оточення; якщо їх немає, виникне помилка валідації.
#tg_bots
👍1🔥1
🔴 Exit code
Повернемось до теми Корисні речі, які варто знати про процес
Код завершення процесу (exit code, return code) — це числове значення, яке процес повертає операційній системі після свого завершення.
Воно показує, як саме процес завершився:
0️⃣ 0 — успішне виконання без помилок;
1️⃣ Будь-яке ненульове значення, вказує на помилку або особливу причину завершення, залежно від програми.
Код завершення використовується іншими процесами, скриптами чи системами автоматизації (наприклад, bash, make, systemd) для визначення, чи потрібно вважати виконання команди успішним або повторити/обробити помилку.
У Linux перевірити exit code останньої команди можна через змінну
У Windows щоб отримати код завершення останньої команди, використовують змінну
Для прикладу розглянемо код
sys.exit() задає код завершення процесу, для помилок ми використали значення 1,2,3
Запустимо наш код у командному рядку:
Linux
Windows
Команда echo виведе нам код з яким завершився процес.
Так як відбувається ділення на 0 — код завершення буде 3.
Інший процес або скрипт може легко дізнатись код завершення і прийняти відповідне рішення.
Повернемось до теми Корисні речі, які варто знати про процес
Код завершення процесу (exit code, return code) — це числове значення, яке процес повертає операційній системі після свого завершення.
Воно показує, як саме процес завершився:
0️⃣ 0 — успішне виконання без помилок;
1️⃣ Будь-яке ненульове значення, вказує на помилку або особливу причину завершення, залежно від програми.
Код завершення використовується іншими процесами, скриптами чи системами автоматизації (наприклад, bash, make, systemd) для визначення, чи потрібно вважати виконання команди успішним або повторити/обробити помилку.
У Linux перевірити exit code останньої команди можна через змінну
$?.У Windows щоб отримати код завершення останньої команди, використовують змінну
%ERRORLEVEL%.Для прикладу розглянемо код
import sys
def main() -> int:
if len(sys.argv) != 3:
print("Usage: python script.py <num1> <num2>", file=sys.stderr)
return 1
try:
a = float(sys.argv[1])
b = float(sys.argv[2])
print(a / b)
return 0
except ValueError:
print("Error: arguments must be numbers", file=sys.stderr)
return 2
except ZeroDivisionError:
print("Error: division by zero", file=sys.stderr)
return 3
if __name__ == "__main__":
sys.exit(main())
sys.exit() задає код завершення процесу, для помилок ми використали значення 1,2,3
Запустимо наш код у командному рядку:
Linux
python3 main.py 1 0
echo $?
Windows
python main.py 1 0
echo %ERRORLEVEL%
Команда echo виведе нам код з яким завершився процес.
Так як відбувається ділення на 0 — код завершення буде 3.
Інший процес або скрипт може легко дізнатись код завершення і прийняти відповідне рішення.
❤1👍1
Підбірка відео укр. по веб фреймворку FastApi від "Python Decoded"
1. FastApi Українською - Резолвери Схеми Роутери
2. FastApi Українською - Обробка Помилок та Middleware
3. FastApi Українською - Ін'єкція Залежностей
4. FastApi Українською - Інтеграція Бази Даних
1. FastApi Українською - Резолвери Схеми Роутери
2. FastApi Українською - Обробка Помилок та Middleware
3. FastApi Українською - Ін'єкція Залежностей
4. FastApi Українською - Інтеграція Бази Даних
YouTube
1. FastApi Українською - Резолвери Схеми Роутери
В цій серії відео ми познайомимось з Пайтон Веб фреймворком FastApi і побудуємо власний веб застосунок.
В цьому відео ми познайомимось з такими поняттями як:
- Резолвери - resolvers
- Роутери - routers
- Схеми - schemas
Та напишемо набір CRUD операцій для…
В цьому відео ми познайомимось з такими поняттями як:
- Резолвери - resolvers
- Роутери - routers
- Схеми - schemas
Та напишемо набір CRUD операцій для…
👍4
Підбірка англ. відео про Dependency Injection від ArjanCodes:
🔗 Dependency Injection Explained in 7 Minutes
🔗 Should You Use Dependency Injection Frameworks?
🔗 Dependency INVERSION vs Dependency INJECTION in Python
🔗 Dependency Injection Explained in 7 Minutes
🔗 Should You Use Dependency Injection Frameworks?
🔗 Dependency INVERSION vs Dependency INJECTION in Python
YouTube
Dependency Injection Makes Code Easier to Change and Test
👷 Review code better and faster with my 3-Factor Framework: https://arjan.codes/diagnosis.
In this video, I'll explain why dependency injection is a game-changer for your coding projects. Creating loosely coupled code is key to making the code more flexible…
In this video, I'll explain why dependency injection is a game-changer for your coding projects. Creating loosely coupled code is key to making the code more flexible…
❤1
Git. Ситуація: Створили репозиторій.Є файл A.txt. Виконали: git add A.txt
Потрібно прибрати A.txt зі staging, не видаляючи файл з диска і не змінюючи його вміст. Що можна виконати? (декілька варіантів)
Потрібно прибрати A.txt зі staging, не видаляючи файл з диска і не змінюючи його вміст. Що можна виконати? (декілька варіантів)
Anonymous Poll
16%
git restore A.txt
37%
git reset A.txt
0%
git restore A.txt
16%
git rm A.txt
63%
git restore --staged A.txt
🟣 Потоки вводу/виводу (Input/Output Streams, stdin/stdout/stderr)
Повернемось до теми Корисні речі, які варто знати про процес
У попередньому прикладі коду я використав такий вивід:
Що це значить?
Подивимось у документацію:
🔗 Документація
Простими слова file це те куди виводити рядок нашого повідомлення. По замовченню вивід відбувається у sys.stdout. Також вивід може відбуватись у реальний файл або у поток sys.stdout - спеціальний потік для помилок.
⚠️ Варто зауважити: що потік в/в в анг. варіанті це stream i/o і не варто його плутати з thread - потоком виконання.
sys.stdout як sys.stderr це два потоки для виводу (stream output) обидва виводять текст у консоль користувач не бачить різницю між ними візуально.
При програмній автоматизації процесів можливо перехоплювати текст з обох потоків, можемо окремо мати звичайний тест інформаційного характеру з sys.stdout і окремо з sys.stderr
Є ще третій поток sys.stdin - це поток для вводу, він необхідний для читання вводу користувача у консоль.
При програмній автоматизації ми також можемо вводити текст замість користувача.
👉 Практична цінність знання про потоки в/в полягає саме у можливості автоматизувати взаємодію між процесами (IPC) шляхом їх перехоплення.
Повернемось до теми Корисні речі, які варто знати про процес
У попередньому прикладі коду я використав такий вивід:
print("Usage: python script.py <num1> <num2>", file=sys.stderr)Що це значить?
Подивимось у документацію:
print(*objects, sep=' ', end='\n', file=None, flush=False)
The file argument must be an object with a write(string) method; if it is not present or None,
sys.stdout will be used. Since printed arguments are converted to text strings,
print() cannot be used with binary mode file objects. For these, use file.write(...) instead.
🔗 Документація
Простими слова file це те куди виводити рядок нашого повідомлення. По замовченню вивід відбувається у sys.stdout. Також вивід може відбуватись у реальний файл або у поток sys.stdout - спеціальний потік для помилок.
⚠️ Варто зауважити: що потік в/в в анг. варіанті це stream i/o і не варто його плутати з thread - потоком виконання.
sys.stdout як sys.stderr це два потоки для виводу (stream output) обидва виводять текст у консоль користувач не бачить різницю між ними візуально.
При програмній автоматизації процесів можливо перехоплювати текст з обох потоків, можемо окремо мати звичайний тест інформаційного характеру з sys.stdout і окремо з sys.stderr
Є ще третій поток sys.stdin - це поток для вводу, він необхідний для читання вводу користувача у консоль.
При програмній автоматизації ми також можемо вводити текст замість користувача.
👉 Практична цінність знання про потоки в/в полягає саме у можливості автоматизувати взаємодію між процесами (IPC) шляхом їх перехоплення.
👍1
🟢 Потоки введення/виведення. Практика.
У Python для створення підпроцесів використовується бібліотека subprocess.
Вона дозволяє запускати програми та працювати з їхніми потоками введення/виведення.
subprocess добре підходить для простих випадків з синхронном кодом.
Але цікавіше розглянути асинхронний приклад з asyncio, який працює одразу з усіма трьома потоками введення/виведення.
Ідея проста: запускаємо Python у інтерактивному режимі та виконуємо дві операції — 2+2 і 1/0.
Вивід у консоль:
Як бачимо ми отримали текст окремо stdout і окремо stderr.
Звісно аналогічним чином ми можемо запускати системі утіліти або інші програми написані на інших мовах програмування — це простір для автоматизації.
Але трохи дивно чому python пише текст привітання саме у stderr
У Python для створення підпроцесів використовується бібліотека subprocess.
Вона дозволяє запускати програми та працювати з їхніми потоками введення/виведення.
subprocess добре підходить для простих випадків з синхронном кодом.
Але цікавіше розглянути асинхронний приклад з asyncio, який працює одразу з усіма трьома потоками введення/виведення.
Ідея проста: запускаємо Python у інтерактивному режимі та виконуємо дві операції — 2+2 і 1/0.
import asyncio
import sys
async def read_stream(name: str, stream: asyncio.StreamReader):
while data := await stream.readline():
line = data.decode("utf8").rstrip()
print(f"[{name}]", line)
async def main():
process = await asyncio.create_subprocess_exec(
sys.executable, "-i", # python -i
stdin=asyncio.subprocess.PIPE,
stdout=asyncio.subprocess.PIPE,
stderr=asyncio.subprocess.PIPE,
)
stdout_task = asyncio.create_task(
read_stream("stdout", process.stdout),
)
stderr_task = asyncio.create_task(
read_stream("stderr", process.stderr),
)
process.stdin.write(b"2+2\n")
await process.stdin.drain()
process.stdin.write(b"1/0\n")
await process.stdin.drain()
process.stdin.write(b"exit()\n")
await process.stdin.drain()
await process.wait() # Чекаємо завершення підпроцесу
Вивід у консоль:
[stderr] Python 3.11.6 (tags/v3.11.6:8b6ee5b, Oct 2 2023, 14:57:12) [MSC v.1935 64 bit (AMD64)] on win32
[stderr] Type "help", "copyright", "credits" or "license" for more information.
[stdout] 4
[stderr] >>> >>> Traceback (most recent call last):
[stderr] File "<stdin>", line 1, in <module>
[stderr] ZeroDivisionError: division by zero
[stderr] >>>
Як бачимо ми отримали текст окремо stdout і окремо stderr.
Звісно аналогічним чином ми можемо запускати системі утіліти або інші програми написані на інших мовах програмування — це простір для автоматизації.
Python Materials For Beginners
Знову git www.youtube.com/watch?v=y6meVhckYmQ #git
Непогане відео про "Environment variables" та .env файли.
https://www.youtube.com/watch?v=Hn5sgLafAMQ
https://www.youtube.com/watch?v=Hn5sgLafAMQ
YouTube
Your .env File Is Lying to You
This video breaks down env vars from the operating system level up — where they live, how they move between processes, and why your app works locally but breaks in Docker.
Environment variables aren't a framework feature — they're an OS primitive. Every…
Environment variables aren't a framework feature — they're an OS primitive. Every…
🔥1
Цікаве відео про черги повідомлень.
#rabbitmq #kafka
https://www.youtube.com/watch?v=byCvosoavLw&pp=ugUEEgJ1aw%3D%3D
#rabbitmq #kafka
https://www.youtube.com/watch?v=byCvosoavLw&pp=ugUEEgJ1aw%3D%3D
YouTube
Kafka чи RabitMQ - Що обрати?
Kafka та RabbitMQ вирішують різні проблеми, обери неправильно і будеш змушений усе перероблювати. Це відео в деталях розглядає як вони працюють під копотом — RabbitMQ як розумний брокер повідомлень, який виконує маршрутизацію та видаляє повідомлення, Kafka…