357 lines
15 KiB
Markdown
357 lines
15 KiB
Markdown
# 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.
|
||
|
||
<details><summary>Авторизация</summary>
|
||
|
||
```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)
|
||
|
||
```
|
||
|
||
</details>
|
||
|
||
<details><summary>Задание декораторов для всех вызываемых функций</summary>
|
||
|
||
```python
|
||
from digital_energy_sdk import DigitalEnergy
|
||
|
||
|
||
DigitalEnergy(
|
||
...,
|
||
f_decorators=[decorator_1, decorator_2],
|
||
)
|
||
```
|
||
|
||
Декораторы будут применяться к вызываемым функциям SDK в обратном порядке, то есть сначала будет применяться декоратор <code>decorator_2</code>, а потом <code>decorator_1</code>.
|
||
|
||
**Важно:** декораторы должны соответствовать аннотации параметра, то есть оставлять без изменений параметры и тип возвращаемого значения функции, иначе применение декораторов приведёт к некорректной работе SDK.
|
||
|
||
</details>
|
||
|
||
<details><summary>Настройка повторных попыток при 503</summary>
|
||
|
||
По умолчанию SDK при получении кода ответа 503 производит 10 повторных попыток с интервалом 5 секунд. Данное поведение можно скорректировать:
|
||
|
||
```python
|
||
from digital_energy_sdk import DigitalEnergy
|
||
|
||
|
||
DigitalEnergy(
|
||
...,
|
||
http503_attempts = 10, # количество повторных попыток при 503
|
||
http503_attempts_interval = 5, # интервал в секундах между повторными попытками
|
||
)
|
||
|
||
```
|
||
|
||
</details>
|
||
|
||
<details><summary>Отключение проверки сертификата SSL</summary>
|
||
|
||
**Важно:** отключение проверки сертификата SSL даёт возможность произвести атаку типа MitM, поэтому пользоваться данной возможостью допустимо только в защищённой среде.
|
||
|
||
```python
|
||
import urllib3
|
||
|
||
from digital_energy_sdk import DigitalEnergy
|
||
|
||
urllib3.disable_warnings() # отключение вывода предупреждений безопасности SSL
|
||
|
||
DigitalEnergy(
|
||
...,
|
||
verify_ssl=False, # отключение проверки сертификата SSL
|
||
)
|
||
```
|
||
|
||
</details>
|
||
|
||
### Функциональный интерфейс
|
||
|
||
Функциональный интерфейс предоставляет функциональные объекты, каждый из которых является реализацией соответствующей функции API. Для упрощения изложения в данном руководстве вместо термина **функциональный объект** будет использоваться термин **функция**, если это позволяет контекст.
|
||
|
||
#### Вызов функции
|
||
|
||
<details><summary>Выбор функции, передача параметров и сохранение результата</summary>
|
||
|
||
```python
|
||
from digital_energy_sdk import DigitalEnergy
|
||
|
||
|
||
de = DigitalEnergy(...)
|
||
|
||
# /digitalenergy/cluster/get
|
||
result = de.api.digitalenergy.cluster.get(id=1)
|
||
|
||
```
|
||
|
||
</details>
|
||
|
||
<details><summary>Передача параметров перечисляемого типа (enum) </summary>
|
||
|
||
```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)
|
||
|
||
```
|
||
|
||
</details>
|
||
|
||
<details><summary>Передача файловых параметров </summary>
|
||
|
||
```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,
|
||
)
|
||
)
|
||
|
||
```
|
||
|
||
</details>
|
||
|
||
#### Результат выполнения функции
|
||
|
||
Тип данных, возвращаемый функцией SDK зависит от типа данных, возвращаемого соответствующей функцией API.
|
||
|
||
Если в результате функции API присутствует структура данных в виде набора пар ключ/значение с заранее известными ключами, то в результате функции SDK эта структура будет представлена в виде модели Pydantic. Остальные типы данных будут представлены соответствующими встроенными типами данных Python.
|
||
|
||
<details><summary>Модель</summary>
|
||
|
||
```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)) # <class '....DigitalenergyClusterListResult'>
|
||
|
||
print(isinstance(list_result, pydantic.BaseModel)) # True
|
||
|
||
```
|
||
|
||
</details>
|
||
|
||
<details><summary>Обращение к полю модели</summary>
|
||
|
||
```python
|
||
from digital_energy_sdk import DigitalEnergy
|
||
|
||
|
||
de = DigitalEnergy(...)
|
||
|
||
# /digitalenergy/cluster/list
|
||
clusters = de.api.digitalenergy.cluster.list().result.clusters
|
||
|
||
```
|
||
|
||
</details>
|
||
|
||
<details><summary>Вложенная модель</summary>
|
||
|
||
```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)) # <class '....ClustersItem'>
|
||
|
||
print(isinstance(cluster1, pydantic.BaseModel)) # True
|
||
|
||
```
|
||
|
||
</details>
|
||
|
||
<br>Все функциональные объекты, реализующие функции API, обладают следующими атрибутами:
|
||
|
||
| Атрибут | Описание |
|
||
| --- | --- |
|
||
| `api_path` | API URL path. |
|
||
| `config` | Экземпляр конфигурации SDK. |
|
||
| `func_name` | Название функции SDK в формате <code>digitalenergy.cluster.list</code> |
|
||
| `http_method` | HTTP-метод. |
|
||
| `last_http_resp` | Экзепляр класса <code>requests.Response</code>, полученный при последнем вызове ФО. |
|
||
| `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**.<br>
|
||
Поэтому, при ошибке валидации, будет вызвано исключение `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**.<br>
|
||
Поэтому, при ошибке HTTP-подключения, будет вызвано соответствующее исключение библиотеки **Requests**.
|
||
|
||
Для проверки соответствует ли код ответа успешному выполнению запроса, SDK вызывает метод `requests.Response.raise_for_status()`, поэтому при неуспешном HTTP-запросе также будет вызвано исключение библиотеки **Requests**.
|
||
|
||
**Примечание:** если код ответа 503, то SDK предпримет несколько повторных попыток. Подробнее в разделе [Конфигурация](#конфигурация).
|
||
|
||
<details><summary>Обработка ошибок HTTP</summary>
|
||
|
||
```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)
|
||
|
||
```
|
||
|
||
</details>
|
||
|
||
Подробную информацию об исключениях библиотеки **Requests** можно получить в [соответствующем разделе официальной документации Requests](https://requests.readthedocs.io/en/latest/user/quickstart/#errors-and-exceptions).
|
||
|
||
<details><summary>Использование исключения SDK</summary>
|
||
|
||
Для возможности получать дополнительную информацию о функциях SDK при ошибках HTTP-запросов, в SDK есть возможность оборачивать все исключения <code>requests.exceptions.RequestException</code> в исключение <code>digital_energy_sdk.exceptions.RequestException</code>:
|
||
|
||
```python
|
||
class RequestException(Exception):
|
||
orig_exception: requests.exceptions.RequestException
|
||
func_name: str
|
||
func_kwargs: None | dict = None
|
||
status_code: None | int = None
|
||
```
|
||
|
||
Чтобы включить использование исключения <code>digital_energy_sdk.exceptions.RequestException</code>, необходимо передать в конструктор класса <code>DigitalEnergy</code> параметр <code>wrap_request_exceptions=True</code>
|
||
</details>
|
||
|
||
## Доступная функциональность
|
||
|
||
На данный момент в SDK доступна реализация всех функций API, за исключением:
|
||
- `/openid/{providername}/authenticate`
|
||
- `/digitalenergy/istore/charts/download`
|
||
- `/digitalenergy/istore/icon/download`
|
||
- `/digitalenergy/istore/image/download`
|
||
- `/digitalenergy/lrecords/download`
|
||
- `/digitalenergy/cluster/getKubectlResources`
|