pydmvl 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.
Files changed (37) hide show
  1. pydmvl-0.1.0/.github/pull_request_template.md +18 -0
  2. pydmvl-0.1.0/.github/workflows/ci.yml +51 -0
  3. pydmvl-0.1.0/.github/workflows/publish.yml +46 -0
  4. pydmvl-0.1.0/.github/workflows/testpypi.yml +47 -0
  5. pydmvl-0.1.0/.gitignore +26 -0
  6. pydmvl-0.1.0/AGENTS.md +147 -0
  7. pydmvl-0.1.0/LICENSE +21 -0
  8. pydmvl-0.1.0/PKG-INFO +149 -0
  9. pydmvl-0.1.0/README.md +116 -0
  10. pydmvl-0.1.0/pyproject.toml +74 -0
  11. pydmvl-0.1.0/specs/0001-auth.md +113 -0
  12. pydmvl-0.1.0/specs/0002-documents.md +121 -0
  13. pydmvl-0.1.0/specs/0003-payments.md +73 -0
  14. pydmvl-0.1.0/specs/0004-client-api.md +96 -0
  15. pydmvl-0.1.0/specs/0005-api-surface.md +95 -0
  16. pydmvl-0.1.0/specs/0006-counters-read.md +83 -0
  17. pydmvl-0.1.0/src/pydmvl/__init__.py +38 -0
  18. pydmvl-0.1.0/src/pydmvl/_api.py +64 -0
  19. pydmvl-0.1.0/src/pydmvl/_logging.py +55 -0
  20. pydmvl-0.1.0/src/pydmvl/aclient.py +81 -0
  21. pydmvl-0.1.0/src/pydmvl/auth.py +32 -0
  22. pydmvl-0.1.0/src/pydmvl/client.py +82 -0
  23. pydmvl-0.1.0/src/pydmvl/errors.py +22 -0
  24. pydmvl-0.1.0/src/pydmvl/models.py +228 -0
  25. pydmvl-0.1.0/src/pydmvl/py.typed +0 -0
  26. pydmvl-0.1.0/tests/conftest.py +49 -0
  27. pydmvl-0.1.0/tests/fixtures/authentication.json +74 -0
  28. pydmvl-0.1.0/tests/fixtures/authentication_error.json +4 -0
  29. pydmvl-0.1.0/tests/test_async.py +34 -0
  30. pydmvl-0.1.0/tests/test_auth.py +120 -0
  31. pydmvl-0.1.0/tests/test_client.py +57 -0
  32. pydmvl-0.1.0/tests/test_documents.py +97 -0
  33. pydmvl-0.1.0/tests/test_live.py +29 -0
  34. pydmvl-0.1.0/tests/test_logging.py +41 -0
  35. pydmvl-0.1.0/tests/test_package.py +50 -0
  36. pydmvl-0.1.0/tests/test_payments.py +83 -0
  37. pydmvl-0.1.0/tests/test_transport.py +66 -0
@@ -0,0 +1,18 @@
1
+ ## Summary
2
+
3
+ <!-- What does this PR change? Link the feature spec: specs/NNNN-slug.md -->
4
+
5
+ ## Spec-driven checklist
6
+
7
+ - [ ] Feature spec exists (`specs/NNNN-slug.md`) and has status `approved`
8
+ - [ ] Tests written before implementation (TDD), failing first
9
+ - [ ] API responses covered by synthetic fixtures (no live API in unit tests)
10
+ - [ ] Live tests stay behind the `live` marker
11
+ - [ ] `ruff check .`, `ruff format --check .`, `mypy`, `pytest -m "not live"` pass
12
+ - [ ] Skeptic review completed: verdict `APPROVED` (or `NITS` only)
13
+ - [ ] No secrets committed (credentials, password hashes); placeholders only
14
+ - [ ] Logs never contain credentials or the password hash
15
+
16
+ ## Commit style
17
+
18
+ Conventional Commits (`feat:`, `fix:`, `docs:`, `test:`, `chore:`, `refactor:`).
@@ -0,0 +1,51 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [master]
6
+ pull_request:
7
+
8
+ concurrency:
9
+ group: ${{ github.workflow }}-${{ github.ref }}
10
+ cancel-in-progress: true
11
+
12
+ jobs:
13
+ test:
14
+ runs-on: ubuntu-latest
15
+ strategy:
16
+ fail-fast: false
17
+ matrix:
18
+ python-version: ["3.11", "3.12", "3.13"]
19
+ steps:
20
+ - uses: actions/checkout@v4
21
+ - uses: actions/setup-python@v5
22
+ with:
23
+ python-version: ${{ matrix.python-version }}
24
+ - name: Install
25
+ run: |
26
+ python -m pip install --upgrade pip
27
+ pip install -e ".[dev]"
28
+ - name: Ruff lint
29
+ run: ruff check .
30
+ - name: Ruff format
31
+ run: ruff format --check .
32
+ - name: Mypy
33
+ run: mypy
34
+ - name: Tests
35
+ run: pytest -m "not live"
36
+
37
+ build:
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
+ - name: Install
45
+ run: |
46
+ python -m pip install --upgrade pip
47
+ pip install -e ".[release]"
48
+ - name: Build
49
+ run: python -m build
50
+ - name: Twine check
51
+ run: twine check dist/*
@@ -0,0 +1,46 @@
1
+ # Publishes to PyPI via Trusted Publishing (OIDC) when a GitHub Release is published.
2
+ name: Publish
3
+
4
+ on:
5
+ release:
6
+ types: [published]
7
+
8
+ permissions:
9
+ contents: read
10
+
11
+ jobs:
12
+ build:
13
+ runs-on: ubuntu-latest
14
+ steps:
15
+ - uses: actions/checkout@v4
16
+ - uses: actions/setup-python@v5
17
+ with:
18
+ python-version: "3.12"
19
+ - name: Install
20
+ run: |
21
+ python -m pip install --upgrade pip
22
+ pip install -U "build>=1.2" "twine>=5"
23
+ - name: Build
24
+ run: python -m build
25
+ - name: Twine check
26
+ run: twine check dist/*
27
+ - name: Upload artifacts
28
+ uses: actions/upload-artifact@v4
29
+ with:
30
+ name: dist
31
+ path: dist/
32
+
33
+ publish:
34
+ needs: build
35
+ runs-on: ubuntu-latest
36
+ environment: pypi
37
+ permissions:
38
+ id-token: write
39
+ steps:
40
+ - name: Download artifacts
41
+ uses: actions/download-artifact@v4
42
+ with:
43
+ name: dist
44
+ path: dist/
45
+ - name: Publish to PyPI
46
+ uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,47 @@
1
+ # Publishes to TestPyPI via Trusted Publishing (OIDC); manual dry run before a release.
2
+ name: TestPyPI
3
+
4
+ on:
5
+ workflow_dispatch:
6
+
7
+ permissions:
8
+ contents: read
9
+
10
+ jobs:
11
+ build:
12
+ runs-on: ubuntu-latest
13
+ steps:
14
+ - uses: actions/checkout@v4
15
+ - uses: actions/setup-python@v5
16
+ with:
17
+ python-version: "3.12"
18
+ - name: Install
19
+ run: |
20
+ python -m pip install --upgrade pip
21
+ pip install -U "build>=1.2" "twine>=5"
22
+ - name: Build
23
+ run: python -m build
24
+ - name: Twine check
25
+ run: twine check dist/*
26
+ - name: Upload artifacts
27
+ uses: actions/upload-artifact@v4
28
+ with:
29
+ name: dist
30
+ path: dist/
31
+
32
+ publish:
33
+ needs: build
34
+ runs-on: ubuntu-latest
35
+ environment: testpypi
36
+ permissions:
37
+ id-token: write
38
+ steps:
39
+ - name: Download artifacts
40
+ uses: actions/download-artifact@v4
41
+ with:
42
+ name: dist
43
+ path: dist/
44
+ - name: Publish to TestPyPI
45
+ uses: pypa/gh-action-pypi-publish@release/v1
46
+ with:
47
+ repository-url: https://test.pypi.org/legacy/
@@ -0,0 +1,26 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *.egg-info/
5
+ dist/
6
+ build/
7
+
8
+ # Environments
9
+ .venv/
10
+ venv/
11
+
12
+ # Tooling caches
13
+ .mypy_cache/
14
+ .pytest_cache/
15
+ .ruff_cache/
16
+ .coverage
17
+ coverage.xml
18
+ htmlcov/
19
+
20
+ # Local secrets (never commit)
21
+ *.local.json
22
+
23
+ # Editors / OS
24
+ .DS_Store
25
+ .idea/
26
+ .vscode/
pydmvl-0.1.0/AGENTS.md ADDED
@@ -0,0 +1,147 @@
1
+ # AGENTS.md — pydmvl
2
+
3
+ Working agreement for humans and AI agents contributing to this repository.
4
+
5
+ ## 1. Role in the group
6
+
7
+ This repository is part of a group of projects that build a self-hosted
8
+ control stack for a residential utility account ("Domovladelets" / homeowner):
9
+
10
+ | Repository | Role | Visibility | Language |
11
+ |---|---|---|---|
12
+ | `pydmvl` (this repo) | Python client for a homeowner account API | public | English |
13
+ | `dmvl-ha-integration` | Home Assistant custom integration, consumes `pydmvl` from PyPI | public | English |
14
+
15
+ `pydmvl` is the producer: it encapsulates authentication and the account data
16
+ models. The Home Assistant integration depends on `pydmvl` as an external
17
+ package, does not duplicate client logic, and performs no authentication of its
18
+ own. Group identity: code name `dmvl`, package/import `pydmvl`, Home Assistant
19
+ domain `dmvl`.
20
+
21
+ ## 2. Language
22
+
23
+ All repository text is English: code, comments, docstrings, documentation,
24
+ commit messages, and review notes. The only exceptions are a short bilingual
25
+ intro and disclaimer in this repository's `README.md` (the app audience is
26
+ Russian-speaking) and runtime translation of user-facing strings (e.g.
27
+ `translations/ru.json`) in the consumer integration, not in this library.
28
+
29
+ ## 3. Stack and commands
30
+
31
+ - Python >= 3.11, hatchling, src-layout (`src/pydmvl/`), plain top-level
32
+ package (no PEP 420 namespace).
33
+ - Runtime dependency: `httpx>=0.27`; dev tools: pytest, pytest-asyncio, ruff,
34
+ mypy (strict for `src/`).
35
+
36
+ ```bash
37
+ python3 -m venv .venv && .venv/bin/pip install -e ".[dev]"
38
+ .venv/bin/ruff check .
39
+ .venv/bin/ruff format --check .
40
+ .venv/bin/mypy
41
+ .venv/bin/pytest -m "not live"
42
+ ```
43
+
44
+ Live tests (real account, real credentials) carry the `live` marker and are run
45
+ manually only: `.venv/bin/pytest -m live`. Credentials come from the
46
+ environment: `DMVL_USERNAME`, `DMVL_PASSWORD`.
47
+
48
+ ## 4. Spec-driven development (SDD)
49
+
50
+ - Every feature starts with a spec in `specs/NNNN-slug.md` (zero-padded number,
51
+ short slug). Status lifecycle: `draft → approved → implemented →
52
+ superseded`.
53
+ - Implementation without an `approved` spec is forbidden. Specs marked
54
+ "implementation pending research" must not be implemented until they move to
55
+ `approved`.
56
+ - Spec template: Summary / Motivation / Requirements (MUST/SHOULD) / Design /
57
+ API / Test plan / Acceptance criteria / Out of scope / Status.
58
+ - Moving a spec from `draft` to `approved` is a reviewable change (PR or a
59
+ recorded decision in the conversation).
60
+
61
+ ## 5. Test-driven development (TDD)
62
+
63
+ - Tests are written first and must fail before the implementation exists.
64
+ - API responses are covered by synthetic fixtures via an httpx mock transport;
65
+ unit tests never touch the real API.
66
+ - A merge requires a fully green run of all gate commands (§3).
67
+
68
+ ## 6. Git process
69
+
70
+ - Default branch: `master`. Direct commits to `master` are forbidden (the
71
+ initial scaffold import is the only exception).
72
+ - One feature = one branch `feat/NNNN-slug` containing the spec, the tests, and
73
+ the implementation together.
74
+ - Commit messages follow Conventional Commits (`feat:`, `fix:`, `docs:`,
75
+ `test:`, `chore:`, `refactor:`).
76
+ - Merge into `master` only after the review gate (§7), squash-merge, then delete
77
+ the feature branch.
78
+
79
+ ## 7. Review gate (mandatory)
80
+
81
+ A feature branch may merge into `master` only when both hold:
82
+
83
+ 1. A full local run is green (§3/§5).
84
+ 2. A skeptic review returns no `BLOCKING` findings. Invoke the skeptic agent
85
+ (Task tool, definition in `.kilo/agent/skeptic.md`) with a prompt such as:
86
+
87
+ > Review branch `feat/NNNN-slug` against its spec `specs/NNNN-slug.md`
88
+ > (diff base: `master`). Follow the checklist in `.kilo/agent/skeptic.md`
89
+ > and answer in the verdict format (`BLOCKING: ...` / `NITS: ...` /
90
+ > `APPROVED`).
91
+
92
+ `BLOCKING` findings forbid the merge; fix and re-review.
93
+
94
+ ## 8. Secrets and safety
95
+
96
+ - Account credentials and account data are confidential: never include them in
97
+ this public repository — in code, docs, examples, fixtures, or commit
98
+ history. This covers logins, passwords, tokens (including the password hash
99
+ sent by the API), full names, addresses, personal account numbers, object and
100
+ payment identifiers, and receipt links. Use synthetic placeholders
101
+ (`<account>`, `<password>`); real values live only in environment variables
102
+ or gitignored `*.local.json` files.
103
+ - Authentication material is sent as request query parameters (an observed
104
+ property of the API). Never log request URLs, credentials, or the password
105
+ hash. The library installs a redaction filter on the `httpx` logger so
106
+ dependency-emitted request-URL records have `login` and `hash` replaced; do
107
+ not remove it.
108
+ - TLS verification defaults to `False` (`DEFAULT_VERIFY`) because the service
109
+ serves an incomplete certificate chain; the `verify` argument stays
110
+ overridable and the rationale is documented in the README and spec 0004 R8.
111
+ Do not remove the argument or change the default without updating both.
112
+
113
+ ## 9. Publication policy (public repository)
114
+
115
+ - Do not copy text or material from non-public sources into this repo.
116
+ - Public documentation is an English description of observed API behavior.
117
+ Cite only this repository's own specs; do not name non-public or third-party
118
+ sources, and do not state or claim how the API was determined.
119
+ - Keep the disclaimers in place (unofficial, not affiliated with the service
120
+ operator, own account only).
121
+
122
+ ## 10. Release runbook (new versions)
123
+
124
+ Ship a release only from a green `master`:
125
+
126
+ 1. Bump the version in one change: `pyproject.toml` `[project].version` and
127
+ `src/pydmvl/__init__.py` `__version__`. A test enforces that they match; no
128
+ other source or test file pins the version. SemVer; `0.x` while the API is
129
+ unstable.
130
+ 2. Feature branch `feat/NNNN-slug` (spec + tests + code **and the version
131
+ bump**), gate (§3), skeptic (§7), squash-merge into `master`.
132
+ 3. Push `master`.
133
+ 4. Create a GitHub Release with tag `vX.Y.Z` equal to the version. Publishing
134
+ the release triggers `publish.yml`, which builds and uploads to PyPI via
135
+ Trusted Publishing. A plain tag push does **not** publish.
136
+ 5. Run the `testpypi.yml` dry run for every packaging/metadata change, and
137
+ always before the first production release.
138
+ 6. Never reuse a published version; if a release is wrong, bump the patch
139
+ version and repeat. Verify with `pip install pydmvl==X.Y.Z`.
140
+ 7. Keep the runtime dependency floor compatible with Home Assistant's pinned
141
+ `httpx`.
142
+
143
+ ## 11. References
144
+
145
+ - Specs: `specs/` (0001 authentication is the first deliverable).
146
+ - Public API surface catalogue: `specs/0005-api-surface.md`.
147
+ - Versioning: SemVer, `0.x` while the API is unstable.
pydmvl-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 The pydmvl contributors
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.
pydmvl-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,149 @@
1
+ Metadata-Version: 2.5
2
+ Name: pydmvl
3
+ Version: 0.1.0
4
+ Summary: Unofficial Python client for the Domovladelets (homeowner) account API
5
+ Project-URL: Homepage, https://github.com/buggy-shep/pydmvl
6
+ Project-URL: Repository, https://github.com/buggy-shep/pydmvl
7
+ Project-URL: Issues, https://github.com/buggy-shep/pydmvl/issues
8
+ Project-URL: Changelog, https://github.com/buggy-shep/pydmvl/releases
9
+ Author: The pydmvl contributors
10
+ License-Expression: MIT
11
+ License-File: LICENSE
12
+ Keywords: domovladelets,home-automation,homeowner,utility-billing
13
+ Classifier: Development Status :: 3 - Alpha
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: Operating System :: OS Independent
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Programming Language :: Python :: 3.13
20
+ Classifier: Topic :: Home Automation
21
+ Classifier: Typing :: Typed
22
+ Requires-Python: >=3.11
23
+ Requires-Dist: httpx>=0.27
24
+ Provides-Extra: dev
25
+ Requires-Dist: mypy>=1.11; extra == 'dev'
26
+ Requires-Dist: pytest-asyncio>=0.24; extra == 'dev'
27
+ Requires-Dist: pytest>=8.2; extra == 'dev'
28
+ Requires-Dist: ruff>=0.6; extra == 'dev'
29
+ Provides-Extra: release
30
+ Requires-Dist: build>=1.2; extra == 'release'
31
+ Requires-Dist: twine>=5; extra == 'release'
32
+ Description-Content-Type: text/markdown
33
+
34
+ # pydmvl
35
+
36
+ [![PyPI version](https://img.shields.io/pypi/v/pydmvl.svg)](https://pypi.org/project/pydmvl/)
37
+ [![CI](https://github.com/buggy-shep/pydmvl/actions/workflows/ci.yml/badge.svg)](https://github.com/buggy-shep/pydmvl/actions/workflows/ci.yml)
38
+
39
+ Unofficial Python client for the **"Domovladelets+"** ("Домовладелец+",
40
+ homeowner) account API. It implements the protocol used by the app
41
+ ([Google Play](https://play.google.com/store/apps/details?id=com.homeowner)):
42
+ it authenticates with an account login and password and exposes the account
43
+ snapshot the service returns for its home screen: account aggregates,
44
+ per-period charges (documents), receipt links, and payment history.
45
+
46
+ Неофициальный Python-клиент API лицевого счёта приложения **«Домовладелец+»**.
47
+ Реализует протокол этого приложения
48
+ ([Google Play](https://play.google.com/store/apps/details?id=com.homeowner)):
49
+ аутентифицируется по логину и паролю лицевого счёта и предоставляет снимок
50
+ счёта, который сервис возвращает для главного экрана: агрегаты по счёту,
51
+ начисления за период (документы), ссылки на квитанции и историю платежей.
52
+
53
+ > **Disclaimer.** This project is unofficial and is not affiliated with,
54
+ > endorsed by, or sponsored by the "Domovladelets+" application or its
55
+ > operators. It is built for interoperability with your own account. Use it at
56
+ > your own risk; only access accounts you are authorized to access.
57
+
58
+ > **Отказ от ответственности.** Проект неофициальный и не связан с
59
+ > приложением «Домовладелец+» или его операторами, не одобрен и не
60
+ > спонсируется ими. Он создан для взаимодействия с вашим собственным лицевым
61
+ > счётом. Используйте его на свой риск; получайте доступ только к тем счетам,
62
+ > на которые у вас есть разрешение.
63
+
64
+ ## Install
65
+
66
+ ```bash
67
+ pip install pydmvl
68
+ ```
69
+
70
+ ## Usage
71
+
72
+ ```python
73
+ from pydmvl import DmvlClient
74
+
75
+ with DmvlClient() as client:
76
+ session = client.login("user", "secret")
77
+ print(session.personal_account.amount_due)
78
+ ```
79
+
80
+ ## TLS verification (disabled by default)
81
+
82
+ The service presents an **incomplete certificate chain** (it does not serve the
83
+ intermediate CA), so standard verification fails against the real endpoint with
84
+ `certificate verify failed: unable to get local issuer certificate`. The
85
+ official client disables verification for this reason, and `pydmvl` matches
86
+ that observed behavior: `verify` defaults to `False`.
87
+
88
+ This is a deliberate, documented default, not a silent downgrade. Whenever you
89
+ can, turn verification back on — pass a CA bundle that includes the missing
90
+ intermediate, or `verify=True` if your trust store already chains the
91
+ certificate:
92
+
93
+ ```python
94
+ DmvlClient(verify="/path/to/ca-bundle.pem")
95
+ ```
96
+
97
+ Consumers that expose TLS settings to end users should present this as an
98
+ explicit opt-in control. See [spec 0004](specs/0004-client-api.md) R8.
99
+
100
+ ## Status
101
+
102
+ Authentication, the account snapshot, documents (charges, receipts, unpaid
103
+ detection), and payment history are implemented (specs 0001–0004); `0.x` — the
104
+ API may still change. See [`specs/`](specs/) for the specifications and their
105
+ status.
106
+
107
+ Capabilities:
108
+
109
+ - Login with `login` + `hash` (MD5 of the password); stateless session, no
110
+ bearer token — [spec 0001](specs/0001-auth.md)
111
+ - Account snapshot with debt/charge/payment aggregates —
112
+ [spec 0002](specs/0002-documents.md)
113
+ - Per-period charges and receipt links — [spec 0002](specs/0002-documents.md)
114
+ - Payment history and the latest payment — [spec 0003](specs/0003-payments.md)
115
+ - Public sync + async client API — [spec 0004](specs/0004-client-api.md)
116
+ - Configurable TLS verification (default off; see below) — [spec 0004](specs/0004-client-api.md) R8
117
+
118
+ ### Known API surface
119
+
120
+ The service exposes a single PHP `action` router. The catalogue of known
121
+ actions is [spec 0005](specs/0005-api-surface.md); only the read-only subset
122
+ needed for the account snapshot is implemented here — writing actions
123
+ (submitting meter readings, creating payments, opening doors, sending
124
+ messages, and similar) are out of scope.
125
+
126
+ ## Requirements
127
+
128
+ - Python >= 3.11
129
+ - [httpx](https://pypi.org/project/httpx/) >= 0.27
130
+
131
+ ## Development
132
+
133
+ ```bash
134
+ python3 -m venv .venv
135
+ .venv/bin/pip install -e ".[dev]"
136
+ .venv/bin/ruff check .
137
+ .venv/bin/ruff format --check .
138
+ .venv/bin/mypy
139
+ .venv/bin/pytest -m "not live"
140
+ ```
141
+
142
+ Live tests against the real API stay behind the `live` marker and are run
143
+ manually only, with credentials from the environment (`DMVL_USERNAME`,
144
+ `DMVL_PASSWORD`). Account credentials are sent as request query parameters, so
145
+ do not enable request-URL logging while a live client is in use.
146
+
147
+ ## License
148
+
149
+ [MIT](LICENSE)
pydmvl-0.1.0/README.md ADDED
@@ -0,0 +1,116 @@
1
+ # pydmvl
2
+
3
+ [![PyPI version](https://img.shields.io/pypi/v/pydmvl.svg)](https://pypi.org/project/pydmvl/)
4
+ [![CI](https://github.com/buggy-shep/pydmvl/actions/workflows/ci.yml/badge.svg)](https://github.com/buggy-shep/pydmvl/actions/workflows/ci.yml)
5
+
6
+ Unofficial Python client for the **"Domovladelets+"** ("Домовладелец+",
7
+ homeowner) account API. It implements the protocol used by the app
8
+ ([Google Play](https://play.google.com/store/apps/details?id=com.homeowner)):
9
+ it authenticates with an account login and password and exposes the account
10
+ snapshot the service returns for its home screen: account aggregates,
11
+ per-period charges (documents), receipt links, and payment history.
12
+
13
+ Неофициальный Python-клиент API лицевого счёта приложения **«Домовладелец+»**.
14
+ Реализует протокол этого приложения
15
+ ([Google Play](https://play.google.com/store/apps/details?id=com.homeowner)):
16
+ аутентифицируется по логину и паролю лицевого счёта и предоставляет снимок
17
+ счёта, который сервис возвращает для главного экрана: агрегаты по счёту,
18
+ начисления за период (документы), ссылки на квитанции и историю платежей.
19
+
20
+ > **Disclaimer.** This project is unofficial and is not affiliated with,
21
+ > endorsed by, or sponsored by the "Domovladelets+" application or its
22
+ > operators. It is built for interoperability with your own account. Use it at
23
+ > your own risk; only access accounts you are authorized to access.
24
+
25
+ > **Отказ от ответственности.** Проект неофициальный и не связан с
26
+ > приложением «Домовладелец+» или его операторами, не одобрен и не
27
+ > спонсируется ими. Он создан для взаимодействия с вашим собственным лицевым
28
+ > счётом. Используйте его на свой риск; получайте доступ только к тем счетам,
29
+ > на которые у вас есть разрешение.
30
+
31
+ ## Install
32
+
33
+ ```bash
34
+ pip install pydmvl
35
+ ```
36
+
37
+ ## Usage
38
+
39
+ ```python
40
+ from pydmvl import DmvlClient
41
+
42
+ with DmvlClient() as client:
43
+ session = client.login("user", "secret")
44
+ print(session.personal_account.amount_due)
45
+ ```
46
+
47
+ ## TLS verification (disabled by default)
48
+
49
+ The service presents an **incomplete certificate chain** (it does not serve the
50
+ intermediate CA), so standard verification fails against the real endpoint with
51
+ `certificate verify failed: unable to get local issuer certificate`. The
52
+ official client disables verification for this reason, and `pydmvl` matches
53
+ that observed behavior: `verify` defaults to `False`.
54
+
55
+ This is a deliberate, documented default, not a silent downgrade. Whenever you
56
+ can, turn verification back on — pass a CA bundle that includes the missing
57
+ intermediate, or `verify=True` if your trust store already chains the
58
+ certificate:
59
+
60
+ ```python
61
+ DmvlClient(verify="/path/to/ca-bundle.pem")
62
+ ```
63
+
64
+ Consumers that expose TLS settings to end users should present this as an
65
+ explicit opt-in control. See [spec 0004](specs/0004-client-api.md) R8.
66
+
67
+ ## Status
68
+
69
+ Authentication, the account snapshot, documents (charges, receipts, unpaid
70
+ detection), and payment history are implemented (specs 0001–0004); `0.x` — the
71
+ API may still change. See [`specs/`](specs/) for the specifications and their
72
+ status.
73
+
74
+ Capabilities:
75
+
76
+ - Login with `login` + `hash` (MD5 of the password); stateless session, no
77
+ bearer token — [spec 0001](specs/0001-auth.md)
78
+ - Account snapshot with debt/charge/payment aggregates —
79
+ [spec 0002](specs/0002-documents.md)
80
+ - Per-period charges and receipt links — [spec 0002](specs/0002-documents.md)
81
+ - Payment history and the latest payment — [spec 0003](specs/0003-payments.md)
82
+ - Public sync + async client API — [spec 0004](specs/0004-client-api.md)
83
+ - Configurable TLS verification (default off; see below) — [spec 0004](specs/0004-client-api.md) R8
84
+
85
+ ### Known API surface
86
+
87
+ The service exposes a single PHP `action` router. The catalogue of known
88
+ actions is [spec 0005](specs/0005-api-surface.md); only the read-only subset
89
+ needed for the account snapshot is implemented here — writing actions
90
+ (submitting meter readings, creating payments, opening doors, sending
91
+ messages, and similar) are out of scope.
92
+
93
+ ## Requirements
94
+
95
+ - Python >= 3.11
96
+ - [httpx](https://pypi.org/project/httpx/) >= 0.27
97
+
98
+ ## Development
99
+
100
+ ```bash
101
+ python3 -m venv .venv
102
+ .venv/bin/pip install -e ".[dev]"
103
+ .venv/bin/ruff check .
104
+ .venv/bin/ruff format --check .
105
+ .venv/bin/mypy
106
+ .venv/bin/pytest -m "not live"
107
+ ```
108
+
109
+ Live tests against the real API stay behind the `live` marker and are run
110
+ manually only, with credentials from the environment (`DMVL_USERNAME`,
111
+ `DMVL_PASSWORD`). Account credentials are sent as request query parameters, so
112
+ do not enable request-URL logging while a live client is in use.
113
+
114
+ ## License
115
+
116
+ [MIT](LICENSE)