Skip to content

Commit 1c707fa

Browse files
committed
Cleanup development dependencies. Add initial packaging support
1 parent 18a619a commit 1c707fa

9 files changed

Lines changed: 227 additions & 73 deletions

File tree

.editorconfig

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# EditorConfig helps maintain consistent coding styles for multiple developers
2+
# See https://editorconfig.org
3+
4+
root = true
5+
6+
[*]
7+
charset = utf-8
8+
end_of_line = lf
9+
insert_final_newline = true
10+
trim_trailing_whitespace = true
11+
12+
[*.py]
13+
indent_style = space
14+
indent_size = 4
15+
max_line_length = 150
16+
17+
[*.{yaml,yml,json}]
18+
indent_style = space
19+
indent_size = 2
20+
21+
[Makefile]
22+
indent_style = tab

.github/workflows/ci.yml

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ jobs:
1414
fail-fast: false
1515
matrix:
1616
os: [ubuntu-latest, windows-latest]
17-
python-version: ['3.11', '3.12']
17+
python-version: ['3.11', '3.14']
1818

1919
steps:
2020
- name: Checkout code
@@ -30,20 +30,19 @@ jobs:
3030
run: |
3131
python -m pip install --upgrade pip setuptools wheel
3232
pip install -r requirements.txt
33+
pip install -r requirements-dev.txt
3334
3435
- name: Verify package can be installed
3536
run: |
3637
pip install -e .
3738
3839
- name: Run unit tests
3940
run: |
40-
python -m pip install --upgrade pip
41-
pip install pytest
4241
pytest -q
4342
4443
- name: Verify CLI is available
4544
run: |
46-
tado-local --help
45+
python -m tado_local --help
4746
4847
- name: Check Python syntax
4948
run: |
@@ -101,7 +100,7 @@ jobs:
101100
- name: Install linting tools
102101
run: |
103102
python -m pip install --upgrade pip
104-
pip install ruff flake8
103+
pip install -r requirements-dev.txt
105104
106105
- name: Run Ruff
107106
run: |

.pylintrc

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
[MASTER]
2+
ignore=env,venv,.env,.venv,__pycache__,.git
3+
jobs=1
4+
module-rgx=([A-Za-z][A-Za-z0-9_]*)$
5+
6+
# Relax function/variable regexes slightly to avoid many C0103 invalid-name
7+
# complaints for project-specific short names or mixed-case usages.
8+
variable-rgx=[a-z_][a-z0-9_]{0,30}$
9+
function-rgx=[a-z_][a-z0-9_]{0,30}$
10+
class-rgx=[A-Z_][a-zA-Z0-9]+$
11+
12+
[MESSAGES CONTROL]
13+
; package-rgx not supported by older pylint versions - omitted
14+
disable=C0114,C0115,C0116,R0913,R0903,C0103,R0914,R0912,R0915,R1702,C0302,R0801,W1203,W0718,W0719,W0212,W0612,E1101,R0911,W1201,W0622,R1723,R1705,R1724,C1802,R0916
15+
16+
[FORMAT]
17+
max-line-length=150

CONTRIBUTING.md

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
# Contributing to TadoLocal
2+
3+
Thank you for your interest in contributing to TadoLocal! This document provides guidelines for developers.
4+
5+
## Development Setup
6+
7+
### Prerequisites
8+
- Python 3.11 or later
9+
- pip and virtualenv (recommended)
10+
11+
### Initial Setup
12+
13+
1. Clone the repository:
14+
```bash
15+
git clone https://github.com/ampscm/TadoLocal.git
16+
cd TadoLocal
17+
```
18+
19+
2. Create a virtual environment:
20+
```bash
21+
python -m venv venv
22+
source venv/bin/activate # On Windows: venv\Scripts\activate
23+
```
24+
25+
3. Install runtime and development dependencies:
26+
```bash
27+
pip install -r requirements.txt
28+
pip install -r requirements-dev.txt
29+
```
30+
31+
4. Install the package in development mode:
32+
```bash
33+
pip install -e .
34+
```
35+
36+
## Running Tests
37+
38+
Run all tests:
39+
```bash
40+
pytest
41+
```
42+
43+
Run tests with verbose output:
44+
```bash
45+
pytest -v
46+
```
47+
48+
Run tests with coverage:
49+
```bash
50+
pytest --cov=tado_local --cov-report=html
51+
```
52+
53+
## Code Quality
54+
55+
The project uses the following tools for code quality:
56+
57+
- **ruff**: Fast Python linter (excludes domoticz/)
58+
- **flake8**: Additional linting
59+
- **black**: Code formatting (configured in pyproject.toml)
60+
- **pytest-asyncio**: Testing async code
61+
62+
### Running Code Quality Checks
63+
64+
```bash
65+
ruff check .
66+
flake8 tado_local/
67+
```
68+
69+
## Project Structure
70+
71+
- `tado_local/` - Main package
72+
- `domoticz/` - Domoticz plugin (uses namespace packaging)
73+
- `tests/` - Unit tests
74+
- `docs/` - Documentation
75+
- `demos/` - Example scripts
76+
- `systemd/` - Systemd service files
77+
78+
## Notes for Developers
79+
80+
- **Domoticz Plugin**: The `domoticz/plugin.py` can be used standalone. Tests use a mocked Domoticz module so the plugin can be tested without the Domoticz runtime.
81+
- **Async Code**: Use `@pytest.mark.asyncio` for async tests (requires pytest-asyncio).
82+
- **Namespace Packages**: The `domoticz/` folder uses namespace packaging to allow it to be imported separately.
83+
84+
## Open PRs
85+
86+
Please check for existing open PRs before working on new features to avoid conflicts.

MANIFEST.in

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
include LICENSE
2+
include README.md
3+
recursive-include tado_local/static *
4+
recursive-include domoticz *.py

pyproject.toml

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
[build-system]
2+
requires = ["setuptools>=61.0", "wheel"]
3+
build-backend = "setuptools.build_meta"
4+
5+
[project]
6+
name = "tado-local"
7+
version = "1.0.0a1"
8+
description = "Tado-Local - Exposing Tado as local API"
9+
readme = "README.md"
10+
requires-python = ">=3.11"
11+
license = { text = "Apache-2.0" }
12+
authors = [ { name = "AmpScm" } ]
13+
classifiers = [
14+
"Development Status :: 4 - Beta",
15+
"Intended Audience :: Developers",
16+
"License :: OSI Approved :: Apache Software License",
17+
"Programming Language :: Python :: 3 :: Only",
18+
"Programming Language :: Python :: 3.11",
19+
]
20+
21+
dependencies = [
22+
"aiohomekit>=3.0.0",
23+
"fastapi>=0.100.0",
24+
"uvicorn[standard]>=0.23.0",
25+
"cryptography>=41.0.0",
26+
"zeroconf>=0.115.0",
27+
"aiohttp>=3.9.0",
28+
"dbus-next>=0.2.3",
29+
]
30+
31+
[project.urls]
32+
Homepage = "https://github.com/AmpScm/tado-local"
33+
Repository = "https://github.com/AmpScm/tado-local.git"
34+
35+
[tool.black]
36+
line-length = 150
37+
target-version = ['py313']
38+
skip-string-normalization = true
39+
40+
[tool.setuptools]
41+
include-package-data = true
42+
43+
[tool.setuptools.packages.find]
44+
where = ["."]
45+
include = ["tado_local", "domoticz"]
46+
47+
[tool.setuptools.package-data]
48+
tado_local = ["static/*"]
49+
50+
[tool.pytest.ini_options]
51+
filterwarnings = [
52+
"ignore::DeprecationWarning:lark.utils",
53+
]
54+
markers = [
55+
"asyncio: marks tests as async (deselect with '-m \"not asyncio\"')",
56+
]
57+
58+
[tool.ruff]
59+
exclude = ["domoticz/"]
60+
select = ["E", "W", "F"]

pytest.ini

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
11
[pytest]
22
filterwarnings =
33
ignore::DeprecationWarning:lark.utils
4+
markers =
5+
asyncio: marks tests as async (deselect with '-m "not asyncio"')
6+

requirements-dev.txt

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# Development dependencies for TadoLocal
2+
# Install with: pip install -r requirements-dev.txt
3+
4+
# Testing
5+
pytest>=8.0.0
6+
pytest-asyncio>=0.23.0
7+
pytest-cov>=4.0.0
8+
9+
# Linting and code quality
10+
ruff>=0.1.0
11+
flake8>=6.0.0
12+
13+
# Build tools
14+
build>=0.10.0
15+
twine>=4.0.0

setup.py

Lines changed: 16 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -1,75 +1,23 @@
1-
"""Setup configuration for Tado Local."""
2-
#
3-
# Copyright 2025 The TadoLocal and AmpScm contributors.
4-
#
5-
# Licensed under the Apache License, Version 2.0 (the "License");
6-
# you may not use this file except in compliance with the License.
7-
# You may obtain a copy of the License at
8-
#
9-
# http://www.apache.org/licenses/LICENSE-2.0
10-
#
11-
# Unless required by applicable law or agreed to in writing, software
12-
# distributed under the License is distributed on an "AS IS" BASIS,
13-
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14-
# See the License for the specific language governing permissions and
15-
# limitations under the License.
1+
"""Setup configuration for Tado Local.
162
17-
from setuptools import setup, find_packages
3+
Configuration is primarily defined in pyproject.toml.
4+
This file provides custom version discovery from __version__.py.
5+
"""
6+
7+
from setuptools import setup
188
from pathlib import Path
199
import re
2010

21-
# Read version without importing the package (to avoid dependency issues during setup)
22-
version_file = Path(__file__).parent / "tado_local" / "__version__.py"
23-
version_content = version_file.read_text(encoding="utf-8")
24-
version_match = re.search(r'^__version__\s*=\s*[\'"]([^\'"]*)[\'"]', version_content, re.MULTILINE)
25-
if not version_match:
26-
raise RuntimeError("Unable to find version string in __version__.py")
27-
__version__ = version_match.group(1)
11+
def get_version():
12+
"""Read version from tado_local/__version__.py"""
13+
version_file = Path(__file__).parent / "tado_local" / "__version__.py"
14+
content = version_file.read_text(encoding="utf-8")
15+
match = re.search(r'^__version__\s*=\s*[\'"]([^\'"]+)[\'"]', content, re.MULTILINE)
16+
if match:
17+
return match.group(1)
18+
raise RuntimeError("Unable to find __version__ in tado_local/__version__.py")
2819

29-
# Read the README file
30-
readme_file = Path(__file__).parent / "README.md"
31-
long_description = readme_file.read_text(encoding="utf-8") if readme_file.exists() else ""
20+
# Use custom version discovery
21+
setup(version=get_version())
3222

33-
# Read requirements
34-
requirements_file = Path(__file__).parent / "requirements.txt"
35-
requirements = []
36-
if requirements_file.exists():
37-
requirements = [
38-
line.strip()
39-
for line in requirements_file.read_text(encoding="utf-8").splitlines()
40-
if line.strip() and not line.startswith("#")
41-
]
4223

43-
setup(
44-
name="tado-local",
45-
version=__version__,
46-
author="Tado Local Contributors",
47-
description="REST API for Tado devices via HomeKit bridge",
48-
long_description=long_description,
49-
long_description_content_type="text/markdown",
50-
url="https://github.com/ampscm/TadoLocal",
51-
packages=find_packages(),
52-
classifiers=[
53-
"Development Status :: 3 - Alpha",
54-
"Intended Audience :: Developers",
55-
"License :: OSI Approved :: Apache Software License",
56-
"Programming Language :: Python :: 3",
57-
"Programming Language :: Python :: 3.11",
58-
"Programming Language :: Python :: 3.12",
59-
"Topic :: Home Automation",
60-
"Topic :: Software Development :: Libraries :: Python Modules",
61-
],
62-
python_requires=">=3.11",
63-
install_requires=requirements,
64-
extras_require={
65-
# Optional Avahi/dbus support for platforms that provide dbus-next
66-
'avahi': ['dbus-next>=0.6.0'],
67-
},
68-
entry_points={
69-
"console_scripts": [
70-
"tado-local=tado_local.__main__:main",
71-
],
72-
},
73-
include_package_data=True,
74-
zip_safe=False,
75-
)

0 commit comments

Comments
 (0)