wt-compiler 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 (71) hide show
  1. wt_compiler-0.1.0/PKG-INFO +301 -0
  2. wt_compiler-0.1.0/README.md +277 -0
  3. wt_compiler-0.1.0/pyproject.toml +128 -0
  4. wt_compiler-0.1.0/setup.cfg +4 -0
  5. wt_compiler-0.1.0/src/wt_compiler/__init__.py +68 -0
  6. wt_compiler-0.1.0/src/wt_compiler/__main__.py +6 -0
  7. wt_compiler-0.1.0/src/wt_compiler/_models.py +41 -0
  8. wt_compiler-0.1.0/src/wt_compiler/_version.py +34 -0
  9. wt_compiler-0.1.0/src/wt_compiler/artifacts.py +513 -0
  10. wt_compiler-0.1.0/src/wt_compiler/cli.py +157 -0
  11. wt_compiler-0.1.0/src/wt_compiler/compiler.py +1078 -0
  12. wt_compiler-0.1.0/src/wt_compiler/discovery.py +391 -0
  13. wt_compiler-0.1.0/src/wt_compiler/exceptions.py +227 -0
  14. wt_compiler-0.1.0/src/wt_compiler/formatting.py +62 -0
  15. wt_compiler-0.1.0/src/wt_compiler/jsonschema.py +268 -0
  16. wt_compiler-0.1.0/src/wt_compiler/progress.py +281 -0
  17. wt_compiler-0.1.0/src/wt_compiler/py.typed +0 -0
  18. wt_compiler-0.1.0/src/wt_compiler/requirements.py +267 -0
  19. wt_compiler-0.1.0/src/wt_compiler/spec.py +1006 -0
  20. wt_compiler-0.1.0/src/wt_compiler/templates/Dockerfile.jinja2 +30 -0
  21. wt_compiler-0.1.0/src/wt_compiler/templates/README.jinja2 +12 -0
  22. wt_compiler-0.1.0/src/wt_compiler/templates/dockerignore.jinja2 +4 -0
  23. wt_compiler-0.1.0/src/wt_compiler/templates/pixi.jinja2 +0 -0
  24. wt_compiler-0.1.0/src/wt_compiler/templates/pkg/cli.jinja2 +240 -0
  25. wt_compiler-0.1.0/src/wt_compiler/templates/pkg/dags/_macros.jinja2 +112 -0
  26. wt_compiler-0.1.0/src/wt_compiler/templates/pkg/dags/init.jinja2 +9 -0
  27. wt_compiler-0.1.0/src/wt_compiler/templates/pkg/dags/run_async.jinja2 +88 -0
  28. wt_compiler-0.1.0/src/wt_compiler/templates/pkg/dags/run_sequential.jinja2 +47 -0
  29. wt_compiler-0.1.0/src/wt_compiler/templates/pkg/dispatch.jinja2 +35 -0
  30. wt_compiler-0.1.0/src/wt_compiler/templates/pkg/metadata.jinja2 +68 -0
  31. wt_compiler-0.1.0/src/wt_compiler/templates/pkg/response.jinja2 +11 -0
  32. wt_compiler-0.1.0/src/wt_compiler/templates/tests/conftest.jinja2 +520 -0
  33. wt_compiler-0.1.0/src/wt_compiler/templates/tests/test_metadata.jinja2 +113 -0
  34. wt_compiler-0.1.0/src/wt_compiler/templates/tests/test_results.jinja2 +142 -0
  35. wt_compiler-0.1.0/src/wt_compiler/util.py +56 -0
  36. wt_compiler-0.1.0/src/wt_compiler/wizard/README.md +93 -0
  37. wt_compiler-0.1.0/src/wt_compiler/wizard/__init__.py +27 -0
  38. wt_compiler-0.1.0/src/wt_compiler/wizard/abstract.py +387 -0
  39. wt_compiler-0.1.0/src/wt_compiler/wizard/default.py +221 -0
  40. wt_compiler-0.1.0/src/wt_compiler/wizard/templates/.gitattributes.jinja2 +1 -0
  41. wt_compiler-0.1.0/src/wt_compiler/wizard/templates/.gitignore.jinja2 +15 -0
  42. wt_compiler-0.1.0/src/wt_compiler/wizard/templates/LICENSE.jinja2 +1 -0
  43. wt_compiler-0.1.0/src/wt_compiler/wizard/templates/README.md.jinja2 +11 -0
  44. wt_compiler-0.1.0/src/wt_compiler/wizard/templates/licenses/Apache-2.0.txt +191 -0
  45. wt_compiler-0.1.0/src/wt_compiler/wizard/templates/licenses/BSD-3-Clause.txt +28 -0
  46. wt_compiler-0.1.0/src/wt_compiler/wizard/templates/licenses/MIT.txt +21 -0
  47. wt_compiler-0.1.0/src/wt_compiler/wizard/templates/spec.yaml.jinja2 +11 -0
  48. wt_compiler-0.1.0/src/wt_compiler/wizard/templates/test-cases.yaml.jinja2 +16 -0
  49. wt_compiler-0.1.0/src/wt_compiler.egg-info/PKG-INFO +301 -0
  50. wt_compiler-0.1.0/src/wt_compiler.egg-info/SOURCES.txt +69 -0
  51. wt_compiler-0.1.0/src/wt_compiler.egg-info/dependency_links.txt +1 -0
  52. wt_compiler-0.1.0/src/wt_compiler.egg-info/entry_points.txt +2 -0
  53. wt_compiler-0.1.0/src/wt_compiler.egg-info/requires.txt +16 -0
  54. wt_compiler-0.1.0/src/wt_compiler.egg-info/top_level.txt +1 -0
  55. wt_compiler-0.1.0/tests/__init__.py +1 -0
  56. wt_compiler-0.1.0/tests/conftest.py +22 -0
  57. wt_compiler-0.1.0/tests/fixtures/simple_spec.yaml +26 -0
  58. wt_compiler-0.1.0/tests/test_artifacts.py +204 -0
  59. wt_compiler-0.1.0/tests/test_cli.py +281 -0
  60. wt_compiler-0.1.0/tests/test_compiler.py +840 -0
  61. wt_compiler-0.1.0/tests/test_discovery_integration.py +823 -0
  62. wt_compiler-0.1.0/tests/test_exceptions.py +157 -0
  63. wt_compiler-0.1.0/tests/test_jsonschema.py +159 -0
  64. wt_compiler-0.1.0/tests/test_progress.py +259 -0
  65. wt_compiler-0.1.0/tests/test_requirements.py +59 -0
  66. wt_compiler-0.1.0/tests/test_spec.py +580 -0
  67. wt_compiler-0.1.0/tests/test_wizard_abstract.py +171 -0
  68. wt_compiler-0.1.0/tests/test_wizard_cli_compat.py +303 -0
  69. wt_compiler-0.1.0/tests/test_wizard_default.py +303 -0
  70. wt_compiler-0.1.0/tests/test_wizard_extensibility.py +479 -0
  71. wt_compiler-0.1.0/uv.lock +855 -0
@@ -0,0 +1,301 @@
1
+ Metadata-Version: 2.4
2
+ Name: wt-compiler
3
+ Version: 0.1.0
4
+ Summary: Workflow compiler for generating DAG artifacts from workflow specifications
5
+ Author: Ecoscope Team
6
+ License: MIT
7
+ Requires-Python: >=3.12
8
+ Description-Content-Type: text/markdown
9
+ Requires-Dist: wt-contracts<1.0.0,>=0.1.0
10
+ Requires-Dist: pydantic<3.0.0,>=2.0.0
11
+ Requires-Dist: jinja2>=3.0.0
12
+ Requires-Dist: ruamel.yaml>=0.17.0
13
+ Requires-Dist: py-rattler<0.23.0,>=0.22.0
14
+ Requires-Dist: datamodel-code-generator>=0.25.0
15
+ Requires-Dist: pydot>=1.4.0
16
+ Requires-Dist: ruff>=0.1.0
17
+ Requires-Dist: tomli-w>=1.0.0
18
+ Provides-Extra: dev
19
+ Requires-Dist: pytest>=7.0.0; extra == "dev"
20
+ Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
21
+ Requires-Dist: pytest-asyncio>=0.23.0; extra == "dev"
22
+ Requires-Dist: mypy>=1.0.0; extra == "dev"
23
+ Requires-Dist: ruff>=0.1.0; extra == "dev"
24
+
25
+ # wt-compiler
26
+
27
+ Workflow compiler for generating DAG artifacts from workflow specifications.
28
+
29
+ ## Overview
30
+
31
+ `wt-compiler` is a key component of the wt (workflow toolkit) ecosystem. It compiles workflow specifications (YAML files) into complete, executable workflow packages including:
32
+
33
+ - DAG Python code (async, sequential, and Jupytext variants)
34
+ - Pydantic parameter models with JSON schemas
35
+ - CLI interfaces for workflow execution
36
+ - Pixi configuration for dependency management
37
+ - Dockerfiles for containerized deployment
38
+ - Test suites
39
+
40
+ ## Key Innovation: Environment-Isolated Task Discovery
41
+
42
+ Unlike legacy systems that require importing task libraries directly, `wt-compiler` uses **subprocess-based task discovery**:
43
+
44
+ 1. Creates ephemeral rattler/pixi environments with specified requirements
45
+ 2. Calls `wt-registry` CLI in that environment
46
+ 3. Parses JSON output (validated against `wt-contracts` schemas)
47
+ 4. Compiles workflows without Python import dependencies on task libraries
48
+
49
+ This enables:
50
+ - ✅ Cross-environment compilation (Python 3.10 compiler can target Python 3.12 tasks)
51
+ - ✅ Isolation from task library dependency conflicts
52
+ - ✅ Type-safe contracts via `wt-contracts` package
53
+ - ✅ No circular dependencies between packages
54
+
55
+ ## Installation
56
+
57
+ ```bash
58
+ # From source (development)
59
+ cd wt/wt-compiler
60
+ uv sync
61
+
62
+ # Once published to PyPI
63
+ uv add wt-compiler
64
+ ```
65
+
66
+ ## Usage
67
+
68
+ ### Basic Compilation
69
+
70
+ ```python
71
+ from wt_compiler import compile_workflow, Spec
72
+ from rattler import MatchSpec
73
+
74
+ # Load a workflow specification
75
+ spec = Spec.parse_file("workflow/spec.yaml")
76
+
77
+ # Compile to artifacts
78
+ artifacts = compile_workflow(
79
+ spec=spec,
80
+ spec_relpath="workflow/spec.yaml"
81
+ )
82
+
83
+ # Write artifacts to disk
84
+ artifacts.dump(clobber=True)
85
+ ```
86
+
87
+ ### Task Discovery
88
+
89
+ ```python
90
+ from wt_compiler.discovery import discover_tasks_from_requirements
91
+ from rattler import MatchSpec
92
+
93
+ # Discover tasks from requirements
94
+ requirements = [
95
+ MatchSpec("my-task-library>=1.0.0"),
96
+ MatchSpec("another-library>=2.0.0"),
97
+ ]
98
+
99
+ tasks = discover_tasks_from_requirements(requirements)
100
+ # Returns: dict[task_name, dict[module_path, KnownTask]]
101
+ ```
102
+
103
+ ### Workflow Specification Format
104
+
105
+ ```yaml
106
+ id: my-workflow
107
+ requirements:
108
+ - name: my-task-library
109
+ version: ">=1.0.0"
110
+ channel: conda-forge
111
+
112
+ workflow:
113
+ - id: task1
114
+ task: extract_data
115
+ partial:
116
+ source: "s3://my-bucket/data.csv"
117
+
118
+ - id: task2
119
+ task: transform_data
120
+ partial:
121
+ input_data: "${{ workflow.task1.return }}"
122
+ map:
123
+ argnames: param
124
+ argvalues: "${{ workflow.task1.return }}"
125
+ ```
126
+
127
+ ## Architecture
128
+
129
+ ### Package Structure
130
+
131
+ ```
132
+ wt-compiler/
133
+ ├── src/wt_compiler/
134
+ │ ├── __init__.py # Public exports
135
+ │ ├── spec.py # Spec and TaskInstance models
136
+ │ ├── compiler.py # DagCompiler class
137
+ │ ├── discovery.py # Task discovery via rattler + CLI
138
+ │ ├── artifacts.py # Artifact generation models
139
+ │ ├── jsonschema.py # JSON schema utilities
140
+ │ ├── requirements.py # Rattler channel/matchspec handling
141
+ │ ├── util.py # Import validation utilities
142
+ │ ├── formatting.py # Ruff formatting decorator
143
+ │ ├── _models.py # Pydantic base classes
144
+ │ └── templates/ # Jinja2 templates
145
+ │ ├── pkg/
146
+ │ │ ├── dags/
147
+ │ │ │ ├── run_async.jinja2
148
+ │ │ │ ├── run_sequential.jinja2
149
+ │ │ │ └── jupytext.jinja2
150
+ │ │ ├── cli.jinja2
151
+ │ │ ├── dispatch.jinja2
152
+ │ │ └── ...
153
+ │ ├── tests/
154
+ │ ├── Dockerfile.jinja2
155
+ │ └── pixi.jinja2
156
+ └── tests/
157
+ ├── test_spec.py
158
+ ├── test_compiler.py
159
+ ├── test_discovery.py
160
+ └── ...
161
+ ```
162
+
163
+ ### Dependencies
164
+
165
+ - **wt-contracts** (>=0.1.0): Shared type contracts (RegistryOutput, TaskProtocol, etc.)
166
+ - **pydantic** (>=2.0.0): Data validation and modeling
167
+ - **jinja2**: Template rendering
168
+ - **ruamel.yaml**: YAML parsing
169
+ - **rattler** (>=0.8.0): Conda environment management
170
+ - **datamodel-code-generator**: Generate Pydantic models from JSON schemas
171
+ - **pydot**: DAG visualization
172
+
173
+ ## Implementation Status
174
+
175
+ ### ✅ Completed Components
176
+
177
+ 1. **Package Structure** - Full directory layout with src/ structure
178
+ 2. **pyproject.toml** - setuptools-scm configuration, dependencies, tool configs
179
+ 3. **spec.py** - Complete Spec, TaskInstance, and related models (~700 lines)
180
+ 4. **discovery.py** - Task discovery via rattler + wt-registry CLI
181
+ 5. **artifacts.py** - All artifact models (Dags, PixiToml, WorkflowArtifacts, etc.)
182
+ 6. **requirements.py** - Channel and MatchSpec handling
183
+ 7. **jsonschema.py** - JSON schema utilities with RJSF support
184
+ 8. **util.py** - Import reference validation
185
+ 9. **formatting.py** - Ruff formatting decorator
186
+ 10. **_models.py** - Pydantic base model classes
187
+ 11. **templates/** - All Jinja2 templates copied from legacy codebase
188
+ 12. **compiler.py** - Core DagCompiler class structure
189
+
190
+ ### ⚠️ Needs Expansion
191
+
192
+ The following areas are implemented as simplified stubs and need full implementation:
193
+
194
+ #### compiler.py TODOs
195
+
196
+ 1. **get_params_jsonschema()** - Currently returns empty schema
197
+ - Needs: Extract schemas from discovered task metadata
198
+ - Needs: Merge schemas for task groups
199
+ - Needs: Apply omit_args logic
200
+ - Needs: Generate proper UI schema
201
+ - Needs: Apply RJSF overrides
202
+
203
+ 2. **generate_params_model()** - Stub implementation
204
+ - Needs: Use datamodel-code-generator to create Pydantic model from JSON schema
205
+ - Needs: Proper imports and type hints
206
+
207
+ 3. **Graph visualization** - Not implemented
208
+ - Needs: Generate pydot graphs showing task dependencies
209
+ - Needs: Export to PNG
210
+
211
+ 4. **README generation** - Not implemented
212
+ - Needs: Generate README.md with fingerprint information
213
+ - Needs: Include workflow diagram, parameter documentation
214
+
215
+ 5. **Version management** - Basic implementation only
216
+ - Needs: Full VERSION.yaml bump logic
217
+ - Needs: Lockfile carryover for updates
218
+
219
+ 6. **get_per_taskinstance_params_notebook()** - Empty stub
220
+ - Needs: Generate parameter notebooks for Jupytext DAG
221
+
222
+ #### discovery.py TODOs
223
+
224
+ 1. **rattler-py native API** - Currently uses subprocess fallback
225
+ - Needs: Update when rattler-py solve/install API is stable
226
+ - Needs: Better error handling
227
+
228
+ 2. **Schema validation** - Basic validation only
229
+ - Needs: Full wt-contracts schema validation
230
+ - Needs: Better error messages for malformed CLI output
231
+
232
+ #### Testing
233
+
234
+ - **Unit tests** - Not yet written
235
+ - Need tests for: spec parsing, validation, compilation
236
+ - Need tests for: task discovery with mock environments
237
+ - Need tests for: artifact generation
238
+ - Need tests for: template rendering
239
+
240
+ ## Development
241
+
242
+ ### Setup
243
+
244
+ ```bash
245
+ cd wt/wt-compiler
246
+ uv sync
247
+ ```
248
+
249
+ ### Run Tests
250
+
251
+ ```bash
252
+ uv run pytest
253
+ ```
254
+
255
+ ### Type Checking
256
+
257
+ ```bash
258
+ uv run mypy src/wt_compiler
259
+ ```
260
+
261
+ ### Linting
262
+
263
+ ```bash
264
+ uv run ruff check src/wt_compiler
265
+ uv run ruff format src/wt_compiler
266
+ ```
267
+
268
+ ## Relationship to Other Packages
269
+
270
+ - **wt-contracts**: Depends on (provides type contracts)
271
+ - **wt-registry**: Called via subprocess (no Python dependency)
272
+ - **wt-task**: No dependency (generates code that uses it)
273
+ - **wt-runner**: No dependency (runner may depend on compiler in future)
274
+ - **wt-invokers**: No dependency
275
+
276
+ ## Migration from Legacy
277
+
278
+ This package replaces `ecoscope_workflows_core.compiler`. Key differences:
279
+
280
+ 1. **No direct task imports** - Uses CLI-based discovery instead
281
+ 2. **wt-contracts integration** - Type-safe schemas for all interfaces
282
+ 3. **Modular dependencies** - Only depends on wt-contracts
283
+ 4. **Simplified models** - Spec models are now in spec.py instead of compiler.py
284
+
285
+ ## Future Work
286
+
287
+ 1. Complete all TODO areas in compiler.py
288
+ 2. Write comprehensive test suite
289
+ 3. Add CLI tool for standalone compilation
290
+ 4. Add workflow visualization tools
291
+ 5. Add workflow validation tools
292
+ 6. Performance optimization for large workflows
293
+ 7. Better error messages and debugging tools
294
+
295
+ ## Contributing
296
+
297
+ See main wt repository CONTRIBUTING.md for guidelines.
298
+
299
+ ## License
300
+
301
+ MIT
@@ -0,0 +1,277 @@
1
+ # wt-compiler
2
+
3
+ Workflow compiler for generating DAG artifacts from workflow specifications.
4
+
5
+ ## Overview
6
+
7
+ `wt-compiler` is a key component of the wt (workflow toolkit) ecosystem. It compiles workflow specifications (YAML files) into complete, executable workflow packages including:
8
+
9
+ - DAG Python code (async, sequential, and Jupytext variants)
10
+ - Pydantic parameter models with JSON schemas
11
+ - CLI interfaces for workflow execution
12
+ - Pixi configuration for dependency management
13
+ - Dockerfiles for containerized deployment
14
+ - Test suites
15
+
16
+ ## Key Innovation: Environment-Isolated Task Discovery
17
+
18
+ Unlike legacy systems that require importing task libraries directly, `wt-compiler` uses **subprocess-based task discovery**:
19
+
20
+ 1. Creates ephemeral rattler/pixi environments with specified requirements
21
+ 2. Calls `wt-registry` CLI in that environment
22
+ 3. Parses JSON output (validated against `wt-contracts` schemas)
23
+ 4. Compiles workflows without Python import dependencies on task libraries
24
+
25
+ This enables:
26
+ - ✅ Cross-environment compilation (Python 3.10 compiler can target Python 3.12 tasks)
27
+ - ✅ Isolation from task library dependency conflicts
28
+ - ✅ Type-safe contracts via `wt-contracts` package
29
+ - ✅ No circular dependencies between packages
30
+
31
+ ## Installation
32
+
33
+ ```bash
34
+ # From source (development)
35
+ cd wt/wt-compiler
36
+ uv sync
37
+
38
+ # Once published to PyPI
39
+ uv add wt-compiler
40
+ ```
41
+
42
+ ## Usage
43
+
44
+ ### Basic Compilation
45
+
46
+ ```python
47
+ from wt_compiler import compile_workflow, Spec
48
+ from rattler import MatchSpec
49
+
50
+ # Load a workflow specification
51
+ spec = Spec.parse_file("workflow/spec.yaml")
52
+
53
+ # Compile to artifacts
54
+ artifacts = compile_workflow(
55
+ spec=spec,
56
+ spec_relpath="workflow/spec.yaml"
57
+ )
58
+
59
+ # Write artifacts to disk
60
+ artifacts.dump(clobber=True)
61
+ ```
62
+
63
+ ### Task Discovery
64
+
65
+ ```python
66
+ from wt_compiler.discovery import discover_tasks_from_requirements
67
+ from rattler import MatchSpec
68
+
69
+ # Discover tasks from requirements
70
+ requirements = [
71
+ MatchSpec("my-task-library>=1.0.0"),
72
+ MatchSpec("another-library>=2.0.0"),
73
+ ]
74
+
75
+ tasks = discover_tasks_from_requirements(requirements)
76
+ # Returns: dict[task_name, dict[module_path, KnownTask]]
77
+ ```
78
+
79
+ ### Workflow Specification Format
80
+
81
+ ```yaml
82
+ id: my-workflow
83
+ requirements:
84
+ - name: my-task-library
85
+ version: ">=1.0.0"
86
+ channel: conda-forge
87
+
88
+ workflow:
89
+ - id: task1
90
+ task: extract_data
91
+ partial:
92
+ source: "s3://my-bucket/data.csv"
93
+
94
+ - id: task2
95
+ task: transform_data
96
+ partial:
97
+ input_data: "${{ workflow.task1.return }}"
98
+ map:
99
+ argnames: param
100
+ argvalues: "${{ workflow.task1.return }}"
101
+ ```
102
+
103
+ ## Architecture
104
+
105
+ ### Package Structure
106
+
107
+ ```
108
+ wt-compiler/
109
+ ├── src/wt_compiler/
110
+ │ ├── __init__.py # Public exports
111
+ │ ├── spec.py # Spec and TaskInstance models
112
+ │ ├── compiler.py # DagCompiler class
113
+ │ ├── discovery.py # Task discovery via rattler + CLI
114
+ │ ├── artifacts.py # Artifact generation models
115
+ │ ├── jsonschema.py # JSON schema utilities
116
+ │ ├── requirements.py # Rattler channel/matchspec handling
117
+ │ ├── util.py # Import validation utilities
118
+ │ ├── formatting.py # Ruff formatting decorator
119
+ │ ├── _models.py # Pydantic base classes
120
+ │ └── templates/ # Jinja2 templates
121
+ │ ├── pkg/
122
+ │ │ ├── dags/
123
+ │ │ │ ├── run_async.jinja2
124
+ │ │ │ ├── run_sequential.jinja2
125
+ │ │ │ └── jupytext.jinja2
126
+ │ │ ├── cli.jinja2
127
+ │ │ ├── dispatch.jinja2
128
+ │ │ └── ...
129
+ │ ├── tests/
130
+ │ ├── Dockerfile.jinja2
131
+ │ └── pixi.jinja2
132
+ └── tests/
133
+ ├── test_spec.py
134
+ ├── test_compiler.py
135
+ ├── test_discovery.py
136
+ └── ...
137
+ ```
138
+
139
+ ### Dependencies
140
+
141
+ - **wt-contracts** (>=0.1.0): Shared type contracts (RegistryOutput, TaskProtocol, etc.)
142
+ - **pydantic** (>=2.0.0): Data validation and modeling
143
+ - **jinja2**: Template rendering
144
+ - **ruamel.yaml**: YAML parsing
145
+ - **rattler** (>=0.8.0): Conda environment management
146
+ - **datamodel-code-generator**: Generate Pydantic models from JSON schemas
147
+ - **pydot**: DAG visualization
148
+
149
+ ## Implementation Status
150
+
151
+ ### ✅ Completed Components
152
+
153
+ 1. **Package Structure** - Full directory layout with src/ structure
154
+ 2. **pyproject.toml** - setuptools-scm configuration, dependencies, tool configs
155
+ 3. **spec.py** - Complete Spec, TaskInstance, and related models (~700 lines)
156
+ 4. **discovery.py** - Task discovery via rattler + wt-registry CLI
157
+ 5. **artifacts.py** - All artifact models (Dags, PixiToml, WorkflowArtifacts, etc.)
158
+ 6. **requirements.py** - Channel and MatchSpec handling
159
+ 7. **jsonschema.py** - JSON schema utilities with RJSF support
160
+ 8. **util.py** - Import reference validation
161
+ 9. **formatting.py** - Ruff formatting decorator
162
+ 10. **_models.py** - Pydantic base model classes
163
+ 11. **templates/** - All Jinja2 templates copied from legacy codebase
164
+ 12. **compiler.py** - Core DagCompiler class structure
165
+
166
+ ### ⚠️ Needs Expansion
167
+
168
+ The following areas are implemented as simplified stubs and need full implementation:
169
+
170
+ #### compiler.py TODOs
171
+
172
+ 1. **get_params_jsonschema()** - Currently returns empty schema
173
+ - Needs: Extract schemas from discovered task metadata
174
+ - Needs: Merge schemas for task groups
175
+ - Needs: Apply omit_args logic
176
+ - Needs: Generate proper UI schema
177
+ - Needs: Apply RJSF overrides
178
+
179
+ 2. **generate_params_model()** - Stub implementation
180
+ - Needs: Use datamodel-code-generator to create Pydantic model from JSON schema
181
+ - Needs: Proper imports and type hints
182
+
183
+ 3. **Graph visualization** - Not implemented
184
+ - Needs: Generate pydot graphs showing task dependencies
185
+ - Needs: Export to PNG
186
+
187
+ 4. **README generation** - Not implemented
188
+ - Needs: Generate README.md with fingerprint information
189
+ - Needs: Include workflow diagram, parameter documentation
190
+
191
+ 5. **Version management** - Basic implementation only
192
+ - Needs: Full VERSION.yaml bump logic
193
+ - Needs: Lockfile carryover for updates
194
+
195
+ 6. **get_per_taskinstance_params_notebook()** - Empty stub
196
+ - Needs: Generate parameter notebooks for Jupytext DAG
197
+
198
+ #### discovery.py TODOs
199
+
200
+ 1. **rattler-py native API** - Currently uses subprocess fallback
201
+ - Needs: Update when rattler-py solve/install API is stable
202
+ - Needs: Better error handling
203
+
204
+ 2. **Schema validation** - Basic validation only
205
+ - Needs: Full wt-contracts schema validation
206
+ - Needs: Better error messages for malformed CLI output
207
+
208
+ #### Testing
209
+
210
+ - **Unit tests** - Not yet written
211
+ - Need tests for: spec parsing, validation, compilation
212
+ - Need tests for: task discovery with mock environments
213
+ - Need tests for: artifact generation
214
+ - Need tests for: template rendering
215
+
216
+ ## Development
217
+
218
+ ### Setup
219
+
220
+ ```bash
221
+ cd wt/wt-compiler
222
+ uv sync
223
+ ```
224
+
225
+ ### Run Tests
226
+
227
+ ```bash
228
+ uv run pytest
229
+ ```
230
+
231
+ ### Type Checking
232
+
233
+ ```bash
234
+ uv run mypy src/wt_compiler
235
+ ```
236
+
237
+ ### Linting
238
+
239
+ ```bash
240
+ uv run ruff check src/wt_compiler
241
+ uv run ruff format src/wt_compiler
242
+ ```
243
+
244
+ ## Relationship to Other Packages
245
+
246
+ - **wt-contracts**: Depends on (provides type contracts)
247
+ - **wt-registry**: Called via subprocess (no Python dependency)
248
+ - **wt-task**: No dependency (generates code that uses it)
249
+ - **wt-runner**: No dependency (runner may depend on compiler in future)
250
+ - **wt-invokers**: No dependency
251
+
252
+ ## Migration from Legacy
253
+
254
+ This package replaces `ecoscope_workflows_core.compiler`. Key differences:
255
+
256
+ 1. **No direct task imports** - Uses CLI-based discovery instead
257
+ 2. **wt-contracts integration** - Type-safe schemas for all interfaces
258
+ 3. **Modular dependencies** - Only depends on wt-contracts
259
+ 4. **Simplified models** - Spec models are now in spec.py instead of compiler.py
260
+
261
+ ## Future Work
262
+
263
+ 1. Complete all TODO areas in compiler.py
264
+ 2. Write comprehensive test suite
265
+ 3. Add CLI tool for standalone compilation
266
+ 4. Add workflow visualization tools
267
+ 5. Add workflow validation tools
268
+ 6. Performance optimization for large workflows
269
+ 7. Better error messages and debugging tools
270
+
271
+ ## Contributing
272
+
273
+ See main wt repository CONTRIBUTING.md for guidelines.
274
+
275
+ ## License
276
+
277
+ MIT
@@ -0,0 +1,128 @@
1
+ [build-system]
2
+ requires = ["setuptools>=64", "setuptools-scm>=8"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "wt-compiler"
7
+ dynamic = ["version"]
8
+ description = "Workflow compiler for generating DAG artifacts from workflow specifications"
9
+ requires-python = ">=3.12"
10
+ readme = "README.md"
11
+ license = { text = "MIT" }
12
+ authors = [
13
+ { name = "Ecoscope Team" }
14
+ ]
15
+ dependencies = [
16
+ "wt-contracts>=0.1.0,<1.0.0",
17
+ "pydantic>=2.0.0,<3.0.0",
18
+ "jinja2>=3.0.0",
19
+ "ruamel.yaml>=0.17.0",
20
+ "py-rattler>=0.22.0,<0.23.0",
21
+ "datamodel-code-generator>=0.25.0",
22
+ "pydot>=1.4.0",
23
+ "ruff>=0.1.0",
24
+ "tomli-w>=1.0.0",
25
+ ]
26
+
27
+ [project.scripts]
28
+ wt-compiler = "wt_compiler.cli:main"
29
+
30
+ [project.optional-dependencies]
31
+ dev = [
32
+ "pytest>=7.0.0",
33
+ "pytest-cov>=4.0.0",
34
+ "pytest-asyncio>=0.23.0",
35
+ "mypy>=1.0.0",
36
+ "ruff>=0.1.0",
37
+ ]
38
+
39
+ [dependency-groups]
40
+ dev = [
41
+ "pytest>=7.0.0",
42
+ "pytest-cov>=4.0.0",
43
+ "pytest-asyncio>=0.23.0",
44
+ "mypy>=1.0.0",
45
+ "ruff>=0.1.0",
46
+ ]
47
+
48
+ [tool.setuptools.packages.find]
49
+ where = ["src"]
50
+
51
+ [tool.setuptools_scm]
52
+ # Version comes from git tags matching this pattern
53
+ tag_regex = "^wt-compiler/v(?P<version>[0-9.]+)$"
54
+ # Root is the git repository root (parent of wt/)
55
+ root = ".."
56
+ # Generate version file
57
+ version_file = "src/wt_compiler/_version.py"
58
+ git_describe_command = ["git", "describe", "--dirty", "--tags", "--long", "--match", "wt-compiler/v*"]
59
+
60
+ [tool.uv.sources]
61
+ # Development override - uses local editable wt-contracts
62
+ # Published packages will reference PyPI version normally
63
+ wt-contracts = { path = "../wt-contracts", editable = true }
64
+
65
+ [tool.pytest.ini_options]
66
+ testpaths = ["tests"]
67
+ pythonpath = ["tests"]
68
+ python_files = ["test_*.py"]
69
+ addopts = "--cov=wt_compiler --cov-report=term-missing"
70
+ asyncio_mode = "auto"
71
+
72
+ [tool.mypy]
73
+ strict = true
74
+ python_version = "3.12"
75
+ warn_return_any = true
76
+ warn_unused_configs = true
77
+ disallow_untyped_defs = true
78
+
79
+ [tool.ruff]
80
+ line-length = 100
81
+ target-version = "py312"
82
+
83
+ [tool.ruff.lint]
84
+ select = [
85
+ "E", # pycodestyle errors
86
+ "W", # pycodestyle warnings
87
+ "F", # pyflakes
88
+ "I", # isort
89
+ "B", # flake8-bugbear
90
+ "C4", # flake8-comprehensions
91
+ "UP", # pyupgrade
92
+ ]
93
+ ignore = []
94
+
95
+ [tool.ruff.lint.per-file-ignores]
96
+ "__init__.py" = ["F401"] # Allow unused imports in __init__.py
97
+
98
+ # ============================================================================
99
+ # Pixi Build Configuration (conda package building)
100
+ # ============================================================================
101
+
102
+ [tool.pixi.package]
103
+ name = "wt-compiler"
104
+ version = "0.1.0"
105
+
106
+ [tool.pixi.package.build]
107
+ backend = { name = "pixi-build-python", version = "*", channels = ["conda-forge", "https://prefix.dev/pixi-build-backends"] }
108
+
109
+ [tool.pixi.package.build.config]
110
+ noarch = true
111
+
112
+ [tool.pixi.package.host-dependencies]
113
+ python = ">=3.12,<3.16"
114
+ setuptools = ">=64"
115
+ setuptools-scm = ">=8"
116
+ pip = "*"
117
+
118
+ [tool.pixi.package.run-dependencies]
119
+ python = ">=3.12,<3.16"
120
+ pydantic = ">=2.0.0,<3.0.0"
121
+ jinja2 = ">=3.0.0"
122
+ "ruamel.yaml" = ">=0.17.0"
123
+ py-rattler = ">=0.22.0,<0.23.0"
124
+ datamodel-code-generator = ">=0.25.0"
125
+ pydot = ">=1.4.0"
126
+ ruff = ">=0.1.0"
127
+ tomli-w = ">=1.0.0"
128
+ wt-contracts = ">=0.1.0,<1.0.0"
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+