Skip to content

Commit 6cd005c

Browse files
authored
Merge pull request #73 from sinricpro/3.0.0-dev
feat: sdk 3.0.0
2 parents 06b1147 + 4b6fa15 commit 6cd005c

File tree

128 files changed

+11426
-2335
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

128 files changed

+11426
-2335
lines changed

.dockerignore

Lines changed: 0 additions & 9 deletions
This file was deleted.
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
#!/usr/bin/env python3
2+
"""Validate Python example files for syntax and imports."""
3+
4+
import ast
5+
import importlib
6+
import sys
7+
from pathlib import Path
8+
9+
10+
def validate_syntax(file_path: Path) -> bool:
11+
"""Validate Python syntax of a file."""
12+
try:
13+
with open(file_path, 'r') as f:
14+
ast.parse(f.read())
15+
print(f' ✓ Syntax valid: {file_path}')
16+
return True
17+
except SyntaxError as e:
18+
print(f' ✗ Syntax error in {file_path}: {e}')
19+
return False
20+
21+
22+
def validate_imports(file_path: Path) -> bool:
23+
"""Validate that sinricpro imports work."""
24+
try:
25+
with open(file_path, 'r') as f:
26+
tree = ast.parse(f.read())
27+
except SyntaxError:
28+
return False # Already reported by validate_syntax
29+
30+
success = True
31+
for node in ast.walk(tree):
32+
if isinstance(node, ast.ImportFrom):
33+
if node.module and node.module.startswith('sinricpro'):
34+
module_name = node.module
35+
try:
36+
importlib.import_module(module_name)
37+
print(f' ✓ Import OK: {module_name}')
38+
except ImportError as e:
39+
print(f' ✗ Failed to import {module_name}: {e}')
40+
success = False
41+
elif isinstance(node, ast.Import):
42+
for alias in node.names:
43+
if alias.name.startswith('sinricpro'):
44+
try:
45+
importlib.import_module(alias.name)
46+
print(f' ✓ Import OK: {alias.name}')
47+
except ImportError as e:
48+
print(f' ✗ Failed to import {alias.name}: {e}')
49+
success = False
50+
51+
return success
52+
53+
54+
def main():
55+
"""Main validation function."""
56+
examples_dir = Path('examples')
57+
58+
if not examples_dir.exists():
59+
print(f'Error: {examples_dir} directory not found')
60+
sys.exit(1)
61+
62+
python_files = sorted(examples_dir.rglob('*.py'))
63+
64+
if not python_files:
65+
print('Warning: No Python files found in examples/')
66+
sys.exit(0)
67+
68+
print(f'Found {len(python_files)} Python example files\n')
69+
70+
all_valid = True
71+
72+
# Check syntax
73+
print('=' * 60)
74+
print('Validating Python syntax...')
75+
print('=' * 60)
76+
for file_path in python_files:
77+
if not validate_syntax(file_path):
78+
all_valid = False
79+
80+
# Check imports
81+
print('\n' + '=' * 60)
82+
print('Validating sinricpro imports...')
83+
print('=' * 60)
84+
for file_path in python_files:
85+
print(f'\nChecking: {file_path}')
86+
if not validate_imports(file_path):
87+
all_valid = False
88+
89+
print('\n' + '=' * 60)
90+
if all_valid:
91+
print('✅ All examples validated successfully!')
92+
sys.exit(0)
93+
else:
94+
print('❌ Some examples failed validation')
95+
sys.exit(1)
96+
97+
98+
if __name__ == '__main__':
99+
main()

.github/workflows/README.md

Lines changed: 247 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,247 @@
1+
# GitHub Workflows
2+
3+
This directory contains GitHub Actions workflows for the SinricPro Python SDK.
4+
5+
## Workflows
6+
7+
### 1. PR Validation (`pr-validation.yml`)
8+
9+
**Trigger:** Automatically runs on pull requests to main branches
10+
11+
**Purpose:** Validates code quality and ensures all examples compile correctly
12+
13+
**Jobs:**
14+
- **validate-examples**: Tests all example files across Python 3.10, 3.11, and 3.12
15+
- Uses `.github/scripts/validate_examples.py` to validate syntax and imports
16+
- Validates Python syntax using AST parsing
17+
- Tests that all sinricpro imports work correctly
18+
19+
- **lint-check**: Runs code quality checks
20+
- Ruff for code linting
21+
- MyPy for type checking
22+
23+
- **package-build**: Tests package building
24+
- Builds wheel and source distribution
25+
- Validates with `twine check`
26+
27+
**What it validates:**
28+
- ✅ All example files have valid Python syntax
29+
- ✅ All imports in examples are correct
30+
- ✅ Package can be built successfully
31+
- ✅ Code passes linting checks (non-blocking)
32+
- ✅ Type hints are correct (non-blocking)
33+
34+
### 2. Publish Release (`publish-release.yml`)
35+
36+
**Trigger:** Manual workflow dispatch
37+
38+
**Purpose:** Publishes a new version to PyPI and creates a GitHub release
39+
40+
**Required Secrets:**
41+
- `PYPI_API_TOKEN`: PyPI API token for publishing packages
42+
- Get from: https://pypi.org/manage/account/token/
43+
- Add to: Repository Settings → Secrets and variables → Actions → New repository secret
44+
45+
**Input Parameters:**
46+
- `version`: Version number (e.g., `3.0.0` or `3.0.0-beta.1`)
47+
- `branch`: Branch or tag to publish from (default: `main`)
48+
- `prerelease`: Mark as pre-release (checkbox)
49+
50+
**Jobs:**
51+
52+
1. **validate-version**
53+
- Validates version format (X.Y.Z or X.Y.Z-suffix)
54+
- Checks that git tag doesn't already exist
55+
56+
2. **build-and-test**
57+
- Updates version in `sinricpro/__init__.py`
58+
- Builds package (wheel + source distribution)
59+
- Validates with `twine check`
60+
- Tests local installation
61+
- Uploads artifacts for next jobs
62+
63+
3. **publish-to-pypi**
64+
- Downloads build artifacts
65+
- Publishes to PyPI using official PyPI publish action
66+
- Waits for propagation
67+
- Verifies package is available on PyPI
68+
69+
4. **create-github-release**
70+
- Creates and pushes git tag (`vX.Y.Z`)
71+
- Generates changelog from git commits
72+
- Creates GitHub release with:
73+
- Release notes
74+
- Attached wheel and source files
75+
- Links to PyPI package
76+
77+
**Workflow Summary:**
78+
After successful completion, the workflow creates a summary with:
79+
- Version number
80+
- PyPI package link
81+
- GitHub release link
82+
- Installation command
83+
84+
## How to Use
85+
86+
### Setting up PyPI Publishing
87+
88+
1. **Create PyPI API Token:**
89+
```bash
90+
# Go to https://pypi.org/manage/account/token/
91+
# Create a new API token with scope: "Entire account" or specific to "sinricpro"
92+
# Copy the token (starts with pypi-...)
93+
```
94+
95+
2. **Add Token to GitHub Secrets:**
96+
- Go to repository Settings → Secrets and variables → Actions
97+
- Click "New repository secret"
98+
- Name: `PYPI_API_TOKEN`
99+
- Value: Paste your PyPI token
100+
- Click "Add secret"
101+
102+
### Publishing a Release
103+
104+
1. **Go to Actions tab** in your repository
105+
106+
2. **Select "Publish Release to PyPI"** from the workflows list
107+
108+
3. **Click "Run workflow"** button
109+
110+
4. **Fill in the parameters:**
111+
- **Version**: Enter version number (e.g., `3.0.1`)
112+
- **Branch**: Select branch to publish from (usually `main`)
113+
- **Prerelease**: Check if this is a pre-release version
114+
115+
5. **Click "Run workflow"**
116+
117+
6. **Monitor the workflow:**
118+
- Watch each job complete
119+
- Check for any errors
120+
- View the summary for installation instructions
121+
122+
### Version Numbering Guidelines
123+
124+
**Stable releases:**
125+
- `3.0.0` - Major version
126+
- `3.0.1` - Patch version
127+
- `3.1.0` - Minor version
128+
129+
**Pre-releases:**
130+
- `3.0.0-alpha.1` - Alpha release
131+
- `3.0.0-beta.1` - Beta release
132+
- `3.0.0-rc.1` - Release candidate
133+
134+
### Testing Before Release
135+
136+
Before publishing a release:
137+
138+
1. **Test locally:**
139+
```bash
140+
# Build the package
141+
python -m build
142+
143+
# Check with twine
144+
twine check dist/*
145+
146+
# Install locally
147+
pip install dist/*.whl
148+
149+
# Test import
150+
python -c "import sinricpro; print(sinricpro.__version__)"
151+
```
152+
153+
2. **Test examples:**
154+
```bash
155+
# Validate all examples
156+
python -m compileall examples/
157+
```
158+
159+
3. **Run tests (if available):**
160+
```bash
161+
pytest tests/
162+
```
163+
164+
### Troubleshooting
165+
166+
**"Tag already exists" error:**
167+
- The version tag already exists in git
168+
- Choose a different version number or delete the existing tag
169+
170+
**"PyPI upload failed" error:**
171+
- Check that `PYPI_API_TOKEN` secret is set correctly
172+
- Verify token has correct permissions
173+
- Ensure version doesn't already exist on PyPI
174+
175+
**"Package build failed" error:**
176+
- Check `pyproject.toml` for syntax errors
177+
- Verify all dependencies are listed correctly
178+
- Check that version number is valid
179+
180+
**"Import error in examples" (PR validation):**
181+
- Missing import in example file
182+
- Typo in module name
183+
- New module not exported in `__init__.py`
184+
185+
## Workflow Permissions
186+
187+
The workflows require the following permissions:
188+
189+
- `contents: write` - For creating tags and releases
190+
- `packages: write` - For publishing to PyPI (via PYPI_API_TOKEN)
191+
192+
These are automatically granted in the workflow files.
193+
194+
## Best Practices
195+
196+
1. **Always test locally before publishing**
197+
2. **Use semantic versioning (semver.org)**
198+
3. **Write meaningful release notes**
199+
4. **Test examples after each change**
200+
5. **Keep dependencies up to date**
201+
6. **Tag releases consistently (vX.Y.Z format)**
202+
203+
## Scripts
204+
205+
The `.github/scripts/` directory contains helper scripts used by the workflows:
206+
207+
### validate_examples.py
208+
209+
Validates all Python example files in the `examples/` directory:
210+
- Checks Python syntax using AST parsing
211+
- Verifies that all `sinricpro` imports are valid
212+
- Provides detailed output for debugging
213+
- Returns exit code 0 on success, 1 on failure
214+
215+
**Usage:**
216+
```bash
217+
python .github/scripts/validate_examples.py
218+
```
219+
220+
**Output:**
221+
```
222+
Found 16 Python example files
223+
224+
============================================================
225+
Validating Python syntax...
226+
============================================================
227+
✓ Syntax valid: examples/switch/switch_example.py
228+
✓ Syntax valid: examples/light/light_example.py
229+
...
230+
231+
============================================================
232+
Validating sinricpro imports...
233+
============================================================
234+
Checking: examples/switch/switch_example.py
235+
✓ Import OK: sinricpro
236+
...
237+
238+
============================================================
239+
✅ All examples validated successfully!
240+
```
241+
242+
## Support
243+
244+
If you encounter issues with the workflows:
245+
- Check the workflow run logs in GitHub Actions
246+
- Review the troubleshooting section above
247+
- Open an issue in the repository

0 commit comments

Comments
 (0)