# Модули

# Pip, описание модулей

**Альтернативные зеркала**

Возможны случаи, когда это потребуется.

```
pip install <package> -i <hostname>
Например
pip install fastapi -i https://pypi.tuna.tsinghua.edu.cn/simple
```

<table border="1" id="bkmrk-%D0%90%D0%B4%D1%80%D0%B5%D1%81-%D1%80%D0%B5%D0%BF%D0%BE%D0%B7%D0%B8%D1%82%D0%BE%D1%80%D0%B8%D1%8F-%D0%A2%D0%B8" style="border-collapse: collapse; width: 100%; height: 119.188px;"><colgroup><col style="width: 35.988%;"></col><col style="width: 64.012%;"></col></colgroup><thead><tr style="height: 29.7969px;"><td class="align-center" style="height: 29.7969px;">Адрес репозитория</td><td class="align-center" style="height: 29.7969px;">Тип</td></tr></thead><tbody><tr style="height: 29.7969px;"><td style="height: 29.7969px;"><div>https://pypi.org/simple</div></td><td style="height: 29.7969px;">Основной репозиторий</td></tr><tr style="height: 29.7969px;"><td style="height: 29.7969px;">[https://pypi.tuna.tsinghua.edu.cn/simple](https://pypi.tuna.tsinghua.edu.cn/simple)</td><td style="height: 29.7969px;">Вроде очень стабильный репозиторий</td></tr><tr style="height: 29.7969px;"><td style="height: 29.7969px;">[https://mirrors.aliyun.com/pypi/simple](https://mirrors.aliyun.com/pypi/simple)</td><td style="height: 29.7969px;">Европейский вариант</td></tr></tbody></table>

<div id="bkmrk-"></div><div id="bkmrk-pip-install-fastapi--1">Настройка pip без необходимости указания сервера</div><div id="bkmrk-%25appdata%25%5Cpip%5Cpip.in">Файл %APPDATA%\pip\pip.ini Если директории нет - создать.</div>```
[global]
index-url = https://pip.ya.ru/simple
trusted-host = pip.ya.ru
```

**Хранение конфигурации**

**Configparser** стандартная библиотека для чтения и записи .ini файлов. [Инструкция 1](https://sky.pro/media/kak-rabotat-s-modulem-configparser-v-python/)

**Jsonschema** модуль для проверки соответствия json существующей схеме. [Документация](https://python-jsonschema.readthedocs.io/en/stable/index.html)

**Libsettings** модуль на основе [jsonschema](http://bobrobotirk.ru/books/python/page/jsonschema "jsonschema") для чтения конфигурации из json файла и проверки конфигурации на соответствие схеме. [Gitverse проекта](https://gitverse.ru/bobrobot/libsettings)

```python
import logging
from libsettings import Jsettings

logging.basicConfig(level=logging.ERROR,
                    filename='error.log',
                    format="%(levelname)s %(message)s")
mysettings = Jsettings(settingsfname='mysettings.json',
                          schemafname='myschema.json')
mysettings.load_settings()
```

# jsonschema

Используется для валидации json схемы. По умолчанию дополнительно указанные ключи (не существующие в схеме, но присутствующие в документе) не проверяются.

**Установка**

```bash
pip install jsonschema
```

**Базовое использование**

```python
from jsonschema import validate

validate(instance=json_to_check, schema=schema)
```

**Исключения**

jsonschema.exceptions.ValidationError - если документ не соответствует структуре

jsonschema.exceptions.SchemaError - если сама схема некорректна

**Пример схемы:**

```json
schema = {
    "type": "object",
    "properties": {
        "name": {"type": "string"},
        "age": {"type": "number"},
    },
    "required": ["name"],
}
```

Данная схема определяет json объект с 2 свойствами: name и age. Обязательное свойство name.

**Ключевые слова**

Для некоторых типов используются дополнительные ключевые слова.

<table border="1" id="bkmrk-%D0%9A%D0%BB%D1%8E%D1%87%D0%B5%D0%B2%D0%BE%D0%B5-%D1%81%D0%BB%D0%BE%D0%B2%D0%BE-%D0%9E%D0%BF%D0%B8%D1%81%D0%B0" style="border-collapse: collapse; width: 100%;"><colgroup><col style="width: 16.9211%;"></col><col style="width: 83.0789%;"></col></colgroup><thead><tr><td class="align-center">Ключевое слово</td><td class="align-center">Описание</td></tr></thead><tbody><tr><td>type</td><td>Тип. Для корня часто object.

string - строка

number - число

object - объект

array - список

</td></tr><tr><td>$defs</td><td>Вложенный шаблон для случая, когда шаблон элемента встречается в нескольких местах.</td></tr><tr><td>$ref</td><td>Подстановка вложенного шаблона.</td></tr><tr><td>$schema</td><td>Ссылка на шаблон шаблона. При обновлении версии библиотеки будет использоваться новый шаблон шаблона, что может привести к проблемам. Желательно указывать.</td></tr></tbody></table>

**Дополнительные ключевые слова для типов.**

 **Тип array**

<table border="1" id="bkmrk-%D0%9A%D0%BB%D1%8E%D1%87%D0%B5%D0%B2%D0%BE%D0%B5-%D1%81%D0%BB%D0%BE%D0%B2%D0%BE-%D0%9E%D0%BF%D0%B8%D1%81%D0%B0-1" style="border-collapse: collapse; width: 100%; height: 89.3907px;"><colgroup><col style="width: 17.4405%;"></col><col style="width: 82.6786%;"></col></colgroup><thead><tr style="height: 29.7969px;"><td class="align-center" style="height: 29.7969px;">Ключевое слово</td><td class="align-center" style="height: 29.7969px;">Описание</td></tr></thead><tbody><tr style="height: 29.7969px;"><td style="height: 29.7969px;">items</td><td style="height: 29.7969px;">Тип элементов списка.

```json
"scores": {
            "type": "array",
            "items": {"type": "number"},
        }
```

</td></tr><tr style="height: 29.7969px;"><td style="height: 29.7969px;">minItems</td><td style="height: 29.7969px;">Минимальное количество элементов</td></tr><tr><td>  
</td><td>  
</td></tr></tbody></table>

**Тип object**

<table border="1" id="bkmrk-%D0%9A%D0%BB%D1%8E%D1%87%D0%B5%D0%B2%D0%BE%D0%B5-%D1%81%D0%BB%D0%BE%D0%B2%D0%BE-%D0%9E%D0%BF%D0%B8%D1%81%D0%B0-2" style="border-collapse: collapse; width: 100%; height: 89.3907px;"><colgroup><col style="width: 17.2025%;"></col><col style="width: 82.9167%;"></col></colgroup><thead><tr style="height: 29.7969px;"><td class="align-center" style="height: 29.7969px;">Ключевое слово</td><td class="align-center" style="height: 29.7969px;">Описание</td></tr></thead><tbody><tr style="height: 29.7969px;"><td style="height: 29.7969px;">required</td><td style="height: 29.7969px;">Список обязательных ключей.

```json
"required": ["name"]
```

</td></tr><tr style="height: 29.7969px;"><td style="height: 29.7969px;">properties</td><td style="height: 29.7969px;">Определяет ключи объекта и их тип.

```json
"properties": {
        "name": {"type": "string"}
    },
```

</td></tr><tr><td>additionalProperties</td><td>Если True, то дополнительно указанные ключи приводят к исключению.

</td></tr></tbody></table>

**Локальные вложенные шаблоны.**

Для определения используется переменная $defs, для использования - $ref.

```json
schema = {
    "type": "object",
    "properties": {
        "address": {"$ref": "#/$defs/address"},
    },
    "$defs": {
        "address": {
            "type": "object",
            "properties": {
                "street": {"type": "string"},
            }
        },
    },
}
```

# Pydantic 2

**Описание**

Библиотека валидации (проверка на соответствие типов) и трансформации (автоматическое приведение к нужным типам и форматам) данных.

Модели наследуются от класса BaseModel. Модель описывает набор полей, представляющих структуру данных и условия валидации.

**Установка**

```bash
pip install pydantic
```

**Типизация:**

- Простая: указание типа, например, name: str.
- Объект Field(): дополнительные параметры, например, значения по умолчанию, ограничения и т.д.

Внутри класса можно комбинировать способы типизации.

```python
from pydantic import BaseModel, Field

class User(BaseModel):
    name: str
    email: str = Field(..., alias='email_address')
```

**Валидация:**

- Минимальная валидация: встроенные типы Python (например, str, int).
- Валидаторы: например EmailStr для проверки email-адресов. Требуется установка дополнительных зависимостей: pydantic\[email\] или pydantic\[all\].
- @field\_validator — добавляет логику валидации поля. Вызывается при создании или изменении модели.

```python
from pydantic import BaseModel, field_validator

class User(BaseModel):
    age: int

    @field_validator('age')
    def check_age(cls, value):
        if value < 18:
            raise ValueError('Возраст должен быть больше 18 лет')
        return value
```

- @computed\_field — вычисляемое поле на основе данных в модели. Его можно использовать для автоматической генерации значений, а также для валидации.

```python
from pydantic import BaseModel, computed_field

class User(BaseModel):
    name: str
    surname: str

    @computed_field
    def full_name(self) -> str:
        return f"{self.name} {self.surname}"
```

- @model\_validator - валидация всей модели.

Работает со всей моделью (а не с отдельными полями), может изменять данные перед валидацией (mode='before') или после (mode='after'), полезен для комплексных проверок, где одно поле зависит от другого, может возвращать новую версию модели (если нужно модифицировать данные).

```python
@model_validator(mode='before')
def validate_before(cls, data: dict):
    if 'username' not in data:
        data['username'] = "guest_" + str(data.get('id', 0))
    return data
```

```python
@model_validator(mode='after')
def validate_after(self):
    if self.age < 18 and self.is_premium:
        raise ValueError("Minors cannot have premium accounts!")
    return self
```

При проверке before передается класс, при after - объект. Можно делать два валидатора: before для подстановки вычисляемых значений и after для финальной проверки

**Интеграция с SQLAlchemy:**

Для настройки используется параметр ConfigDict с флагом from\_attributes=True.

```python
from datetime import date
from pydantic import BaseModel, ConfigDict

class User(BaseModel):
    id: int
    name: str = 'John Doe'
    birthday_date: date

    config = ConfigDict(from_attributes=True)
```

Для создания модели Pydantic из объекта ORM используется метод from\_orm.

```python
user = User.from_orm(orm_instance)
```

**Ссылки:**

[Основа для текста](https://habr.com/ru/companies/amvera/articles/851642/)

# Pyinstaller

Установка:

```
python -m pip install pyinstaller
```

Использование

```
pyinstaller [параметры] script.py
```

Параметры

<table border="1" id="bkmrk-%D0%9F%D0%B0%D1%80%D0%B0%D0%BC%D0%B5%D1%82%D1%80-%D0%9E%D0%BF%D0%B8%D1%81%D0%B0%D0%BD%D0%B8%D0%B5---" style="border-collapse: collapse; width: 100%;"><colgroup><col style="width: 25.6232%;"></col><col style="width: 74.3768%;"></col></colgroup><thead><tr><td class="align-center">Параметр</td><td class="align-center">Описание</td></tr></thead><tbody><tr><td>--onefile</td><td>собирает всё в один .exe файл</td></tr><tr><td>--windowed</td><td>скрывает консоль (если у вас GUI-приложение). Если нужна консоль, уберите этот флаг.</td></tr><tr><td>--icon=ваша\_иконка.ico</td><td>иконка</td></tr><tr><td>--name "МояПрограмма"</td><td>имя программы</td></tr><tr><td>--dest &lt;путь\_к\_директории&gt;</td><td>директория, в которую будет собираться exe файл</td></tr></tbody></table>

# Telegram

При взаимодействии с ботом нужен идентификатор.

**Свой идентификатор**

- В Telegram напиши боту <a class="decorated-link cursor-pointer" data-end="565" data-start="525" rel="noopener" target="_new">@userinfobot</a>
- Он ответит твоим `user_id` (число). Это и есть твой `chat_id`. <a class="decorated-link cursor-pointer" data-end="565" data-start="525" rel="noopener" target="_new"><span aria-hidden="true" class="ms-0.5 inline-block align-middle leading-none"><svg class="block h-[0.75em] w-[0.75em] stroke-current stroke-[0.75]" data-rtl-flip="" fill="currentColor" height="20" viewbox="0 0 20 20" width="20" xmlns="http://www.w3.org/2000/svg"></svg></span></a>

**Для групп или каналов**

- Добавь бота в группу/канал.
- Напиши любое сообщение.
- В браузере открой: https://api.telegram.org/bot&lt;YOUR\_BOT\_TOKEN&gt;/getUpdates
- В JSON-ответе найди `chat":{"id": ... }` — это и есть `CHAT_ID`. Для супергрупп он будет вида `-1001234567890`.

# Bitcoinlib

Библиотека для работы с кошельками. Операции, связанные с кошельком:

- + Создание нового кошелька
- Экспорт данных о созданном кошельке
- Импорт существующего кошелька
- + Информация о кошельке
- Транзакция

**Создание кошелька.** Создается хранилище данных в ~/.bitcoinlib Затем можно проводить операции.

```python
def create_wallet():
    # Создаем новый testnet кошелек
    wallet = Wallet.create(
        name='my_testnet_wallet',
        network='testnet'
    )

    print(f"Адрес: {wallet.get_key().address}")
    print(f"Приватный ключ (WIF): {wallet.get_key().wif}")
    print(f"Баланс: {wallet.balance()} satoshi")

    # Получить информацию об адресе
    print(f"Это testnet адрес? {wallet.get_key().address.startswith(('m', 'n', '2', 'tb1'))}")
```

Для получения стартовых btc в сети testnet использовал [https://coinfaucet.eu/en/btc-testnet/](https://coinfaucet.eu/en/btc-testnet/)

Информация о кошельке. Кошелек с данным названием уже установлен в системе.

```python
def wallet_info():
    """Полная информация о кошельке (исправленная)"""
    
    wallet = Wallet('my_testnet_wallet')
    wallet.scan()  # Важно: синхронизируем с сетью
    
    print("=" * 60)
    print(f"КОШЕЛЁК: {wallet.name}")
    print(f"СЕТЬ: {wallet.network.name}")
    print("=" * 60)
    
    # Баланс
    balance = wallet.balance()
    print(f"\n💰 БАЛАНС: {balance:,} satoshi")
    print(f"         ≈ {balance / 100000000:.8f} BTC")
    
    # UTXOs
    utxos = wallet.utxos()
    print(f"\n UTXOs: {len(utxos)}")
    
    if utxos:
        utxo_total = 0
        for i, utxo in enumerate(utxos, 1):
            print(f"\n  UTXO #{i}:")
            print(f"    Транзакция: {utxo['txid'][:20]}...:{utxo['output_n']}")
            print(f"    Адрес: {utxo['address']}")
            print(f"    Сумма: {utxo['value']:,} sat")
            
            if 'confirmations' in utxo:
                confs = utxo['confirmations']
                status = "✓ Подтверждено" if confs > 0 else " Ожидание"
                print(f"    Статус: {status} ({confs} подтверждений)")
            
            utxo_total += utxo['value']
        
        print(f"\n  Сумма всех UTXOs: {utxo_total:,} sat")
    
    # Транзакции
    transactions = wallet.transactions()
    print(f"\n ТРАНЗАКЦИИ: {len(transactions)}")
    
    if transactions:
        for tx in transactions:
            print(f"\n  Транзакция: {tx.txid[:20]}...")
            print(f"    Дата: {tx.date}")
            
            if tx.confirmations:
                print(f"    Подтверждений: {tx.confirmations}")
            else:
                print(f"    Статус: Неподтверждена")
            
            print(f"    Комиссия: {tx.fee} sat")
            
            # Анализируем сумму
            our_addresses = wallet.addresslist()
            received = 0
            sent = 0
            
            # Выходы (получение)
            for output in tx.outputs:
                if output.address in our_addresses:
                    received += output.value
            
            # Входы (отправка)
            for input_tx in tx.inputs:
                if input_tx.address in our_addresses:
                    sent += input_tx.value
            
            if received > 0 and sent > 0:
                print(f"    Тип: Перевод")
                print(f"    Изменение баланса: {received - sent:,} sat")
            elif received > 0:
                print(f"    Тип: Получение")
                print(f"    Сумма: +{received:,} sat")
            elif sent > 0:
                net_sent = sent - tx.fee
                print(f"    Тип: Отправка")
                print(f"    Сумма: -{net_sent:,} sat (включая комиссию)")
    
    # Ключи и адреса
    print(f"\n КЛЮЧИ И АДРЕСА:")
    keys = wallet.keys()
    print(f"  Всего ключей: {len(keys)}")
    
    used_addresses = [key.address for key in keys if key.used]
    print(f"  Использованных адресов: {len(used_addresses)}")
    
    # Показываем первые 5 адресов
    for i, key in enumerate(keys[:5], 1):
        status = " Использован" if key.used else " Не использован"
        print(f"  {i}. {key.address} - {status} ({key.balance} sat)")
    
    if len(keys) > 5:
        print(f"  ... и ещё {len(keys) - 5} адресов")
    
    # Сетевая информация
    print(f"\n СЕТЕВАЯ ИНФОРМАЦИЯ:")
    #print(f"  Последний блок: {wallet.last_block}")
    print(f"  ID кошелька: {wallet.wallet_id}")
    
    return wallet
```

# Логгирование

Встроенный модуль logging. Нужно настроить логгер и использовать его.

Настройка:

---

```python
import logging

if __name__ == '__main__':
    logging.basicConfig(level=logging.ERROR, filename="error.log",filemode="w",
                        format="%(asctime)s %(levelname)s %(message)s")
```

**Использование:**

Внутри модуля, где настраивался логгер:

```
logging.error("Критическая ошибка в основном модуле")
```

В вызываемом модуле не проводим настройку, только:

```python
logger = logging.getLogger(__name__)
logger.error('Wow')
```

# Docsvision

Существует webapi

Узнать realm можно через ipconfig на win машине в домене, строка "DNS-суффикс подключения"

Список контроллеров домена: nslookup -type=SRV \_ldap.\_tcp.&lt;realm&gt;

Для работы требуется

```
sudo apt install krb5-user
sudo apt install libkrb5-dev
```

Файл /etc/krb5.conf

```
[libdefaults]
    default_realm = DOMAIN.LOCAL
    dns_lookup_realm = true
    dns_lookup_kdc = true

[realms]
    DOMAIN.LOCAL = {
        kdc = dc01.domain.local
        admin_server = dc01.domain.local
    }
```

Для ручного получения тикета <span style="color: rgb(224, 62, 45);">(REALM обязательно прописными!)</span>:

```
kinit username@REALM
```

Проверка полученного тикета:

```
klist
```

Модули python

b