# Digital Energy Python SDK
- [Описание](#описание)
- [Системные требования](#системные-требования)
- [Установка](#установка)
- [Использование](#использование)
- [Конфигурация](#конфигурация)
- [Функциональный интерфейс](#функциональный-интерфейс)
- [Вызов функции](#вызов-функции)
- [Результат выполнения функции](#результат-выполнения-функции)
- [Соответствие названий](#соответствие-названий)
- [Типы данных SDK](#типы-данных-sdk)
- [Ошибки и исключения (exceptions)](#ошибки-и-исключения-exceptions)
- [Ошибки валидации данных](#ошибки-валидации-данных)
- [Ошибки HTTP](#ошибки-http)
- [Доступная функциональность](#доступная-функциональность)
## Описание
**Digital Energy Python SDK** предоставляет удобный интерфейс для интеграции взаимодействия с API **Digital Energy** в программный код на языке Python.
## Системные требования
### Совместимость версий **Digital Energy** и версий SDK
| Digital Energy | SDK |
| --- | --- |
| 1.9.0 | 2.0.x |
| 1.8.0 | 1.0.x |
### Зависимости
Зависимости указаны в конфигурационном файле проекта [pyproject.toml](/pyproject.toml):
- версия Python: раздел `[project]`, ключ `requires-python`
- библиотеки: раздел `[project]`, ключ `dependencies`
## Установка
Установка с помощью системы управления пакетами Python (pip), `version` - тег или ветка:
```sh
pip install git+https://repository.basistech.ru/BASIS/de-py-sdk@version
```
Посмотреть версию установленного пакета:
```sh
pip show digital_energy_sdk
```
## Использование
### Конфигурация
Для работы с SDK необходимо создать экземпляр класса `DigitalEnergy`, конструктор которого принимает на вход параметры конфигурации SDK.
Авторизация
```python
from digital_energy_sdk import DigitalEnergy
DE_URL = '...'
USERNAME = '...'
PASSWORD = '...'
token = DigitalEnergy(
url=DE_URL,
auth='',
).api.session.create(
username=USERNAME,
password=PASSWORD,
).result.token
de = DigitalEnergy(url=DE_URL, auth=token)
```
Задание декораторов для всех вызываемых функций
```python
from digital_energy_sdk import DigitalEnergy
DigitalEnergy(
...,
f_decorators=[decorator_1, decorator_2],
)
```
Декораторы будут применяться к вызываемым функциям SDK в обратном порядке, то есть сначала будет применяться декоратор decorator_2, а потом decorator_1.
**Важно:** декораторы должны соответствовать аннотации параметра, то есть оставлять без изменений параметры и тип возвращаемого значения функции, иначе применение декораторов приведёт к некорректной работе SDK.
Настройка повторных попыток при 503
По умолчанию SDK при получении кода ответа 503 производит 10 повторных попыток с интервалом 5 секунд. Данное поведение можно скорректировать:
```python
from digital_energy_sdk import DigitalEnergy
DigitalEnergy(
...,
http503_attempts = 10, # количество повторных попыток при 503
http503_attempts_interval = 5, # интервал в секундах между повторными попытками
)
```
Отключение проверки сертификата SSL
**Важно:** отключение проверки сертификата SSL даёт возможность произвести атаку типа MitM, поэтому пользоваться данной возможостью допустимо только в защищённой среде.
```python
import urllib3
from digital_energy_sdk import DigitalEnergy
urllib3.disable_warnings() # отключение вывода предупреждений безопасности SSL
DigitalEnergy(
...,
verify_ssl=False, # отключение проверки сертификата SSL
)
```
### Функциональный интерфейс
Функциональный интерфейс предоставляет функциональные объекты, каждый из которых является реализацией соответствующей функции API. Для упрощения изложения в данном руководстве вместо термина **функциональный объект** будет использоваться термин **функция**, если это позволяет контекст.
#### Вызов функции
Выбор функции, передача параметров и сохранение результата
```python
from digital_energy_sdk import DigitalEnergy
de = DigitalEnergy(...)
# /digitalenergy/cluster/get
result = de.api.digitalenergy.cluster.get(id=1)
```
Передача параметров перечисляемого типа (enum)
```python
from digital_energy_sdk import DigitalEnergy
from digital_energy_sdk.api.digitalenergy.cluster.list import Type
de = DigitalEnergy(...)
# /digitalenergy/cluster/list
list_result = de.api.digitalenergy.cluster.list(type=Type.DENERGY)
```
Передача файловых параметров
```python
from digital_energy_sdk import DigitalEnergy
from digital_energy_sdk.types.params import ParamFile
de = DigitalEnergy(...)
file_name = ...
with open(file_name, 'rb') as f:
# /digitalenergy/files/fileUpload
de.api.digitalenergy.files.file_upload(
file=ParamFile(
file_name=file_name,
content=f,
)
)
```
#### Результат выполнения функции
Тип данных, возвращаемый функцией SDK зависит от типа данных, возвращаемого соответствующей функцией API.
Если в результате функции API присутствует структура данных в виде набора пар ключ/значение с заранее известными ключами, то в результате функции SDK эта структура будет представлена в виде модели Pydantic. Остальные типы данных будут представлены соответствующими встроенными типами данных Python.
Модель
```python
import pydantic
from digital_energy_sdk import DigitalEnergy
de = DigitalEnergy(...)
# /digitalenergy/cluster/list
list_result = de.api.digitalenergy.cluster.list()
print(type(list_result)) #
print(isinstance(list_result, pydantic.BaseModel)) # True
```
Обращение к полю модели
```python
from digital_energy_sdk import DigitalEnergy
de = DigitalEnergy(...)
# /digitalenergy/cluster/list
clusters = de.api.digitalenergy.cluster.list().result.clusters
```
Вложенная модель
```python
import pydantic
from digital_energy_sdk import DigitalEnergy
de = DigitalEnergy(...)
# /digitalenergy/cluster/list
cluster1 = de.api.digitalenergy.cluster.list().result.clusters[0]
print(type(cluster1)) #
print(isinstance(cluster1, pydantic.BaseModel)) # True
```
Все функциональные объекты, реализующие функции API, обладают следующими атрибутами:
| Атрибут | Описание |
| --- | --- |
| `api_path` | API URL path. |
| `config` | Экземпляр конфигурации SDK. |
| `func_name` | Название функции SDK в формате digitalenergy.cluster.list |
| `http_method` | HTTP-метод. |
| `last_http_resp` | Экзепляр класса requests.Response, полученный при последнем вызове ФО. |
| `last_params_model` | Модель Pydantic, содержащая параметры, переданные в последний вызов ФО. |
| `params_model_type` | Класс модели Pydantic для параметров вызова ФО. |
| `post_json` | Отправляются ли данные в формате JSON в POST-запросах. |
| `result_type` | Аннотация типа результата вызова ФО. |
| `signature` | Сигнатура вызова ФО. |
#### Соответствие названий
В SDK названия из API приведены к стилю, принятому в Python:
- PascalCase для названия классов
- snake_case для названия атрибутов классов (кроме классов перечисляемых типов)
- SCREAMING_CASE для названия атрибутов классов перечисляемых типов
### Типы данных SDK
Общие типы доступны через пакет `digital_energy_sdk.types`.
Частные типы доступны через модуль функции. Например, частные типы функции `digitalenergy.cluster.list` расположены в модуле `digital_energy_sdk.api.digitalenergy.cluster.list`.
### Ошибки и исключения (exceptions)
SDK может вызывать исключения, которые должны быть обработаны в соответствии с требованиями к разрабатываемому вами ПО.
#### Ошибки валидации данных
SDK производит валидацию параметров функций API с помощью библиотеки **Pydantic**.
Поэтому, при ошибке валидации, будет вызвано исключение `pydantic.ValidationError`.
Таким же образом валидируются данные HTTP-ответов API. Причиной ошибки валидации данных HTTP-ответа API может быть:
1. Несоответствие версии SDK и версии **Digital Energy**.
1. Программная ошибка, допущенная при разработке SDK или **Digital Energy**. Получить подтверждение наличия такой ошибки, а также ускорить её устранение, можно сообщив нам о ней.
Получить подробную информацию об исключении `pydantic.ValidationError` можно [в соответствующем разделе официальной документации Pydantic](https://docs.pydantic.dev/latest/errors/errors/) (ссылка ведёт на документацию для последней версии, поэтому важно выбрать версию, соответствующую используемой в SDK).
#### Ошибки HTTP
SDK для выполнения HTTP-запросов использует библиотеку **Requests**.
Поэтому, при ошибке HTTP-подключения, будет вызвано соответствующее исключение библиотеки **Requests**.
Для проверки соответствует ли код ответа успешному выполнению запроса, SDK вызывает метод `requests.Response.raise_for_status()`, поэтому при неуспешном HTTP-запросе также будет вызвано исключение библиотеки **Requests**.
**Примечание:** если код ответа 503, то SDK предпримет несколько повторных попыток. Подробнее в разделе [Конфигурация](#конфигурация).
Обработка ошибок HTTP
```python
from requests.exceptions import RequestException, HTTPError
from digital_energy_sdk import DigitalEnergy
cluster_id = 1
try:
get_result = de.api.digitalenergy.cluster.get(id=cluster_id)
except HTTPError as e:
resp = e.response
if resp.status_code == 404:
print(f'The cluster with ID={cluster_id} not found.')
else:
print(f'{e}: {resp.text}')
except RequestException as e:
print(e)
```
Подробную информацию об исключениях библиотеки **Requests** можно получить в [соответствующем разделе официальной документации Requests](https://requests.readthedocs.io/en/latest/user/quickstart/#errors-and-exceptions).
Использование исключения SDK
Для возможности получать дополнительную информацию о функциях SDK при ошибках HTTP-запросов, в SDK есть возможность оборачивать все исключения requests.exceptions.RequestException в исключение digital_energy_sdk.exceptions.RequestException:
```python
class RequestException(Exception):
orig_exception: requests.exceptions.RequestException
func_name: str
func_kwargs: None | dict = None
status_code: None | int = None
```
Чтобы включить использование исключения digital_energy_sdk.exceptions.RequestException, необходимо передать в конструктор класса DigitalEnergy параметр wrap_request_exceptions=True
## Доступная функциональность
На данный момент в SDK доступна реализация всех функций API, за исключением:
- `/openid/{providername}/authenticate`
- `/digitalenergy/istore/charts/download`
- `/digitalenergy/istore/icon/download`
- `/digitalenergy/istore/image/download`
- `/digitalenergy/lrecords/download`
- `/digitalenergy/cluster/getKubectlResources`