hassl 0.2.0__tar.gz → 0.3.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 (36) hide show
  1. hassl-0.3.0/MANIFEST.in +2 -0
  2. {hassl-0.2.0 → hassl-0.3.0}/PKG-INFO +53 -10
  3. {hassl-0.2.0 → hassl-0.3.0}/README.md +52 -9
  4. hassl-0.3.0/hassl/__init__.py +1 -0
  5. hassl-0.3.0/hassl/ast/nodes.py +53 -0
  6. hassl-0.3.0/hassl/cli.py +372 -0
  7. hassl-0.3.0/hassl/codegen/generate.py +6 -0
  8. hassl-0.3.0/hassl/codegen/init.py +3 -0
  9. {hassl-0.2.0 → hassl-0.3.0}/hassl/codegen/package.py +255 -20
  10. {hassl-0.2.0 → hassl-0.3.0}/hassl/codegen/rules_min.py +158 -187
  11. hassl-0.3.0/hassl/parser/hassl.lark +160 -0
  12. hassl-0.3.0/hassl/parser/loader.py +6 -0
  13. {hassl-0.2.0 → hassl-0.3.0}/hassl/parser/transform.py +152 -70
  14. hassl-0.3.0/hassl/semantics/analyzer.py +305 -0
  15. {hassl-0.2.0 → hassl-0.3.0}/hassl.egg-info/PKG-INFO +53 -10
  16. {hassl-0.2.0 → hassl-0.3.0}/hassl.egg-info/SOURCES.txt +11 -1
  17. {hassl-0.2.0 → hassl-0.3.0}/pyproject.toml +6 -1
  18. {hassl-0.2.0 → hassl-0.3.0}/setup.cfg +3 -0
  19. hassl-0.3.0/tests/test_imports_and_schedules.py +257 -0
  20. hassl-0.2.0/hassl/ast/nodes.py +0 -34
  21. hassl-0.2.0/hassl/cli.py +0 -42
  22. hassl-0.2.0/hassl/semantics/__init__.py +0 -0
  23. hassl-0.2.0/hassl/semantics/analyzer.py +0 -145
  24. {hassl-0.2.0 → hassl-0.3.0}/LICENSE +0 -0
  25. {hassl-0.2.0/hassl → hassl-0.3.0/hassl/ast}/__init__.py +0 -0
  26. {hassl-0.2.0 → hassl-0.3.0}/hassl/codegen/__init__.py +0 -0
  27. {hassl-0.2.0 → hassl-0.3.0}/hassl/codegen/yaml_emit.py +0 -0
  28. {hassl-0.2.0/hassl/ast → hassl-0.3.0/hassl/parser}/__init__.py +0 -0
  29. {hassl-0.2.0/hassl/parser → hassl-0.3.0/hassl/semantics}/__init__.py +0 -0
  30. {hassl-0.2.0 → hassl-0.3.0}/hassl/semantics/domains.py +0 -0
  31. {hassl-0.2.0 → hassl-0.3.0}/hassl.egg-info/dependency_links.txt +0 -0
  32. {hassl-0.2.0 → hassl-0.3.0}/hassl.egg-info/entry_points.txt +0 -0
  33. {hassl-0.2.0 → hassl-0.3.0}/hassl.egg-info/requires.txt +0 -0
  34. {hassl-0.2.0 → hassl-0.3.0}/hassl.egg-info/top_level.txt +0 -0
  35. {hassl-0.2.0 → hassl-0.3.0}/tests/test_codegen_sync_basic.py +0 -0
  36. {hassl-0.2.0 → hassl-0.3.0}/tests/test_golden_ir_sync_shared.py +0 -0
@@ -0,0 +1,2 @@
1
+ # MANIFEST.in
2
+ recursive-include hassl *.lark
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: hassl
3
- Version: 0.2.0
3
+ Version: 0.3.0
4
4
  Summary: HASSL: Home Assistant Simple Scripting Language
5
5
  Home-page: https://github.com/adanowitz/hassl
6
6
  Author: adanowitz
@@ -17,6 +17,8 @@ Dynamic: license-file
17
17
 
18
18
  > **Home Assistant Simple Scripting Language**
19
19
 
20
+ ![Version](https://img.shields.io/badge/version-v0.3.0-blue)
21
+
20
22
  HASSL is a human-friendly domain-specific language (DSL) for building **loop-safe**, **deterministic**, and **composable** automations for [Home Assistant](https://www.home-assistant.io/).
21
23
 
22
24
  It compiles lightweight `.hassl` scripts into fully functional YAML packages that plug directly into Home Assistant, replacing complex automations with a clean, readable syntax.
@@ -32,12 +34,15 @@ It compiles lightweight `.hassl` scripts into fully functional YAML packages tha
32
34
  - **Per-rule enable gates** → `disable rule` or `enable rule` dynamically
33
35
  - **Inline waits** → `wait (!motion for 10m)` works like native HA triggers
34
36
  - **Color temperature in Kelvin** → `light.kelvin = 2700`
37
+ - **Modular packages/imports** → split automations across files with public/private exports (v0.3.0)
35
38
  - **Auto-reload resilience** → schedules re-evaluate automatically on HA restart
36
39
 
37
40
  ---
38
41
 
39
42
  ## 🧰 Example
40
43
 
44
+ ### Basic standalone script
45
+
41
46
  ```hassl
42
47
  alias light = light.wesley_lamp
43
48
  alias motion = binary_sensor.wesley_motion_motion
@@ -64,6 +69,45 @@ Produces a complete Home Assistant package with:
64
69
  - Sync automations for linked devices
65
70
  - Rule-based automations with schedules and `not_by` guards
66
71
 
72
+ ### Using imports across packages
73
+
74
+ ```hassl
75
+ # packages/std/shared.hassl
76
+ package std.shared
77
+
78
+ alias light = light.wesley_lamp
79
+ alias motion = binary_sensor.wesley_motion_motion
80
+ alias lux = sensor.wesley_motion_illuminance
81
+
82
+ schedule wake_hours:
83
+ enable from 08:00 until 19:00;
84
+ ```
85
+
86
+ ```hassl
87
+ # packages/home/landing.hassl
88
+ package home.landing
89
+ import std.shared.*
90
+
91
+ rule wesley_motion_light:
92
+ schedule use wake_hours;
93
+ if (motion && lux < 50)
94
+ then light = on;
95
+ wait (!motion for 10m) light = off
96
+
97
+ rule landing_manual_off:
98
+ if (light == off) not_by any_hassl
99
+ then disable rule wesley_motion_light for 3m
100
+ ```
101
+
102
+ This setup produces:
103
+ - One **shared package** defining reusable aliases and schedules
104
+ - A **landing package** importing and reusing those exports
105
+
106
+ Together, they generate:
107
+ - ✅ Shared schedule sensor (`binary_sensor.hassl_schedule_std_shared_wake_hours_active`)
108
+ - ✅ Cross-package rule automations gated by that schedule
109
+ - ✅ Context-safe helpers and syncs for both packages
110
+
67
111
  ---
68
112
 
69
113
  ## 🏗 Installation
@@ -103,6 +147,7 @@ Each `.hassl` file compiles into an isolated package — no naming collisions, n
103
147
  | `scripts_<pkg>.yaml` | Writer scripts with context stamping |
104
148
  | `sync_<pkg>_*.yaml` | Sync automations for each property |
105
149
  | `rules_bundled_<pkg>.yaml` | Rule logic automations + schedules |
150
+ | `schedules_<pkg>.yaml` | Time/sun-based schedule sensors (v0.3.0) |
106
151
 
107
152
  ---
108
153
 
@@ -120,7 +165,7 @@ Each `.hassl` file compiles into an isolated package — no naming collisions, n
120
165
 
121
166
  ## 🔒 Loop Safety & Context Tracking
122
167
 
123
- HASSL automatically writes the **parent context ID** into helper entities before performing actions.\
168
+ HASSL automatically writes the **parent context ID** into helper entities before performing actions.
124
169
  This ensures `not_by any_hassl` and `not_by rule("name")` guards work flawlessly, preventing infinite feedback.
125
170
 
126
171
  ---
@@ -129,23 +174,22 @@ This ensures `not_by any_hassl` and `not_by rule("name")` guards work flawlessly
129
174
 
130
175
  All schedules are restart-safe:
131
176
 
132
- - `input_boolean.hassl_schedule_<name>` automatically re-evaluates on startup.
133
- - Triggers are set for both start and end times.
177
+ - `binary_sensor.hassl_schedule_<package>_<name>_active` automatically re-evaluates on startup.
178
+ - Clock and sun-based windows update continuously through HA’s template engine.
134
179
  - Missed events (like mid-day restarts) are recovered automatically.
135
180
 
136
181
  ---
137
182
 
138
183
  ## 📚 Documentation
139
184
 
140
- For full grammar and detailed semantics, see the [HASSL Language Specification](./HASSL_Specification.md).
141
-
142
- For a hands-on guide, check out the [Quickstart](./quickstart.md).
185
+ - [Quickstart Guide](./quickstart_v1.4_2025_v0.3.0.md)
186
+ - [Language Specification](./hassl_language_spec_v1.4_2025_updated_v0.3.0.md)
143
187
 
144
188
  ---
145
189
 
146
190
  ## 🧩 Contributing
147
191
 
148
- Contributions, tests, and ideas welcome!\
192
+ Contributions, tests, and ideas welcome!
149
193
  To run tests locally:
150
194
 
151
195
  ```bash
@@ -158,10 +202,9 @@ Please open pull requests for grammar improvements, new device domains, or sched
158
202
 
159
203
  ## 📄 License
160
204
 
161
- MIT License © 2025\
205
+ MIT License © 2025
162
206
  Created and maintained by [@adanowitz](https://github.com/adanowitz)
163
207
 
164
208
  ---
165
209
 
166
210
  **HASSL** — simple, reliable, human-readable automations for Home Assistant.
167
-
@@ -2,6 +2,8 @@
2
2
 
3
3
  > **Home Assistant Simple Scripting Language**
4
4
 
5
+ ![Version](https://img.shields.io/badge/version-v0.3.0-blue)
6
+
5
7
  HASSL is a human-friendly domain-specific language (DSL) for building **loop-safe**, **deterministic**, and **composable** automations for [Home Assistant](https://www.home-assistant.io/).
6
8
 
7
9
  It compiles lightweight `.hassl` scripts into fully functional YAML packages that plug directly into Home Assistant, replacing complex automations with a clean, readable syntax.
@@ -17,12 +19,15 @@ It compiles lightweight `.hassl` scripts into fully functional YAML packages tha
17
19
  - **Per-rule enable gates** → `disable rule` or `enable rule` dynamically
18
20
  - **Inline waits** → `wait (!motion for 10m)` works like native HA triggers
19
21
  - **Color temperature in Kelvin** → `light.kelvin = 2700`
22
+ - **Modular packages/imports** → split automations across files with public/private exports (v0.3.0)
20
23
  - **Auto-reload resilience** → schedules re-evaluate automatically on HA restart
21
24
 
22
25
  ---
23
26
 
24
27
  ## 🧰 Example
25
28
 
29
+ ### Basic standalone script
30
+
26
31
  ```hassl
27
32
  alias light = light.wesley_lamp
28
33
  alias motion = binary_sensor.wesley_motion_motion
@@ -49,6 +54,45 @@ Produces a complete Home Assistant package with:
49
54
  - Sync automations for linked devices
50
55
  - Rule-based automations with schedules and `not_by` guards
51
56
 
57
+ ### Using imports across packages
58
+
59
+ ```hassl
60
+ # packages/std/shared.hassl
61
+ package std.shared
62
+
63
+ alias light = light.wesley_lamp
64
+ alias motion = binary_sensor.wesley_motion_motion
65
+ alias lux = sensor.wesley_motion_illuminance
66
+
67
+ schedule wake_hours:
68
+ enable from 08:00 until 19:00;
69
+ ```
70
+
71
+ ```hassl
72
+ # packages/home/landing.hassl
73
+ package home.landing
74
+ import std.shared.*
75
+
76
+ rule wesley_motion_light:
77
+ schedule use wake_hours;
78
+ if (motion && lux < 50)
79
+ then light = on;
80
+ wait (!motion for 10m) light = off
81
+
82
+ rule landing_manual_off:
83
+ if (light == off) not_by any_hassl
84
+ then disable rule wesley_motion_light for 3m
85
+ ```
86
+
87
+ This setup produces:
88
+ - One **shared package** defining reusable aliases and schedules
89
+ - A **landing package** importing and reusing those exports
90
+
91
+ Together, they generate:
92
+ - ✅ Shared schedule sensor (`binary_sensor.hassl_schedule_std_shared_wake_hours_active`)
93
+ - ✅ Cross-package rule automations gated by that schedule
94
+ - ✅ Context-safe helpers and syncs for both packages
95
+
52
96
  ---
53
97
 
54
98
  ## 🏗 Installation
@@ -88,6 +132,7 @@ Each `.hassl` file compiles into an isolated package — no naming collisions, n
88
132
  | `scripts_<pkg>.yaml` | Writer scripts with context stamping |
89
133
  | `sync_<pkg>_*.yaml` | Sync automations for each property |
90
134
  | `rules_bundled_<pkg>.yaml` | Rule logic automations + schedules |
135
+ | `schedules_<pkg>.yaml` | Time/sun-based schedule sensors (v0.3.0) |
91
136
 
92
137
  ---
93
138
 
@@ -105,7 +150,7 @@ Each `.hassl` file compiles into an isolated package — no naming collisions, n
105
150
 
106
151
  ## 🔒 Loop Safety & Context Tracking
107
152
 
108
- HASSL automatically writes the **parent context ID** into helper entities before performing actions.\
153
+ HASSL automatically writes the **parent context ID** into helper entities before performing actions.
109
154
  This ensures `not_by any_hassl` and `not_by rule("name")` guards work flawlessly, preventing infinite feedback.
110
155
 
111
156
  ---
@@ -114,23 +159,22 @@ This ensures `not_by any_hassl` and `not_by rule("name")` guards work flawlessly
114
159
 
115
160
  All schedules are restart-safe:
116
161
 
117
- - `input_boolean.hassl_schedule_<name>` automatically re-evaluates on startup.
118
- - Triggers are set for both start and end times.
162
+ - `binary_sensor.hassl_schedule_<package>_<name>_active` automatically re-evaluates on startup.
163
+ - Clock and sun-based windows update continuously through HA’s template engine.
119
164
  - Missed events (like mid-day restarts) are recovered automatically.
120
165
 
121
166
  ---
122
167
 
123
168
  ## 📚 Documentation
124
169
 
125
- For full grammar and detailed semantics, see the [HASSL Language Specification](./HASSL_Specification.md).
126
-
127
- For a hands-on guide, check out the [Quickstart](./quickstart.md).
170
+ - [Quickstart Guide](./quickstart_v1.4_2025_v0.3.0.md)
171
+ - [Language Specification](./hassl_language_spec_v1.4_2025_updated_v0.3.0.md)
128
172
 
129
173
  ---
130
174
 
131
175
  ## 🧩 Contributing
132
176
 
133
- Contributions, tests, and ideas welcome!\
177
+ Contributions, tests, and ideas welcome!
134
178
  To run tests locally:
135
179
 
136
180
  ```bash
@@ -143,10 +187,9 @@ Please open pull requests for grammar improvements, new device domains, or sched
143
187
 
144
188
  ## 📄 License
145
189
 
146
- MIT License © 2025\
190
+ MIT License © 2025
147
191
  Created and maintained by [@adanowitz](https://github.com/adanowitz)
148
192
 
149
193
  ---
150
194
 
151
195
  **HASSL** — simple, reliable, human-readable automations for Home Assistant.
152
-
@@ -0,0 +1 @@
1
+ __version__ = "0.3.0"
@@ -0,0 +1,53 @@
1
+ from dataclasses import dataclass, asdict, field
2
+ from typing import List, Any, Dict, Optional
3
+
4
+ @dataclass
5
+ class Alias:
6
+ name: str
7
+ entity: str
8
+ private: bool = False
9
+
10
+ @dataclass
11
+ class Sync:
12
+ kind: str
13
+ members: List[str]
14
+ name: str
15
+ invert: List[str] = field(default_factory=list)
16
+
17
+ @dataclass
18
+ class IfClause:
19
+ condition: Dict[str, Any]
20
+ actions: List[Dict[str, Any]]
21
+
22
+ @dataclass
23
+ class Schedule:
24
+ name: str
25
+ # raw clauses as produced by the transformer, e.g. {"type":"schedule_clause", ...}
26
+ clauses: List[Dict[str, Any]]
27
+ private: bool = False
28
+
29
+ @dataclass
30
+ class Rule:
31
+ name: str
32
+ # allow schedule dicts
33
+ clauses: List[Any]
34
+
35
+ @dataclass
36
+ class Program:
37
+ statements: List[object]
38
+ package: Optional[str] = None
39
+ # normalized import entries (dicts) from the transformer:
40
+ # {"type":"import","module": "...", "kind": "glob|list|alias", "items":
41
+ #[...], "as": "name"|None}
42
+ imports: List[Dict[str, Any]] = field(default_factory=list)
43
+ def to_dict(self):
44
+ def enc(x):
45
+ if isinstance(x, (Alias, Sync, Rule, IfClause, Schedule)):
46
+ d = asdict(x); d["type"] = x.__class__.__name__; return d
47
+ return x
48
+ return {
49
+ "type": "Program",
50
+ "package": self.package,
51
+ "imports": self.imports,
52
+ "statements": [enc(s) for s in self.statements],
53
+ }