🟠 Telegram боти. Приблизний список додаткових параметрів в обробниках.
bot: Bot
command: CommandObject
fsm_storage: MemoryStorage
state: FSMContext
dispatcher: Dispatcher
bots: tuple
raw_state: str | None
handler: HandlerObject
event_update: Update
event_router: Router
event_context: EventContext
event_from_user: User
event_chat: Chat
#tg_bots
bot: Bot
command: CommandObject
fsm_storage: MemoryStorage
state: FSMContext
dispatcher: Dispatcher
bots: tuple
raw_state: str | None
handler: HandlerObject
event_update: Update
event_router: Router
event_context: EventContext
event_from_user: User
event_chat: Chat
#tg_bots
👍2
🟡 Telegram боти. Приклад використання додаткових параметрів у обробнику
Команди телеграм бота можуть мати аргументи.
Уявімо ситуацію коли ми хочемо реалізувати команду яка рахує суму чисел:
У відповідь будемо очікувати:
До обробника додамо параметр command: CommandObject 🔗 , який полегшує розбір аргументів команди.
Атрибут command.args це рядок з аргументами, якщо вони є, а якщо немає він дорівнює None.
#tg_bots
Команди телеграм бота можуть мати аргументи.
Уявімо ситуацію коли ми хочемо реалізувати команду яка рахує суму чисел:
/sum 1 2 3.5
У відповідь будемо очікувати:
Сума: 6.5
До обробника додамо параметр command: CommandObject 🔗 , який полегшує розбір аргументів команди.
Атрибут command.args це рядок з аргументами, якщо вони є, а якщо немає він дорівнює None.
from aiogram.filters import CommandObject
@router.message(Command("sum"))
async def sum_handler(message: Message, command: CommandObject):
success = False
if args := command.args and command.args.split():
try:
result = sum(map(float, args))
success = True
await message.answer(f"Сума: {result}")
except ValueError:
pass
if not success:
await message.answer(
"Щось пішло не так, можливо передані неправильні аргументи /sum"
)
#tg_bots
👍1
🔴 Опис роботи echo-бота. Відправка повідомлень.
Розглянемо код тіла функції-обробника.
Є два способи відправляти повідомлення:
▪️ через об'єкт Message
▪️ через об'єкт Bot
Перевага відправки через bot: Bot у тому що можна відсилати повідомлення у інші чати і гілки чатів.
Telegram дозволяє надсилати форматований текст у форматах HTML і Markdown
(насправді — у їхніх дуже спрощених версіях).
🔗 Telegram Bot API: Markdown v2
🔗 Telegram Bot API: HTML
⚠️ Якщо передати некоректний HTML, виникне виняток типу:
Тому завжди потрібно зважати на текст, який передається у вигляді змінних — чи не може він зламати HTML-розмітку. У нашому прикладі message.from_user.first_name — це ім’я користувача, яке може містити символи
👉 Щоб уникнути таких помилок, використовуйте екранування за допомогою html.unparse() та інші функції для форматування у aiogram3
Корисні посилання по темі:
🔗 Aiogram 3 FAQ : Bad Request: can't parse entities
🔗 aiogram3 documentation: Formatting
#tg_bots
Розглянемо код тіла функції-обробника.
Є два способи відправляти повідомлення:
▪️ через об'єкт Message
▪️ через об'єкт Bot
from aiogram import html
@router.message(Command("start"))
async def start_handler(message: Message):
await message.answer(
f"<i>Hello</i> {html.unparse(message.from_user.first_name)}!",
parse_mode=ParseMode.HTML
)
Перевага відправки через bot: Bot у тому що можна відсилати повідомлення у інші чати і гілки чатів.
from aiogram import html
@router.message(Command("start"))
async def start_handler(message: Message, bot: Bot):
await bot.send_message(
chat_id=message.chat.id,
text=f"<i>Hello</i> {html.unparse(message.from_user.first_name)}!",
parse_mode=ParseMode.HTML
)
Telegram дозволяє надсилати форматований текст у форматах HTML і Markdown
(насправді — у їхніх дуже спрощених версіях).
🔗 Telegram Bot API: Markdown v2
🔗 Telegram Bot API: HTML
⚠️ Якщо передати некоректний HTML, виникне виняток типу:
TelegramBadRequest('Telegram server says - Bad Request: can't parse entities ...')
Тому завжди потрібно зважати на текст, який передається у вигляді змінних — чи не може він зламати HTML-розмітку. У нашому прикладі message.from_user.first_name — це ім’я користувача, яке може містити символи
< або > що зламає розмітку.👉 Щоб уникнути таких помилок, використовуйте екранування за допомогою html.unparse() та інші функції для форматування у aiogram3
Корисні посилання по темі:
🔗 Aiogram 3 FAQ : Bad Request: can't parse entities
🔗 aiogram3 documentation: Formatting
#tg_bots
👍1
У об'єкта message є атрибут from_user, які твердження правильні?
Anonymous Poll
6%
from_user.id може бути None
28%
from_user.first_name може бути None
56%
from_user.last_name може бути None
28%
from_user.username може бути None
28%
Сам атрибут message.from_user може бути None
22%
Не знаю, я просто хочу подивитися результати опитування
🟤 Телеграм боти. Використання магічних фільтрів.
🔗 Message.from_user
🔗 User
Як бачимо:
▪️ username і last_name можуть бути None
▪️ cам атрибут from_user може бути None
⚠️ Об'єкти у aiogram3 часто можуть бути None — варто зважати на це.
Те що ми використовуємо first_name у коді обробника не спричиняє проблем.А ось те що не перевіряєм from_user на None це потенційна проблема. Чесно кажучи я не можу назвати випадок коли повідомлення може приходити без відправника, але мабуть може ... і мабуть ми хотіли би уникнути проблем пов'язаних з цим. Крім того тайп чекери типу mypy при перевірці коду будут вказувати на цю потенційну проблему.
👉 Рішенням може бути використання магічних фільтрів:
Фільтр бере об'єкт message і перевіряє атрибут from_user, якщо from_user is None обробник просто не буде викликатись, якщо не None то from_user буде переданий як додатковий параметр.
Виклик методу .as_() як раз відповідає за передачу додаткового параметру у обробник, у ньому вказується ім'я цього параметру.
#tg_bots
🔗 Message.from_user
🔗 User
class User(TelegramObject):
id: int
first_name: str
last_name: str | None
username: str | None
# ...
Як бачимо:
▪️ username і last_name можуть бути None
▪️ cам атрибут from_user може бути None
⚠️ Об'єкти у aiogram3 часто можуть бути None — варто зважати на це.
Те що ми використовуємо first_name у коді обробника не спричиняє проблем.А ось те що не перевіряєм from_user на None це потенційна проблема. Чесно кажучи я не можу назвати випадок коли повідомлення може приходити без відправника, але мабуть може ... і мабуть ми хотіли би уникнути проблем пов'язаних з цим. Крім того тайп чекери типу mypy при перевірці коду будут вказувати на цю потенційну проблему.
👉 Рішенням може бути використання магічних фільтрів:
from aiogram F
from aiogram.types import User
@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
)
Фільтр бере об'єкт message і перевіряє атрибут from_user, якщо from_user is None обробник просто не буде викликатись, якщо не None то from_user буде переданий як додатковий параметр.
Виклик методу .as_() як раз відповідає за передачу додаткового параметру у обробник, у ньому вказується ім'я цього параметру.
#tg_bots
👍1
Чи варто продовжувати писати пости і писати про телеграм ботів?
Здається про тг ботів писати можна вічно. Буде ще один канал по тг ботам?
Але наразі по телеграм ботам такий приблизний план:
▪️ pydantic-settings
▪️ Dependency injection
▪️ Filters / BotAdminFilter
▪️ Робота з фото.
Можливо варто переключитись на іншу тему, наприклад
про скрапінг даних? Якийсь сайт заскрапати?
Пишіть пропозиції у коментарях і голосуйте.
Здається про тг ботів писати можна вічно. Буде ще один канал по тг ботам?
Але наразі по телеграм ботам такий приблизний план:
▪️ pydantic-settings
▪️ Dependency injection
▪️ Filters / BotAdminFilter
▪️ Робота з фото.
Можливо варто переключитись на іншу тему, наприклад
про скрапінг даних? Якийсь сайт заскрапати?
Пишіть пропозиції у коментарях і голосуйте.
👍1👎1
❓ Що виведе код:
👉 🔗 Перечитати пост про екранування html.
🡇🡇🡇 Опитування нижче 🡇🡇🡇
from aiogram import html as aiogram_html # unparse
import html as builtin_html # escape
nickname = "DeadInside <x_x>"
print(
aiogram_html.unparse(nickname),
aiogram_html.unparse(nickname) == builtin_html.escape(nickname),
)
👉 🔗 Перечитати пост про екранування html.
🡇🡇🡇 Опитування нижче 🡇🡇🡇
✴️ Клас для налаштувань за допомогою pydantic_settings
python-dotenv — це добре, але лише тоді, коли налаштувань небагато.
Існує бібліотека pydantic_settings яка використовує pydantic та python-dotenv і дозволяє:
1️⃣ Об'єднати всі змінні в один клас.
2️⃣ Конвертувати та валідувати значення змінних із рядків у потрібні типи.
3️⃣ Підтримувати вкладені класи, що дає змогу згрупувати змінні за призначенням.
4️⃣ Зменшити ймовірність розкриття секретних значень при виводі через print або при логувані
5️⃣ Інші тонкі налаштування.
🔗 Pydantic Settings Documentation
Уявімо ситуацію, коли нам потрібно зберігати список ID адміністраторів бота та налаштування підключення до бази даних. pydantic_settings уміє працювати з базовими типами, включно зі списками та множинами (парсити їх за допомогою бібліотеки json). Також бібліотека надає широкий простір налаштування процесу валідації під конкретні потреби.
Файл .env
Фай main.py
Вивід:
python-dotenv — це добре, але лише тоді, коли налаштувань небагато.
Існує бібліотека pydantic_settings яка використовує pydantic та python-dotenv і дозволяє:
1️⃣ Об'єднати всі змінні в один клас.
2️⃣ Конвертувати та валідувати значення змінних із рядків у потрібні типи.
3️⃣ Підтримувати вкладені класи, що дає змогу згрупувати змінні за призначенням.
4️⃣ Зменшити ймовірність розкриття секретних значень при виводі через print або при логувані
5️⃣ Інші тонкі налаштування.
🔗 Pydantic Settings Documentation
Уявімо ситуацію, коли нам потрібно зберігати список ID адміністраторів бота та налаштування підключення до бази даних. pydantic_settings уміє працювати з базовими типами, включно зі списками та множинами (парсити їх за допомогою бібліотеки json). Також бібліотека надає широкий простір налаштування процесу валідації під конкретні потреби.
Файл .env
BOT__TOKEN="Ваш токен"
BOT__ADMINS=[1361728070, 1060557517]
DB__HOST=localhost
DB__PORT=5432
DB__USER=postgres
DB__PASSWORD=mysecretpassword
DB__NAME=mydatabase
Фай main.py
# pip insatall pydantic
from pydantic import BaseModel, SecretStr
# pip insatall pydantic_settings
from pydantic_settings import BaseSettings
class BotSettings(BaseModel):
token: SecretStr # BOT__TOKEN
admins: frozenset[int] # BOT__ADMINS
class DatabaseSettings(BaseModel):
host: str # DB__HOST
port: int = 5432 # DB__PORT
user: str # DB__USER
password: SecretStr # DB__PASSWORD
name: str # DB__NAME
class Settings(BaseSettings):
bot: BotSettings
db: DatabaseSettings
async def main():
settings = Settings(
_env_file=".env",
_env_nested_delimiter='__'
)
print(repr(settings))
# use: settings.bot.token.get_secret_value()
# for get origin token value
if __name__ == "__main__":
asyncio.run(main())
Вивід:
Settings(bot=BotSettings(token=SecretStr('**********'), admins=frozenset({1060557517, 1361728070})), db=DatabaseSettings(host='localhost', port=5432, user='postgres', password=SecretStr('**********'), name='mydatabase')✳️ Телеграм боти. 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