aiofortiosapi 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- aiofortiosapi-0.1.0/.github/workflows/ci.yml +46 -0
- aiofortiosapi-0.1.0/.github/workflows/release.yml +31 -0
- aiofortiosapi-0.1.0/.gitignore +47 -0
- aiofortiosapi-0.1.0/CHANGELOG.md +43 -0
- aiofortiosapi-0.1.0/LICENSE +21 -0
- aiofortiosapi-0.1.0/PKG-INFO +125 -0
- aiofortiosapi-0.1.0/README.md +95 -0
- aiofortiosapi-0.1.0/pyproject.toml +77 -0
- aiofortiosapi-0.1.0/src/aiofortiosapi/__init__.py +31 -0
- aiofortiosapi-0.1.0/src/aiofortiosapi/client.py +200 -0
- aiofortiosapi-0.1.0/src/aiofortiosapi/const.py +29 -0
- aiofortiosapi-0.1.0/src/aiofortiosapi/exceptions.py +35 -0
- aiofortiosapi-0.1.0/src/aiofortiosapi/models.py +192 -0
- aiofortiosapi-0.1.0/src/aiofortiosapi/py.typed +0 -0
- aiofortiosapi-0.1.0/tests/__init__.py +0 -0
- aiofortiosapi-0.1.0/tests/conftest.py +39 -0
- aiofortiosapi-0.1.0/tests/fixtures/detected_devices.json +31 -0
- aiofortiosapi-0.1.0/tests/fixtures/resource_usage.json +22 -0
- aiofortiosapi-0.1.0/tests/fixtures/system_status.json +22 -0
- aiofortiosapi-0.1.0/tests/test_auth.py +73 -0
- aiofortiosapi-0.1.0/tests/test_client.py +218 -0
- aiofortiosapi-0.1.0/tests/test_models.py +188 -0
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
lint:
|
|
10
|
+
name: Lint & type-check
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
steps:
|
|
13
|
+
- uses: actions/checkout@v4
|
|
14
|
+
- uses: actions/setup-python@v5
|
|
15
|
+
with:
|
|
16
|
+
python-version: "3.12"
|
|
17
|
+
- run: pip install ruff mypy aiohttp
|
|
18
|
+
- run: ruff check src tests
|
|
19
|
+
- run: ruff format --check src tests
|
|
20
|
+
- run: mypy src
|
|
21
|
+
|
|
22
|
+
test:
|
|
23
|
+
name: Tests (Python ${{ matrix.python-version }})
|
|
24
|
+
runs-on: ubuntu-latest
|
|
25
|
+
strategy:
|
|
26
|
+
matrix:
|
|
27
|
+
python-version: ["3.12", "3.13", "3.14"]
|
|
28
|
+
steps:
|
|
29
|
+
- uses: actions/checkout@v4
|
|
30
|
+
- uses: actions/setup-python@v5
|
|
31
|
+
with:
|
|
32
|
+
python-version: ${{ matrix.python-version }}
|
|
33
|
+
- run: pip install -e ".[test]"
|
|
34
|
+
- run: pytest
|
|
35
|
+
|
|
36
|
+
build:
|
|
37
|
+
name: Package build check
|
|
38
|
+
runs-on: ubuntu-latest
|
|
39
|
+
steps:
|
|
40
|
+
- uses: actions/checkout@v4
|
|
41
|
+
- uses: actions/setup-python@v5
|
|
42
|
+
with:
|
|
43
|
+
python-version: "3.12"
|
|
44
|
+
- run: pip install build twine
|
|
45
|
+
- run: python -m build
|
|
46
|
+
- run: twine check dist/*
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# BEFORE FIRST USE: configure a PyPI Trusted Publisher for this repo.
|
|
2
|
+
# Go to https://pypi.org/manage/account/publishing/ and add:
|
|
3
|
+
# owner/repo: kimfrellsen/aiofortiosapi
|
|
4
|
+
# workflow: release.yml
|
|
5
|
+
# environment: release
|
|
6
|
+
# No API token needs to be stored — OIDC handles auth.
|
|
7
|
+
|
|
8
|
+
name: Release
|
|
9
|
+
|
|
10
|
+
on:
|
|
11
|
+
push:
|
|
12
|
+
tags:
|
|
13
|
+
- "v*"
|
|
14
|
+
|
|
15
|
+
permissions:
|
|
16
|
+
id-token: write # required for OIDC trusted publishing
|
|
17
|
+
contents: read
|
|
18
|
+
|
|
19
|
+
jobs:
|
|
20
|
+
build-and-publish:
|
|
21
|
+
name: Build & publish to PyPI
|
|
22
|
+
runs-on: ubuntu-latest
|
|
23
|
+
environment: release
|
|
24
|
+
steps:
|
|
25
|
+
- uses: actions/checkout@v4
|
|
26
|
+
- uses: actions/setup-python@v5
|
|
27
|
+
with:
|
|
28
|
+
python-version: "3.12"
|
|
29
|
+
- run: pip install build
|
|
30
|
+
- run: python -m build
|
|
31
|
+
- uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*.pyo
|
|
5
|
+
*.pyd
|
|
6
|
+
*.so
|
|
7
|
+
*.egg
|
|
8
|
+
*.egg-info/
|
|
9
|
+
dist/
|
|
10
|
+
build/
|
|
11
|
+
.eggs/
|
|
12
|
+
wheels/
|
|
13
|
+
|
|
14
|
+
# Virtual environments
|
|
15
|
+
.venv/
|
|
16
|
+
venv/
|
|
17
|
+
env/
|
|
18
|
+
ENV/
|
|
19
|
+
|
|
20
|
+
# Testing / coverage
|
|
21
|
+
.pytest_cache/
|
|
22
|
+
.coverage
|
|
23
|
+
.coverage.*
|
|
24
|
+
htmlcov/
|
|
25
|
+
coverage.xml
|
|
26
|
+
*.cover
|
|
27
|
+
|
|
28
|
+
# Typing
|
|
29
|
+
.mypy_cache/
|
|
30
|
+
.dmypy.json
|
|
31
|
+
dmypy.json
|
|
32
|
+
|
|
33
|
+
# Editors
|
|
34
|
+
.vscode/
|
|
35
|
+
.idea/
|
|
36
|
+
*.swp
|
|
37
|
+
*.swo
|
|
38
|
+
*~
|
|
39
|
+
.DS_Store
|
|
40
|
+
|
|
41
|
+
# Packaging
|
|
42
|
+
MANIFEST
|
|
43
|
+
pip-log.txt
|
|
44
|
+
pip-delete-this-directory.txt
|
|
45
|
+
|
|
46
|
+
# Ruff
|
|
47
|
+
.ruff_cache/
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
|
|
5
|
+
This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
6
|
+
|
|
7
|
+
## [Unreleased]
|
|
8
|
+
|
|
9
|
+
## [0.1.0] - 2026-08-26
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
- Initial scaffold: `FortiOSClient` with Bearer token auth and injected `aiohttp.ClientSession`.
|
|
13
|
+
- `get_system_status()`, `get_resource_usage()`, `get_detected_devices()` endpoints.
|
|
14
|
+
- `async_validate()` for cheap credential validation in HA config_flow.
|
|
15
|
+
- `FortiOSClient.get(path, *, params=None)` — generic raw-envelope GET for
|
|
16
|
+
endpoints without a dedicated typed method (e.g. HA coordinator polling).
|
|
17
|
+
- Exception hierarchy: `FortiOSConnectionError`, `FortiOSAuthenticationError`,
|
|
18
|
+
`FortiOSNotFoundError`, `FortiOSResponseError`.
|
|
19
|
+
- Typed frozen dataclasses: `SystemStatus`, `ResourceUsage`, `DetectedDevice`.
|
|
20
|
+
- `verify_ssl` flag for self-signed FortiGate certificates.
|
|
21
|
+
- `vdom` parameter support.
|
|
22
|
+
- Full test suite using `aresponses` (no live network required).
|
|
23
|
+
- Ruff + mypy strict configuration.
|
|
24
|
+
- GitHub Actions CI (lint + test on Python 3.12/3.13/3.14) and OIDC-based PyPI release workflow.
|
|
25
|
+
|
|
26
|
+
### Changed
|
|
27
|
+
- `DetectedDevice.is_online` uses the API-reported `is_online` flag; when a
|
|
28
|
+
firmware omits the field it falls back to `last_seen` freshness (seen within
|
|
29
|
+
the new `device_online_threshold` client argument, default 300 s).
|
|
30
|
+
`DetectedDevice.list_from_api()` accepts keyword-only `now` and
|
|
31
|
+
`online_threshold` for deterministic parsing.
|
|
32
|
+
- `ResourceUsage` model matches real firmware: memory under `"mem"`/`"current"`,
|
|
33
|
+
`sessions` and `session_setup_rate` sum IPv4+IPv6 buckets; `uptime` was
|
|
34
|
+
dropped (not present on `monitor/system/resource/usage`).
|
|
35
|
+
|
|
36
|
+
### Fixed
|
|
37
|
+
- `DetectedDevice.ip` no longer becomes the string `"None"` when the API returns
|
|
38
|
+
a null `ipv4_address`; all string fields map null to `""`.
|
|
39
|
+
- Parsing no longer raises on scalar list entries (`_first`), null envelopes
|
|
40
|
+
(`"results": null`), or non-numeric stat values; safe defaults are used.
|
|
41
|
+
- Error messages for failed requests surface FortiOS detail keys (`cli_error`,
|
|
42
|
+
`message`, `error`, `http_message`) instead of an often-empty `error`,
|
|
43
|
+
falling back to the truncated raw body.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Kim <kim@frellsen.se>
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: aiofortiosapi
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Async FortiOS REST API client for Home Assistant
|
|
5
|
+
Project-URL: Homepage, https://github.com/kimfrellsen/aiofortiosapi
|
|
6
|
+
Project-URL: Repository, https://github.com/kimfrellsen/aiofortiosapi
|
|
7
|
+
Project-URL: Changelog, https://github.com/kimfrellsen/aiofortiosapi/blob/main/CHANGELOG.md
|
|
8
|
+
Project-URL: Issues, https://github.com/kimfrellsen/aiofortiosapi/issues
|
|
9
|
+
Author-email: Kim <kim@frellsen.se>
|
|
10
|
+
License-Expression: MIT
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
Keywords: api-client,asyncio,fortigate,fortinet,fortios,home-assistant
|
|
13
|
+
Classifier: Development Status :: 3 - Alpha
|
|
14
|
+
Classifier: Framework :: AsyncIO
|
|
15
|
+
Classifier: Intended Audience :: Developers
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
20
|
+
Classifier: Topic :: System :: Networking :: Monitoring
|
|
21
|
+
Classifier: Typing :: Typed
|
|
22
|
+
Requires-Python: >=3.12
|
|
23
|
+
Requires-Dist: aiohttp>=3.9
|
|
24
|
+
Provides-Extra: test
|
|
25
|
+
Requires-Dist: aresponses>=3; extra == 'test'
|
|
26
|
+
Requires-Dist: pytest-asyncio>=0.24; extra == 'test'
|
|
27
|
+
Requires-Dist: pytest-cov>=5; extra == 'test'
|
|
28
|
+
Requires-Dist: pytest>=8; extra == 'test'
|
|
29
|
+
Description-Content-Type: text/markdown
|
|
30
|
+
|
|
31
|
+
# aiofortiosapi
|
|
32
|
+
|
|
33
|
+
Async Python client for the FortiOS REST API, built for the [Home Assistant](https://www.home-assistant.io/) `fortios` integration.
|
|
34
|
+
|
|
35
|
+
> **Community project** — not affiliated with or supported by Fortinet TAC.
|
|
36
|
+
|
|
37
|
+
## Install
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
pip install aiofortiosapi
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Usage
|
|
44
|
+
|
|
45
|
+
The library requires an injected `aiohttp.ClientSession` — Home Assistant provides one via
|
|
46
|
+
`async_get_clientsession(hass)`. You own the session lifecycle; this library never creates or closes it.
|
|
47
|
+
|
|
48
|
+
```python
|
|
49
|
+
import asyncio
|
|
50
|
+
import aiohttp
|
|
51
|
+
from aiofortiosapi import FortiOSClient, FortiOSAuthenticationError, FortiOSConnectionError
|
|
52
|
+
|
|
53
|
+
async def main() -> None:
|
|
54
|
+
session = aiohttp.ClientSession()
|
|
55
|
+
try:
|
|
56
|
+
client = FortiOSClient(
|
|
57
|
+
host="192.168.1.1",
|
|
58
|
+
token="your-rest-api-token",
|
|
59
|
+
session=session,
|
|
60
|
+
verify_ssl=False, # set True in production with a valid cert
|
|
61
|
+
)
|
|
62
|
+
status = await client.get_system_status()
|
|
63
|
+
print(status.hostname, status.version)
|
|
64
|
+
|
|
65
|
+
usage = await client.get_resource_usage()
|
|
66
|
+
print(f"CPU {usage.cpu_percent}% MEM {usage.memory_percent}%")
|
|
67
|
+
|
|
68
|
+
devices = await client.get_detected_devices()
|
|
69
|
+
for d in devices:
|
|
70
|
+
print(d.mac, d.hostname, d.ip, "online" if d.is_online else "offline")
|
|
71
|
+
except FortiOSAuthenticationError:
|
|
72
|
+
print("Bad token — re-enter credentials")
|
|
73
|
+
except FortiOSConnectionError:
|
|
74
|
+
print("Cannot reach the FortiGate — check host/port")
|
|
75
|
+
finally:
|
|
76
|
+
await session.close()
|
|
77
|
+
|
|
78
|
+
asyncio.run(main())
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## Generating a FortiOS REST API token
|
|
82
|
+
|
|
83
|
+
1. In the FortiGate GUI go to **System → Administrators → Create New → REST API Admin**.
|
|
84
|
+
2. Set a **Trusted Host** (the IP of your Home Assistant instance) to restrict token use.
|
|
85
|
+
3. Assign a read-only profile (`prof_admin` or custom).
|
|
86
|
+
4. Copy the generated token — it is shown only once.
|
|
87
|
+
|
|
88
|
+
The library uses `Authorization: Bearer <token>` (not the legacy `?access_token=` query string).
|
|
89
|
+
|
|
90
|
+
### Device online state
|
|
91
|
+
|
|
92
|
+
`DetectedDevice.is_online` uses the flag reported by FortiOS. On firmware that
|
|
93
|
+
omits the field, it falls back to deriving online state from `last_seen`
|
|
94
|
+
freshness: a device counts as online when seen within
|
|
95
|
+
`DEFAULT_ONLINE_THRESHOLD` seconds (300). Tune the fallback per client:
|
|
96
|
+
|
|
97
|
+
```python
|
|
98
|
+
client = FortiOSClient(..., device_online_threshold=600)
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## Scope
|
|
102
|
+
|
|
103
|
+
`aiofortiosapi` is intentionally minimal:
|
|
104
|
+
|
|
105
|
+
- **Three typed monitor endpoints** (`get_system_status`, `get_resource_usage`,
|
|
106
|
+
`get_detected_devices`) used by the Home Assistant integration.
|
|
107
|
+
- A generic `get(path)` for any other endpoint that returns the raw JSON envelope.
|
|
108
|
+
- **No** config-write, CMDB, file upload, SSH fallback, or CLI helpers.
|
|
109
|
+
- **No** session/cookie login flow — Bearer token only.
|
|
110
|
+
|
|
111
|
+
This keeps the dependency tree small (runtime dep: `aiohttp` only) and passes HA integration
|
|
112
|
+
quality review requirements.
|
|
113
|
+
|
|
114
|
+
## Exception hierarchy
|
|
115
|
+
|
|
116
|
+
| Exception | When raised | HA mapping |
|
|
117
|
+
|---|---|---|
|
|
118
|
+
| `FortiOSConnectionError` | Transport/timeout failure | `ConfigEntryNotReady` |
|
|
119
|
+
| `FortiOSAuthenticationError` | HTTP 401 / 403 | `ConfigEntryAuthFailed` |
|
|
120
|
+
| `FortiOSNotFoundError` | HTTP 404 | log / inspect |
|
|
121
|
+
| `FortiOSResponseError` | Bad JSON, 5xx, other 4xx | log / raise |
|
|
122
|
+
|
|
123
|
+
## License
|
|
124
|
+
|
|
125
|
+
MIT
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# aiofortiosapi
|
|
2
|
+
|
|
3
|
+
Async Python client for the FortiOS REST API, built for the [Home Assistant](https://www.home-assistant.io/) `fortios` integration.
|
|
4
|
+
|
|
5
|
+
> **Community project** — not affiliated with or supported by Fortinet TAC.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
pip install aiofortiosapi
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Usage
|
|
14
|
+
|
|
15
|
+
The library requires an injected `aiohttp.ClientSession` — Home Assistant provides one via
|
|
16
|
+
`async_get_clientsession(hass)`. You own the session lifecycle; this library never creates or closes it.
|
|
17
|
+
|
|
18
|
+
```python
|
|
19
|
+
import asyncio
|
|
20
|
+
import aiohttp
|
|
21
|
+
from aiofortiosapi import FortiOSClient, FortiOSAuthenticationError, FortiOSConnectionError
|
|
22
|
+
|
|
23
|
+
async def main() -> None:
|
|
24
|
+
session = aiohttp.ClientSession()
|
|
25
|
+
try:
|
|
26
|
+
client = FortiOSClient(
|
|
27
|
+
host="192.168.1.1",
|
|
28
|
+
token="your-rest-api-token",
|
|
29
|
+
session=session,
|
|
30
|
+
verify_ssl=False, # set True in production with a valid cert
|
|
31
|
+
)
|
|
32
|
+
status = await client.get_system_status()
|
|
33
|
+
print(status.hostname, status.version)
|
|
34
|
+
|
|
35
|
+
usage = await client.get_resource_usage()
|
|
36
|
+
print(f"CPU {usage.cpu_percent}% MEM {usage.memory_percent}%")
|
|
37
|
+
|
|
38
|
+
devices = await client.get_detected_devices()
|
|
39
|
+
for d in devices:
|
|
40
|
+
print(d.mac, d.hostname, d.ip, "online" if d.is_online else "offline")
|
|
41
|
+
except FortiOSAuthenticationError:
|
|
42
|
+
print("Bad token — re-enter credentials")
|
|
43
|
+
except FortiOSConnectionError:
|
|
44
|
+
print("Cannot reach the FortiGate — check host/port")
|
|
45
|
+
finally:
|
|
46
|
+
await session.close()
|
|
47
|
+
|
|
48
|
+
asyncio.run(main())
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Generating a FortiOS REST API token
|
|
52
|
+
|
|
53
|
+
1. In the FortiGate GUI go to **System → Administrators → Create New → REST API Admin**.
|
|
54
|
+
2. Set a **Trusted Host** (the IP of your Home Assistant instance) to restrict token use.
|
|
55
|
+
3. Assign a read-only profile (`prof_admin` or custom).
|
|
56
|
+
4. Copy the generated token — it is shown only once.
|
|
57
|
+
|
|
58
|
+
The library uses `Authorization: Bearer <token>` (not the legacy `?access_token=` query string).
|
|
59
|
+
|
|
60
|
+
### Device online state
|
|
61
|
+
|
|
62
|
+
`DetectedDevice.is_online` uses the flag reported by FortiOS. On firmware that
|
|
63
|
+
omits the field, it falls back to deriving online state from `last_seen`
|
|
64
|
+
freshness: a device counts as online when seen within
|
|
65
|
+
`DEFAULT_ONLINE_THRESHOLD` seconds (300). Tune the fallback per client:
|
|
66
|
+
|
|
67
|
+
```python
|
|
68
|
+
client = FortiOSClient(..., device_online_threshold=600)
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## Scope
|
|
72
|
+
|
|
73
|
+
`aiofortiosapi` is intentionally minimal:
|
|
74
|
+
|
|
75
|
+
- **Three typed monitor endpoints** (`get_system_status`, `get_resource_usage`,
|
|
76
|
+
`get_detected_devices`) used by the Home Assistant integration.
|
|
77
|
+
- A generic `get(path)` for any other endpoint that returns the raw JSON envelope.
|
|
78
|
+
- **No** config-write, CMDB, file upload, SSH fallback, or CLI helpers.
|
|
79
|
+
- **No** session/cookie login flow — Bearer token only.
|
|
80
|
+
|
|
81
|
+
This keeps the dependency tree small (runtime dep: `aiohttp` only) and passes HA integration
|
|
82
|
+
quality review requirements.
|
|
83
|
+
|
|
84
|
+
## Exception hierarchy
|
|
85
|
+
|
|
86
|
+
| Exception | When raised | HA mapping |
|
|
87
|
+
|---|---|---|
|
|
88
|
+
| `FortiOSConnectionError` | Transport/timeout failure | `ConfigEntryNotReady` |
|
|
89
|
+
| `FortiOSAuthenticationError` | HTTP 401 / 403 | `ConfigEntryAuthFailed` |
|
|
90
|
+
| `FortiOSNotFoundError` | HTTP 404 | log / inspect |
|
|
91
|
+
| `FortiOSResponseError` | Bad JSON, 5xx, other 4xx | log / raise |
|
|
92
|
+
|
|
93
|
+
## License
|
|
94
|
+
|
|
95
|
+
MIT
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "aiofortiosapi"
|
|
7
|
+
dynamic = ["version"]
|
|
8
|
+
description = "Async FortiOS REST API client for Home Assistant"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = "MIT"
|
|
11
|
+
license-files = ["LICENSE"]
|
|
12
|
+
authors = [{ name = "Kim", email = "kim@frellsen.se" }]
|
|
13
|
+
requires-python = ">=3.12"
|
|
14
|
+
dependencies = ["aiohttp>=3.9"]
|
|
15
|
+
keywords = ["fortios", "fortigate", "fortinet", "home-assistant", "asyncio", "api-client"]
|
|
16
|
+
classifiers = [
|
|
17
|
+
"Development Status :: 3 - Alpha",
|
|
18
|
+
"Intended Audience :: Developers",
|
|
19
|
+
"Programming Language :: Python :: 3",
|
|
20
|
+
"Programming Language :: Python :: 3.12",
|
|
21
|
+
"Programming Language :: Python :: 3.13",
|
|
22
|
+
"Programming Language :: Python :: 3.14",
|
|
23
|
+
"Topic :: System :: Networking :: Monitoring",
|
|
24
|
+
"Framework :: AsyncIO",
|
|
25
|
+
"Typing :: Typed",
|
|
26
|
+
]
|
|
27
|
+
|
|
28
|
+
[project.urls]
|
|
29
|
+
Homepage = "https://github.com/kimfrellsen/aiofortiosapi"
|
|
30
|
+
Repository = "https://github.com/kimfrellsen/aiofortiosapi"
|
|
31
|
+
Changelog = "https://github.com/kimfrellsen/aiofortiosapi/blob/main/CHANGELOG.md"
|
|
32
|
+
Issues = "https://github.com/kimfrellsen/aiofortiosapi/issues"
|
|
33
|
+
|
|
34
|
+
[project.optional-dependencies]
|
|
35
|
+
test = [
|
|
36
|
+
"pytest>=8",
|
|
37
|
+
"pytest-asyncio>=0.24",
|
|
38
|
+
"aresponses>=3",
|
|
39
|
+
"pytest-cov>=5",
|
|
40
|
+
]
|
|
41
|
+
|
|
42
|
+
[tool.hatch.version]
|
|
43
|
+
path = "src/aiofortiosapi/__init__.py"
|
|
44
|
+
|
|
45
|
+
[tool.hatch.build.targets.wheel]
|
|
46
|
+
packages = ["src/aiofortiosapi"]
|
|
47
|
+
|
|
48
|
+
# ---------------------------------------------------------------------------
|
|
49
|
+
# pytest
|
|
50
|
+
# ---------------------------------------------------------------------------
|
|
51
|
+
[tool.pytest.ini_options]
|
|
52
|
+
asyncio_mode = "auto"
|
|
53
|
+
asyncio_default_fixture_loop_scope = "function"
|
|
54
|
+
testpaths = ["tests"]
|
|
55
|
+
addopts = "--cov=src/aiofortiosapi --cov-report=term-missing"
|
|
56
|
+
|
|
57
|
+
# ---------------------------------------------------------------------------
|
|
58
|
+
# ruff
|
|
59
|
+
# ---------------------------------------------------------------------------
|
|
60
|
+
[tool.ruff]
|
|
61
|
+
line-length = 99
|
|
62
|
+
target-version = "py312"
|
|
63
|
+
|
|
64
|
+
[tool.ruff.lint]
|
|
65
|
+
select = ["E", "F", "I", "UP", "B", "ASYNC", "SIM"]
|
|
66
|
+
ignore = ["SIM102"] # nested if acceptable in parse code
|
|
67
|
+
|
|
68
|
+
[tool.ruff.lint.isort]
|
|
69
|
+
known-first-party = ["aiofortiosapi"]
|
|
70
|
+
|
|
71
|
+
# ---------------------------------------------------------------------------
|
|
72
|
+
# mypy
|
|
73
|
+
# ---------------------------------------------------------------------------
|
|
74
|
+
[tool.mypy]
|
|
75
|
+
python_version = "3.12"
|
|
76
|
+
strict = true
|
|
77
|
+
files = ["src"]
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"""aiofortiosapi — async FortiOS REST API client for Home Assistant."""
|
|
2
|
+
|
|
3
|
+
from .client import FortiOSClient
|
|
4
|
+
from .const import DEFAULT_ONLINE_THRESHOLD
|
|
5
|
+
from .exceptions import (
|
|
6
|
+
FortiOSAuthenticationError,
|
|
7
|
+
FortiOSConnectionError,
|
|
8
|
+
FortiOSError,
|
|
9
|
+
FortiOSNotFoundError,
|
|
10
|
+
FortiOSResponseError,
|
|
11
|
+
)
|
|
12
|
+
from .models import DetectedDevice, ResourceUsage, SystemStatus
|
|
13
|
+
|
|
14
|
+
__version__ = "0.1.0"
|
|
15
|
+
|
|
16
|
+
__all__ = [
|
|
17
|
+
"FortiOSClient",
|
|
18
|
+
# exceptions
|
|
19
|
+
"FortiOSError",
|
|
20
|
+
"FortiOSConnectionError",
|
|
21
|
+
"FortiOSAuthenticationError",
|
|
22
|
+
"FortiOSNotFoundError",
|
|
23
|
+
"FortiOSResponseError",
|
|
24
|
+
# models
|
|
25
|
+
"SystemStatus",
|
|
26
|
+
"ResourceUsage",
|
|
27
|
+
"DetectedDevice",
|
|
28
|
+
# constants
|
|
29
|
+
"DEFAULT_ONLINE_THRESHOLD",
|
|
30
|
+
"__version__",
|
|
31
|
+
]
|