mirrordash-sdk 0.2.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.
- mirrordash_sdk-0.2.0/.github/workflows/publish.yml +68 -0
- mirrordash_sdk-0.2.0/.github/workflows/test.yml +36 -0
- mirrordash_sdk-0.2.0/.gitignore +28 -0
- mirrordash_sdk-0.2.0/LICENSE.md +137 -0
- mirrordash_sdk-0.2.0/MODULE_AGENTS.md +112 -0
- mirrordash_sdk-0.2.0/MODULE_GUIDE.md +685 -0
- mirrordash_sdk-0.2.0/PKG-INFO +196 -0
- mirrordash_sdk-0.2.0/README.md +48 -0
- mirrordash_sdk-0.2.0/mirrordash_sdk/__init__.py +2 -0
- mirrordash_sdk-0.2.0/mirrordash_sdk/cli.py +86 -0
- mirrordash_sdk-0.2.0/mirrordash_sdk/manager.py +384 -0
- mirrordash_sdk-0.2.0/mirrordash_sdk/scaffolder.py +111 -0
- mirrordash_sdk-0.2.0/mirrordash_sdk/templates/api/README.md +36 -0
- mirrordash_sdk-0.2.0/mirrordash_sdk/templates/api/__package__/config_schema.json +34 -0
- mirrordash_sdk-0.2.0/mirrordash_sdk/templates/api/__package__/plugin.py +73 -0
- mirrordash_sdk-0.2.0/mirrordash_sdk/templates/api/__package__/templates/widget.html +18 -0
- mirrordash_sdk-0.2.0/mirrordash_sdk/templates/api/__package__/translations/en.json +8 -0
- mirrordash_sdk-0.2.0/mirrordash_sdk/templates/api/__package__/translations/sv.json +8 -0
- mirrordash_sdk-0.2.0/mirrordash_sdk/templates/api/tests/test_plugin.py +54 -0
- mirrordash_sdk-0.2.0/mirrordash_sdk/templates/basic/README.md +22 -0
- mirrordash_sdk-0.2.0/mirrordash_sdk/templates/basic/__package__/config_schema.json +21 -0
- mirrordash_sdk-0.2.0/mirrordash_sdk/templates/basic/__package__/plugin.py +30 -0
- mirrordash_sdk-0.2.0/mirrordash_sdk/templates/basic/__package__/templates/widget.html +10 -0
- mirrordash_sdk-0.2.0/mirrordash_sdk/templates/basic/__package__/translations/en.json +4 -0
- mirrordash_sdk-0.2.0/mirrordash_sdk/templates/basic/__package__/translations/sv.json +4 -0
- mirrordash_sdk-0.2.0/mirrordash_sdk/templates/basic/tests/test_plugin.py +23 -0
- mirrordash_sdk-0.2.0/mirrordash_sdk/templates/common/__package__/__init__.py +0 -0
- mirrordash_sdk-0.2.0/mirrordash_sdk/templates/common/__package__/icon.svg +5 -0
- mirrordash_sdk-0.2.0/mirrordash_sdk/templates/common/gitignore +15 -0
- mirrordash_sdk-0.2.0/mirrordash_sdk/templates/common/pyproject.toml +26 -0
- mirrordash_sdk-0.2.0/mirrordash_sdk/validator.py +240 -0
- mirrordash_sdk-0.2.0/pyproject.toml +36 -0
- mirrordash_sdk-0.2.0/scripts/release.py +100 -0
- mirrordash_sdk-0.2.0/tests/test_cli.py +213 -0
- mirrordash_sdk-0.2.0/tests/test_templates.py +80 -0
- mirrordash_sdk-0.2.0/uv.lock +111 -0
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
name: Publish to PyPI
|
|
2
|
+
|
|
3
|
+
# Publishes mirrordash-sdk to PyPI when a tag vX.Y.Z is pushed (git tag v0.2.0 && git push origin v0.2.0).
|
|
4
|
+
# PyPI trusts the publish job in the pypi environment (trusted publishing), so no token is stored.
|
|
5
|
+
on:
|
|
6
|
+
push:
|
|
7
|
+
tags: ["v*"]
|
|
8
|
+
|
|
9
|
+
permissions:
|
|
10
|
+
contents: read
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
test:
|
|
14
|
+
uses: ./.github/workflows/test.yml
|
|
15
|
+
|
|
16
|
+
build:
|
|
17
|
+
name: Build package
|
|
18
|
+
runs-on: ubuntu-24.04
|
|
19
|
+
timeout-minutes: 10
|
|
20
|
+
|
|
21
|
+
steps:
|
|
22
|
+
- name: Checkout repository
|
|
23
|
+
uses: actions/checkout@v7
|
|
24
|
+
|
|
25
|
+
- name: Set up uv
|
|
26
|
+
uses: astral-sh/setup-uv@c18668ad3cf93ea998bef934396af7bb5c839dc7 # v10.2.0
|
|
27
|
+
|
|
28
|
+
# PyPI publishes whatever pyproject.toml says, so a mismatched tag would ship the wrong version under it
|
|
29
|
+
- name: Check the tag matches pyproject.toml
|
|
30
|
+
env:
|
|
31
|
+
TAG: ${{ github.ref_name }}
|
|
32
|
+
run: |
|
|
33
|
+
VERSION=$(python3 -c 'import tomllib; print(tomllib.load(open("pyproject.toml", "rb"))["project"]["version"])')
|
|
34
|
+
if [ "$TAG" != "v$VERSION" ]; then
|
|
35
|
+
echo "::error::Tag $TAG does not match pyproject.toml version $VERSION (expected v$VERSION)"
|
|
36
|
+
exit 1
|
|
37
|
+
fi
|
|
38
|
+
|
|
39
|
+
- name: Build package distribution
|
|
40
|
+
run: uv build
|
|
41
|
+
|
|
42
|
+
- name: Save package
|
|
43
|
+
uses: actions/upload-artifact@v7
|
|
44
|
+
with:
|
|
45
|
+
name: dist
|
|
46
|
+
path: dist/
|
|
47
|
+
|
|
48
|
+
# Only this job can publish (id-token), and it runs no build code: it uploads what the build job made
|
|
49
|
+
publish:
|
|
50
|
+
name: Publish to PyPI
|
|
51
|
+
needs: [test, build]
|
|
52
|
+
runs-on: ubuntu-24.04
|
|
53
|
+
timeout-minutes: 10
|
|
54
|
+
environment:
|
|
55
|
+
name: pypi
|
|
56
|
+
url: https://pypi.org/p/mirrordash-sdk
|
|
57
|
+
permissions:
|
|
58
|
+
id-token: write
|
|
59
|
+
|
|
60
|
+
steps:
|
|
61
|
+
- name: Download package
|
|
62
|
+
uses: actions/download-artifact@v8
|
|
63
|
+
with:
|
|
64
|
+
name: dist
|
|
65
|
+
path: dist/
|
|
66
|
+
|
|
67
|
+
- name: Publish package to PyPI
|
|
68
|
+
uses: pypa/gh-action-pypi-publish@dc37677b2e1c63e2034f94d8a5b11f265b73ba33 # v1.14.2
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
name: Tests
|
|
2
|
+
|
|
3
|
+
# Runs the tests on every push to master, and before every PyPI publish (publish.yml calls it).
|
|
4
|
+
# The tests also generate each module template and run that module's own tests.
|
|
5
|
+
on:
|
|
6
|
+
push:
|
|
7
|
+
branches: [master]
|
|
8
|
+
workflow_dispatch:
|
|
9
|
+
workflow_call:
|
|
10
|
+
|
|
11
|
+
permissions:
|
|
12
|
+
contents: read
|
|
13
|
+
|
|
14
|
+
# A newer push replaces a running test of an older one; runs called by publish are never cancelled
|
|
15
|
+
concurrency:
|
|
16
|
+
group: test-${{ github.workflow }}-${{ github.ref }}
|
|
17
|
+
cancel-in-progress: ${{ github.event_name == 'push' }}
|
|
18
|
+
|
|
19
|
+
jobs:
|
|
20
|
+
test:
|
|
21
|
+
name: Tests
|
|
22
|
+
runs-on: ubuntu-24.04
|
|
23
|
+
timeout-minutes: 15
|
|
24
|
+
|
|
25
|
+
steps:
|
|
26
|
+
- name: Checkout repository
|
|
27
|
+
uses: actions/checkout@v7
|
|
28
|
+
|
|
29
|
+
- name: Set up uv
|
|
30
|
+
uses: astral-sh/setup-uv@c18668ad3cf93ea998bef934396af7bb5c839dc7 # v10.2.0
|
|
31
|
+
|
|
32
|
+
- name: Install dependencies
|
|
33
|
+
run: uv sync --frozen
|
|
34
|
+
|
|
35
|
+
- name: Run tests
|
|
36
|
+
run: uv run pytest -q
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
__pycache__/
|
|
2
|
+
*.py[cod]
|
|
3
|
+
*$py.class
|
|
4
|
+
.venv/
|
|
5
|
+
venv/
|
|
6
|
+
ENV/
|
|
7
|
+
build/
|
|
8
|
+
develop-eggs/
|
|
9
|
+
dist/
|
|
10
|
+
downloads/
|
|
11
|
+
eggs/
|
|
12
|
+
.eggs/
|
|
13
|
+
lib/
|
|
14
|
+
lib64/
|
|
15
|
+
parts/
|
|
16
|
+
sdist/
|
|
17
|
+
var/
|
|
18
|
+
wheels/
|
|
19
|
+
share/python-wheels/
|
|
20
|
+
*.egg-info/
|
|
21
|
+
.installed.cfg
|
|
22
|
+
*.egg
|
|
23
|
+
MANIFEST
|
|
24
|
+
|
|
25
|
+
# IntelliJ IDEA
|
|
26
|
+
.idea/
|
|
27
|
+
*.iml
|
|
28
|
+
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
# MirrorDash License
|
|
2
|
+
|
|
3
|
+
Required Notice: Copyright (C) 2026 Jonas Öhlander (https://github.com/Menturan/MirrorDash)
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# PolyForm Noncommercial License 1.0.0
|
|
8
|
+
|
|
9
|
+
<https://polyformproject.org/licenses/noncommercial/1.0.0>
|
|
10
|
+
|
|
11
|
+
## Acceptance
|
|
12
|
+
|
|
13
|
+
In order to get any license under these terms, you must agree
|
|
14
|
+
to them as both strict obligations and conditions to all
|
|
15
|
+
your licenses.
|
|
16
|
+
|
|
17
|
+
## Copyright License
|
|
18
|
+
|
|
19
|
+
The licensor grants you a copyright license for the
|
|
20
|
+
software to do everything you might do with the software
|
|
21
|
+
that would otherwise infringe the licensor's copyright
|
|
22
|
+
in it for any permitted purpose. However, you may
|
|
23
|
+
only distribute the software according to [Distribution
|
|
24
|
+
License](#distribution-license) and make changes or new works
|
|
25
|
+
based on the software according to [Changes and New Works
|
|
26
|
+
License](#changes-and-new-works-license).
|
|
27
|
+
|
|
28
|
+
## Distribution License
|
|
29
|
+
|
|
30
|
+
The licensor grants you an additional copyright license
|
|
31
|
+
to distribute copies of the software. Your license
|
|
32
|
+
to distribute covers distributing the software with
|
|
33
|
+
changes and new works permitted by [Changes and New Works
|
|
34
|
+
License](#changes-and-new-works-license).
|
|
35
|
+
|
|
36
|
+
## Notices
|
|
37
|
+
|
|
38
|
+
You must ensure that anyone who gets a copy of any part of
|
|
39
|
+
the software from you also gets a copy of these terms or the
|
|
40
|
+
URL for them above, as well as copies of any plain-text lines
|
|
41
|
+
beginning with `Required Notice:` that the licensor provided
|
|
42
|
+
with the software. For example:
|
|
43
|
+
|
|
44
|
+
> Required Notice: Copyright Yoyodyne, Inc. (http://example.com)
|
|
45
|
+
|
|
46
|
+
## Changes and New Works License
|
|
47
|
+
|
|
48
|
+
The licensor grants you an additional copyright license to
|
|
49
|
+
make changes and new works based on the software for any
|
|
50
|
+
permitted purpose.
|
|
51
|
+
|
|
52
|
+
## Patent License
|
|
53
|
+
|
|
54
|
+
The licensor grants you a patent license for the software that
|
|
55
|
+
covers patent claims the licensor can license, or becomes able
|
|
56
|
+
to license, that you would infringe by using the software.
|
|
57
|
+
|
|
58
|
+
## Noncommercial Purposes
|
|
59
|
+
|
|
60
|
+
Any noncommercial purpose is a permitted purpose.
|
|
61
|
+
|
|
62
|
+
## Personal Uses
|
|
63
|
+
|
|
64
|
+
Personal use for research, experiment, and testing for
|
|
65
|
+
the benefit of public knowledge, personal study, private
|
|
66
|
+
entertainment, hobby projects, amateur pursuits, or religious
|
|
67
|
+
observance, without any anticipated commercial application,
|
|
68
|
+
is use for a permitted purpose.
|
|
69
|
+
|
|
70
|
+
## Noncommercial Organizations
|
|
71
|
+
|
|
72
|
+
Use by any charitable organization, educational institution,
|
|
73
|
+
public research organization, public safety or health
|
|
74
|
+
organization, environmental protection organization,
|
|
75
|
+
or government institution is use for a permitted purpose
|
|
76
|
+
regardless of the source of funding or obligations resulting
|
|
77
|
+
from the funding.
|
|
78
|
+
|
|
79
|
+
## Fair Use
|
|
80
|
+
|
|
81
|
+
You may have "fair use" rights for the software under the
|
|
82
|
+
law. These terms do not limit them.
|
|
83
|
+
|
|
84
|
+
## No Other Rights
|
|
85
|
+
|
|
86
|
+
These terms do not allow you to sublicense or transfer any of
|
|
87
|
+
your licenses to anyone else, or prevent the licensor from
|
|
88
|
+
granting licenses to anyone else. These terms do not imply
|
|
89
|
+
any other licenses.
|
|
90
|
+
|
|
91
|
+
## Patent Defense
|
|
92
|
+
|
|
93
|
+
If you make any written claim that the software infringes or
|
|
94
|
+
contributes to infringement of any patent, your patent license
|
|
95
|
+
for the software granted under these terms ends immediately. If
|
|
96
|
+
your company makes such a claim, your patent license ends
|
|
97
|
+
immediately for work on behalf of your company.
|
|
98
|
+
|
|
99
|
+
## Violations
|
|
100
|
+
|
|
101
|
+
The first time you are notified in writing that you have
|
|
102
|
+
violated any of these terms, or done anything with the software
|
|
103
|
+
not covered by your licenses, your licenses can nonetheless
|
|
104
|
+
continue if you come into full compliance with these terms,
|
|
105
|
+
and take practical steps to correct past violations, within
|
|
106
|
+
32 days of receiving notice. Otherwise, all your licenses
|
|
107
|
+
end immediately.
|
|
108
|
+
|
|
109
|
+
## No Liability
|
|
110
|
+
|
|
111
|
+
***As far as the law allows, the software comes as is, without
|
|
112
|
+
any warranty or condition, and the licensor will not be liable
|
|
113
|
+
to you for any damages arising out of these terms or the use
|
|
114
|
+
or nature of the software, under any kind of legal claim.***
|
|
115
|
+
|
|
116
|
+
## Definitions
|
|
117
|
+
|
|
118
|
+
The **licensor** is the individual or entity offering these
|
|
119
|
+
terms, and the **software** is the software the licensor makes
|
|
120
|
+
available under these terms.
|
|
121
|
+
|
|
122
|
+
**You** refers to the individual or entity agreeing to these
|
|
123
|
+
terms.
|
|
124
|
+
|
|
125
|
+
**Your company** is any legal entity, sole proprietorship,
|
|
126
|
+
or other kind of organization that you work for, plus all
|
|
127
|
+
organizations that have control over, are under the control of,
|
|
128
|
+
or are under common control with that organization. **Control**
|
|
129
|
+
means ownership of substantially all the assets of an entity,
|
|
130
|
+
or the power to direct its management and policies by vote,
|
|
131
|
+
contract, or otherwise. Control can be direct or indirect.
|
|
132
|
+
|
|
133
|
+
**Your licenses** are all the licenses granted to you for the
|
|
134
|
+
software under these terms.
|
|
135
|
+
|
|
136
|
+
**Use** means anything you do with the software requiring one
|
|
137
|
+
of your licenses.
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
# MODULE_AGENTS.md — MirrorDash Module AI Agent Guide
|
|
2
|
+
|
|
3
|
+
This file provides AI coding agents with instructions for creating, modifying, and testing custom modules for MirrorDash. Read this before developing any module.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 1. Developer Environment & Scaffolding
|
|
8
|
+
|
|
9
|
+
### Always Use the CLI Scaffolder
|
|
10
|
+
Never build module packages by hand. Create a module from a template; pick `api` when it fetches data from a web API, `basic` otherwise:
|
|
11
|
+
```bash
|
|
12
|
+
uvx mirrordash-sdk create-module mirrordash-<name> --template api --description "<description>"
|
|
13
|
+
```
|
|
14
|
+
This gives the right Hatchling layout, entry point, settings form, translations and tests (`uv run pytest`).
|
|
15
|
+
|
|
16
|
+
### A Local Mirror
|
|
17
|
+
Inside the module directory, set up a local mirror with the module on it and start it (`http://localhost:8000/`, admin password `mirrordash`):
|
|
18
|
+
```bash
|
|
19
|
+
uvx mirrordash-sdk dev-setup -e
|
|
20
|
+
uvx mirrordash-sdk start
|
|
21
|
+
```
|
|
22
|
+
`uvx mirrordash-sdk quickstart mirrordash-<name>` does all of the above in one go and opens the browser.
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## 2. Coding Rules for Modules
|
|
27
|
+
|
|
28
|
+
### Async & Non-Blocking Loops
|
|
29
|
+
0. **Fetch with `self.fetch_json`**: never write your own HTTP code for JSON APIs. `data, error = await self.fetch_json(url, headers=..., params=...)` has a timeout, doesn't block, and on a failure returns the last good answer with `error` set (`rejected`, `offline`, `http <code>`, `invalid`). Put API keys in `headers`, never in the URL. Show `data` when there is any and a `.module-message` when `error` is set. In tests: `module.fetch_json = AsyncMock(return_value=(data, None))`.
|
|
30
|
+
1. **Never block the event loop**: The module's `run_loop` is an async task. Do not use blocking operations (like `requests`, `urllib.request.urlopen`, or `time.sleep()`).
|
|
31
|
+
2. **Wrap Synchronous I/O**: Use `await asyncio.to_thread(sync_func, ...)` to offload synchronous network or disk reads.
|
|
32
|
+
3. **Use Async Sleeps**: Sleep only with `await asyncio.sleep(self.interval)`.
|
|
33
|
+
4. **Handle Shutdown Cleanly**: Always catch and re-raise `asyncio.CancelledError` to allow graceful stops:
|
|
34
|
+
```python
|
|
35
|
+
except asyncio.CancelledError:
|
|
36
|
+
# perform cleanup...
|
|
37
|
+
raise
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### State & Persistence (OverlayFS Compliance)
|
|
41
|
+
The system runs on a read-only root filesystem in production.
|
|
42
|
+
- **Do not write to package directories**: Never open files relative to `__file__` for writing.
|
|
43
|
+
- **Use Injected Paths**:
|
|
44
|
+
- `self.data_dir`: Write SQLite databases, configurations, and user state here (backed up).
|
|
45
|
+
- `self.cache_dir`: Write temporary data, HTTP response caches, and asset downloads here (excluded from backups).
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## 3. Localization & Globals
|
|
50
|
+
|
|
51
|
+
### Respect Global Configurations
|
|
52
|
+
Never hardcode locales, metric units, or time zones. Fall back to settings defined under the global configuration:
|
|
53
|
+
|
|
54
|
+
```python
|
|
55
|
+
def __init__(self, config):
|
|
56
|
+
global_cfg = config.get("globals", {})
|
|
57
|
+
self.language = global_cfg.get("language", "en")
|
|
58
|
+
self.timezone = global_cfg.get("timezone", "Europe/Stockholm")
|
|
59
|
+
self.time_format = global_cfg.get("time_format", "24h")
|
|
60
|
+
self.temp_unit = global_cfg.get("temperature_unit", "C")
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### Localization Mappings
|
|
64
|
+
1. Place translation dictionaries in a `translations/` directory (e.g. `en.json`, `sv.json`) inside your package folder.
|
|
65
|
+
2. The core automatically resolves and merges `translations` onto the Jinja2 render context as `translations` and attaches them to `self.translations`.
|
|
66
|
+
3. Use the injected helper `self.translate("key", "default_val")` inside Python files.
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
## 4. UI Design & Styling Rules
|
|
71
|
+
|
|
72
|
+
All module designs must adhere to the MirrorDash **Ethereal Design System** to preserve visual unity on a dark ambient mirror display:
|
|
73
|
+
|
|
74
|
+
- **Transparent Backgrounds**: Widgets float on a pure black background. Never define a custom background color on the module wrapper.
|
|
75
|
+
- **Building blocks first**: lay out with the classes every module gets (no CSS needed): `.module-header`, `.display-xl`/`.display-lg` for big numbers, `.flex-row`, `.flex-row-between` (label–value rows), `.flex-column`, `.text-primary`/`.text-secondary`, `.module-message` for errors and empty states. See `http://localhost:8000/design`.
|
|
76
|
+
- **HUD Contrast**: For your own CSS, use the design tokens:
|
|
77
|
+
- Primary text/numbers: `var(--color-high-contrast)` (#ffffff)
|
|
78
|
+
- Secondary metadata/labels: `var(--color-standard-gray)` (#999999)
|
|
79
|
+
- Dimmed borders/dividers: `var(--color-dimmed-charcoal)` (#666666)
|
|
80
|
+
- **Vector Icons**: Use Lucide outline icons via standard HTML attributes. Do not use emoji icons:
|
|
81
|
+
```html
|
|
82
|
+
<i data-lucide="cloud-rain"></i>
|
|
83
|
+
```
|
|
84
|
+
- **Translation-Safe Responsive Fluidity**:
|
|
85
|
+
- **No fixed widths**: Do not use hardcoded pixel widths (`width: 150px`) for lists, columns, or layout elements. Swedish, German, or French text strings can be twice as long as English.
|
|
86
|
+
- Use Flexbox or CSS Grid with flexible sizing (`flex: 1`, `min-width: 0`, `max-content`).
|
|
87
|
+
- Use text-overflow ellipsis utilities to handle long strings gracefully.
|
|
88
|
+
- **Shadow DOM Encapsulation**: Remember that modules render inside Shadow DOM. CSS beyond the building blocks goes in a template `<style>` block; other page styles do not cascade in, and global scripts (`document.querySelector`) cannot select your module's elements. Every template `<script>` gets `root` (the module's shadow root): query from it and keep timers on it (`clearInterval(root._timer); root._timer = setInterval(...)`). Never use `document.currentScript` (null in a shadow root) or globals (two instances would share them).
|
|
89
|
+
|
|
90
|
+
---
|
|
91
|
+
|
|
92
|
+
## 5. Configuration UI (Admin Dashboard Integration)
|
|
93
|
+
|
|
94
|
+
Provide a `config_schema` dictionary or a `config_schema.json` to allow the user to modify settings from the Admin panel UI.
|
|
95
|
+
|
|
96
|
+
- Use basic JSON schema types (`boolean`, `string`, `integer`).
|
|
97
|
+
- Define title, description, and sensible default values.
|
|
98
|
+
- If providing a set of selections, use `enum` to render a dropdown.
|
|
99
|
+
- API keys, tokens and passwords get `"format": "password"`, so the admin page hides what is typed (`mirrordash-sdk validate` warns otherwise).
|
|
100
|
+
- Don't declare `enabled`, `position`, `carousel_group`, `carousel_interval`, `max_width`, `max_height`, `z_index` or `opacity`: the core adds them to every module.
|
|
101
|
+
- `self.render_template` / `self.translate` don't exist yet inside `__init__`; use them from `run_loop`.
|
|
102
|
+
|
|
103
|
+
---
|
|
104
|
+
|
|
105
|
+
## 6. Checklist for Module Commits
|
|
106
|
+
Before submitting a pull request or code change:
|
|
107
|
+
1. Ensure the package naming matches Hatchling requirements (folder uses hyphens, package/source uses underscores).
|
|
108
|
+
2. Ensure you have provided a `README.md` at the module root containing:
|
|
109
|
+
- Clear description.
|
|
110
|
+
- Step-by-step setup instructions for API keys/tokens (if any).
|
|
111
|
+
- A `screenshot.png` at the package root, referenced in the markdown.
|
|
112
|
+
3. Run the test suite: `uv run pytest`, and `uvx mirrordash-sdk validate .`.
|