wt-runner 0.1.3__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.
@@ -0,0 +1,17 @@
1
+ # Changelog
2
+
3
+ ## v0.1.3 — 2026-03-13
4
+
5
+ - Remove direct git reference from `wt-runner[gcp]` extras to fix PyPI publishing ([#71](https://github.com/wildlife-dynamics/wt/pull/71))
6
+
7
+ ## v0.1.2 — 2026-03-13
8
+
9
+ - Bootstrap release for prefix.dev conda channel
10
+
11
+ ## v0.1.1 — 2026-03-05
12
+
13
+ - Fix incorrect license metadata
14
+
15
+ ## v0.1.0 — 2026-03-05
16
+
17
+ - Initial release
@@ -0,0 +1,25 @@
1
+ Metadata-Version: 2.4
2
+ Name: wt-runner
3
+ Version: 0.1.3
4
+ Summary: FastAPI application for workflow execution using wt-invokers
5
+ License: BSD-3-Clause
6
+ Classifier: Development Status :: 3 - Alpha
7
+ Classifier: Intended Audience :: Developers
8
+ Classifier: License :: OSI Approved :: BSD License
9
+ Classifier: Programming Language :: Python :: 3
10
+ Classifier: Programming Language :: Python :: 3.13
11
+ Requires-Python: <3.16,>=3.13
12
+ Requires-Dist: wt-contracts<1.0.0,>=0.1.0
13
+ Requires-Dist: wt-invokers<1.0.0,>=0.1.0
14
+ Requires-Dist: fastapi>=0.100.0
15
+ Requires-Dist: uvicorn>=0.20.0
16
+ Requires-Dist: pydantic<3.0.0,>=2.0.0
17
+ Requires-Dist: py-rattler>=0.8.0
18
+ Requires-Dist: ruamel.yaml>=0.18.0
19
+ Requires-Dist: opentelemetry-api>=1.0.0
20
+ Requires-Dist: opentelemetry-sdk>=1.0.0
21
+ Requires-Dist: obstore>=0.6.0
22
+ Provides-Extra: gcp
23
+ Requires-Dist: opentelemetry-sdk<2,>=1.37.0; extra == "gcp"
24
+ Requires-Dist: opentelemetry-exporter-gcp-trace<2,>=1.9.0; extra == "gcp"
25
+ Requires-Dist: gcloud-aio-pubsub<7,>=6.1.0; extra == "gcp"
@@ -0,0 +1,435 @@
1
+ # wt-runner
2
+
3
+ FastAPI application for executing workflows using wt-invokers.
4
+
5
+ ## Overview
6
+
7
+ `wt-runner` is a production-ready web service that provides HTTP endpoints for executing workflows. It integrates with `wt-invokers` to support multiple execution backends (local subprocess, cloud batch, etc.) and provides comprehensive workflow management capabilities.
8
+
9
+ ## Features
10
+
11
+ - **Workflow Execution**: Run workflows with various configurations via HTTP API
12
+ - **Pub/Sub Integration**: Process workflow requests from Google Cloud Pub/Sub
13
+ - **Metadata Endpoints**: Retrieve workflow schemas and metadata
14
+ - **Format Conversion**: Convert between parameter formats (params ↔ formdata)
15
+ - **OpenTelemetry Tracing**: Built-in distributed tracing support
16
+ - **Multiple Invokers**: Support for different execution backends via wt-invokers
17
+
18
+ ## Installation
19
+
20
+ ### Basic Installation
21
+
22
+ ```bash
23
+ pip install wt-runner
24
+ ```
25
+
26
+ ### With Optional Dependencies
27
+
28
+ ```bash
29
+ # For GCP support (tracing, Pub/Sub, ecoscope-eda-core)
30
+ pip install wt-runner[gcp]
31
+ ```
32
+
33
+ ### Development Installation
34
+
35
+ ```bash
36
+ cd wt-runner
37
+ uv sync --dev
38
+ uv run pytest
39
+ ```
40
+
41
+ ## Variants
42
+
43
+ `wt-runner` ships as a base package with an optional GCP variant:
44
+
45
+ | Variant | Package | Adds |
46
+ |---------|---------|------|
47
+ | **Base** | `wt-runner` | Workflow execution, result retrieval (obstore), all endpoints except Pub/Sub |
48
+ | **GCP** | `wt-runner-gcp` | Pub/Sub endpoint, GCP tracing, Cloud Batch deps (`wt-invokers-gcp`) |
49
+
50
+ ### Installing variants
51
+
52
+ - **pip**: `pip install wt-runner[gcp]`
53
+ - **conda**: `pixi add wt-runner-gcp` (metapackage that pulls in `wt-runner` + all GCP deps)
54
+ - **Compiled workflows**: `wt-compiler compile --spec spec.yaml --variant gcp`
55
+
56
+ ## Usage
57
+
58
+ ### Starting the Server
59
+
60
+ ```bash
61
+ # Basic usage
62
+ uvicorn wt_runner.app:app
63
+
64
+ # With custom host and port
65
+ uvicorn wt_runner.app:app --host 0.0.0.0 --port 8000
66
+
67
+ # With auto-reload for development
68
+ uvicorn wt_runner.app:app --reload
69
+ ```
70
+
71
+ ### Using the FastAPI App in Code
72
+
73
+ ```python
74
+ from wt_runner import app
75
+
76
+ # The app can be imported and used with any ASGI server
77
+ import uvicorn
78
+ uvicorn.run(app, host="0.0.0.0", port=8000)
79
+ ```
80
+
81
+ ## API Endpoints
82
+
83
+ ### Health Check
84
+
85
+ ```bash
86
+ GET /
87
+ ```
88
+
89
+ Returns server health status.
90
+
91
+ **Response:**
92
+ ```json
93
+ {
94
+ "status": "ok"
95
+ }
96
+ ```
97
+
98
+ ### Run Workflow
99
+
100
+ ```bash
101
+ POST /
102
+ ```
103
+
104
+ Execute a workflow with specified parameters.
105
+
106
+ **Query Parameters:**
107
+ - `matchspec` (required): Rattler matchspec for the workflow package
108
+ - `invoker_type` (optional): Type of invoker to use (default: `BlockingLocalSubprocessInvoker`)
109
+ - `results_url` (required): URL or path for storing results
110
+ - `workflow_run_id` (optional): Unique identifier for the workflow run
111
+ - `timeout` (optional): Timeout in seconds
112
+ - `docker_image_uri` (optional): Docker image URI for the workflow
113
+
114
+ **Request Body:**
115
+ ```json
116
+ {
117
+ "params": {
118
+ "key": "value"
119
+ },
120
+ "execution_mode": "sequential",
121
+ "mock_io": false,
122
+ "data_connections_env_vars": {
123
+ "SECRET_KEY": "secret_value"
124
+ },
125
+ "lithops_config": {
126
+ "lithops": {
127
+ "backend": "localhost",
128
+ "storage": "localhost"
129
+ }
130
+ }
131
+ }
132
+ ```
133
+
134
+ **Response:**
135
+ ```json
136
+ {
137
+ "result": {...},
138
+ "error": null,
139
+ "trace": null
140
+ }
141
+ ```
142
+
143
+ ### Run from Pub/Sub
144
+
145
+ ```bash
146
+ POST /run-from-pubsub
147
+ ```
148
+
149
+ Process workflow execution requests from Google Cloud Pub/Sub messages.
150
+
151
+ **Request Body:** (Pub/Sub message format)
152
+ ```json
153
+ {
154
+ "message": {
155
+ "data": "base64-encoded-workflow-params"
156
+ }
157
+ }
158
+ ```
159
+
160
+ **Response:**
161
+ ```json
162
+ {
163
+ "status": "processed"
164
+ }
165
+ ```
166
+
167
+ ### Get RJSF Schema
168
+
169
+ ```bash
170
+ GET /rjsf?matchspec=<workflow-matchspec>
171
+ ```
172
+
173
+ Retrieve the React JSON Schema Form schema for a workflow.
174
+
175
+ **Response:**
176
+ ```json
177
+ {
178
+ "schema": {...},
179
+ "uiSchema": {...}
180
+ }
181
+ ```
182
+
183
+ ### Get Data Connection Property Names
184
+
185
+ ```bash
186
+ GET /data-connection-property-names?matchspec=<workflow-matchspec>
187
+ ```
188
+
189
+ Retrieve data connection property names for a workflow.
190
+
191
+ ### Convert Form Data to Params
192
+
193
+ ```bash
194
+ POST /formdata-to-params?matchspec=<workflow-matchspec>
195
+ ```
196
+
197
+ Convert form data format to workflow parameters.
198
+
199
+ **Request Body:**
200
+ ```json
201
+ {
202
+ "field1": "value1",
203
+ "field2": "value2"
204
+ }
205
+ ```
206
+
207
+ ### Convert Params to Form Data
208
+
209
+ ```bash
210
+ POST /params-to-formdata?matchspec=<workflow-matchspec>
211
+ ```
212
+
213
+ Convert workflow parameters to form data format.
214
+
215
+ **Request Body:**
216
+ ```json
217
+ {
218
+ "param1": "value1",
219
+ "param2": "value2"
220
+ }
221
+ ```
222
+
223
+ ## Configuration
224
+
225
+ ### Environment Variables
226
+
227
+ - `ECOSCOPE_WORKFLOWS_MATCHSPEC_OVERRIDE`: Override matchspec for all requests
228
+ - `ECOSCOPE_WORKFLOWS_OTEL_EXPORTER`: OpenTelemetry exporter type (`console` or `gcp`)
229
+ - `ECOSCOPE_WORKFLOWS_OTEL_CONSOLE_EXPORTER_DST`: Console exporter destination (`stdout` or `file`)
230
+ - `ECOSCOPE_WORKFLOWS_OTEL_CONSOLE_EXPORTER_FILE_DST_TARGET_DIR`: Directory for trace files
231
+
232
+ ### OpenTelemetry Tracing
233
+
234
+ Enable tracing by setting environment variables:
235
+
236
+ ```bash
237
+ # Console exporter (stdout)
238
+ export ECOSCOPE_WORKFLOWS_OTEL_EXPORTER=console
239
+ export ECOSCOPE_WORKFLOWS_OTEL_CONSOLE_EXPORTER_DST=stdout
240
+
241
+ # Console exporter (file)
242
+ export ECOSCOPE_WORKFLOWS_OTEL_EXPORTER=console
243
+ export ECOSCOPE_WORKFLOWS_OTEL_CONSOLE_EXPORTER_DST=file
244
+ export ECOSCOPE_WORKFLOWS_OTEL_CONSOLE_EXPORTER_FILE_DST_TARGET_DIR=/path/to/traces
245
+
246
+ # GCP Cloud Trace
247
+ export ECOSCOPE_WORKFLOWS_OTEL_EXPORTER=gcp
248
+ export GOOGLE_APPLICATION_CREDENTIALS=/path/to/credentials.json
249
+ ```
250
+
251
+ ### Programmatic Tracing Configuration
252
+
253
+ ```python
254
+ from wt_runner import configure_tracer
255
+
256
+ configure_tracer(
257
+ name="my-service",
258
+ version="1.0.0",
259
+ exporter="console",
260
+ exporter_kws={}
261
+ )
262
+ ```
263
+
264
+ ## Development
265
+
266
+ ### Running Tests
267
+
268
+ ```bash
269
+ # Core tests (GCP tests skipped)
270
+ uv sync --dev
271
+ uv run pytest
272
+
273
+ # Full tests including GCP (Pub/Sub, tracing)
274
+ uv sync --extra gcp --dev
275
+ uv run pytest
276
+
277
+ # Run with coverage
278
+ uv run pytest --cov=wt_runner --cov-report=term-missing
279
+
280
+ # Run specific test file
281
+ uv run pytest tests/test_app.py
282
+
283
+ # Run with verbose output
284
+ uv run pytest -v
285
+ ```
286
+
287
+ ### Type Checking
288
+
289
+ ```bash
290
+ uv run mypy src/wt_runner
291
+ ```
292
+
293
+ ### Linting and Formatting
294
+
295
+ ```bash
296
+ # Check code
297
+ uv run ruff check src/wt_runner
298
+
299
+ # Format code
300
+ uv run ruff format src/wt_runner
301
+ ```
302
+
303
+ ## Architecture
304
+
305
+ ### Dependencies
306
+
307
+ - **wt-invokers**: Provides workflow execution backends (required)
308
+ - **wt-contracts**: Shared interface contracts (required)
309
+ - **FastAPI**: Web framework for API endpoints
310
+ - **Uvicorn**: ASGI server for running the application
311
+ - **Rattler**: Conda package management
312
+ - **OpenTelemetry**: Distributed tracing (optional)
313
+ - **obstore**: Object storage for result retrieval (required)
314
+
315
+ ### Package Structure
316
+
317
+ ```
318
+ wt-runner/
319
+ ├── src/wt_runner/
320
+ │ ├── __init__.py # Package exports
321
+ │ ├── app.py # FastAPI application
322
+ │ ├── tracing.py # OpenTelemetry tracing
323
+ │ └── _version.py # Version info (auto-generated)
324
+ ├── tests/
325
+ │ ├── test_app.py # Endpoint tests
326
+ │ ├── test_tracing.py # Tracing tests
327
+ │ └── conftest.py # Pytest configuration
328
+ ├── pyproject.toml # Package metadata
329
+ └── README.md
330
+ ```
331
+
332
+ ## Invoker Support
333
+
334
+ The runner supports all invokers provided by `wt-invokers`:
335
+
336
+ - `BlockingLocalSubprocessInvoker`: Synchronous local subprocess execution
337
+ - `AsyncLocalSubprocessInvoker`: Asynchronous local subprocess execution
338
+ - `CloudBatchInvoker`: Google Cloud Batch execution (requires GCP dependencies)
339
+
340
+ See [wt-invokers documentation](../wt-invokers/README.md) for more details.
341
+
342
+ ## Error Handling
343
+
344
+ The runner provides comprehensive error handling:
345
+
346
+ - **400 Bad Request**: Invalid request parameters
347
+ - **422 Unprocessable Entity**: Validation errors
348
+ - **500 Internal Server Error**: Workflow execution failures
349
+ - **503 Service Unavailable**: Timeout errors
350
+
351
+ All errors include detailed trace information in the response.
352
+
353
+ ## Examples
354
+
355
+ ### Basic Workflow Execution
356
+
357
+ ```python
358
+ import httpx
359
+
360
+ response = httpx.post(
361
+ "http://localhost:8000/",
362
+ params={
363
+ "matchspec": "my-workflow>=1.0",
364
+ "results_url": "gs://bucket/results",
365
+ },
366
+ json={
367
+ "params": {"input": "data"},
368
+ "execution_mode": "sequential",
369
+ "mock_io": False,
370
+ },
371
+ )
372
+
373
+ result = response.json()
374
+ print(result["result"])
375
+ ```
376
+
377
+ ### With Custom Invoker
378
+
379
+ ```python
380
+ response = httpx.post(
381
+ "http://localhost:8000/",
382
+ params={
383
+ "matchspec": "my-workflow>=1.0",
384
+ "invoker_type": "AsyncLocalSubprocessInvoker",
385
+ "results_url": "gs://bucket/results",
386
+ },
387
+ json={
388
+ "params": {"input": "data"},
389
+ "execution_mode": "async",
390
+ "mock_io": False,
391
+ },
392
+ )
393
+ ```
394
+
395
+ ### With Tracing
396
+
397
+ ```python
398
+ response = httpx.post(
399
+ "http://localhost:8000/",
400
+ params={
401
+ "matchspec": "my-workflow>=1.0",
402
+ "results_url": "gs://bucket/results",
403
+ },
404
+ headers={
405
+ "traceparent": "00-trace-id-span-id-01",
406
+ },
407
+ json={
408
+ "params": {"input": "data"},
409
+ "execution_mode": "sequential",
410
+ "mock_io": False,
411
+ },
412
+ )
413
+ ```
414
+
415
+ ## Contributing
416
+
417
+ Contributions are welcome! Please ensure:
418
+
419
+ 1. All tests pass: `uv run pytest`
420
+ 2. Type checking passes: `uv run mypy src/wt_runner`
421
+ 3. Code is formatted: `uv run ruff format src/wt_runner`
422
+ 4. Test coverage remains >90%
423
+ 5. All public functions have docstrings
424
+
425
+ ## License
426
+
427
+ BSD-3-Clause
428
+
429
+ ## Related Packages
430
+
431
+ - [wt-contracts](../wt-contracts/README.md): Shared interface contracts
432
+ - [wt-invokers](../wt-invokers/README.md): Workflow execution backends
433
+ - [wt-task](../wt-task/README.md): Task decorator and execution
434
+ - [wt-compiler](../wt-compiler/README.md): Workflow compilation
435
+ - [wt-registry](../wt-registry/README.md): Function registration
@@ -0,0 +1,149 @@
1
+ [build-system]
2
+ requires = ["setuptools>=64", "setuptools-scm>=8"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "wt-runner"
7
+ dynamic = ["version"]
8
+ description = "FastAPI application for workflow execution using wt-invokers"
9
+ requires-python = ">=3.13,<3.16"
10
+ license = { text = "BSD-3-Clause" }
11
+ classifiers = [
12
+ "Development Status :: 3 - Alpha",
13
+ "Intended Audience :: Developers",
14
+ "License :: OSI Approved :: BSD License",
15
+ "Programming Language :: Python :: 3",
16
+ "Programming Language :: Python :: 3.13",
17
+ ]
18
+ dependencies = [
19
+ "wt-contracts>=0.1.0,<1.0.0",
20
+ "wt-invokers>=0.1.0,<1.0.0",
21
+ "fastapi>=0.100.0",
22
+ "uvicorn>=0.20.0",
23
+ "pydantic>=2.0.0,<3.0.0",
24
+ "py-rattler>=0.8.0",
25
+ "ruamel.yaml>=0.18.0",
26
+ "opentelemetry-api>=1.0.0",
27
+ "opentelemetry-sdk>=1.0.0",
28
+ "obstore>=0.6.0",
29
+ ]
30
+
31
+ [project.optional-dependencies]
32
+ # Google Cloud Platform dependencies (tracing, Pub/Sub)
33
+ # Note: ecoscope-eda-core is excluded here because PyPI forbids direct git
34
+ # references in extras. Install it separately or use the wt-runner-gcp conda
35
+ # metapackage which includes it.
36
+ gcp = [
37
+ "opentelemetry-sdk>=1.37.0,<2",
38
+ "opentelemetry-exporter-gcp-trace>=1.9.0,<2",
39
+ "gcloud-aio-pubsub>=6.1.0,<7",
40
+ ]
41
+
42
+ [dependency-groups]
43
+ dev = [
44
+ "pytest>=7.0.0",
45
+ "pytest-asyncio>=0.21.0",
46
+ "pytest-cov>=4.0.0",
47
+ "httpx>=0.24.0", # For FastAPI testing
48
+ "mypy>=1.0.0",
49
+ "ruff>=0.1.0",
50
+ ]
51
+
52
+ [tool.uv.sources]
53
+ # Development override - uses local editable packages
54
+ # Published packages will reference PyPI version normally
55
+ wt-contracts = { path = "../wt-contracts", editable = true }
56
+ wt-invokers = { path = "../wt-invokers", editable = true }
57
+
58
+ [tool.setuptools.packages.find]
59
+ where = ["src"]
60
+
61
+ [tool.setuptools_scm]
62
+ # Version comes from git tags matching this pattern
63
+ tag_regex = "^wt-runner/v(?P<version>[0-9.]+)$"
64
+ # Root is the git repository root
65
+ root = ".."
66
+ # Generate version file
67
+ version_file = "src/wt_runner/_version.py"
68
+ git_describe_command = ["git", "describe", "--dirty", "--tags", "--long", "--match", "wt-runner/v*"]
69
+
70
+ [tool.pytest.ini_options]
71
+ testpaths = ["tests"]
72
+ asyncio_mode = "auto"
73
+ addopts = "--cov=wt_runner --cov-report=term-missing"
74
+
75
+ [tool.mypy]
76
+ python_version = "3.13"
77
+ strict = true
78
+ warn_return_any = true
79
+ warn_unused_configs = true
80
+ plugins = ["pydantic.mypy"]
81
+
82
+ [[tool.mypy.overrides]]
83
+ module = [
84
+ "opentelemetry",
85
+ "opentelemetry.*",
86
+ ]
87
+ ignore_missing_imports = true
88
+
89
+ [[tool.mypy.overrides]]
90
+ module = ["wt_runner.tracing"]
91
+ warn_unused_ignores = false
92
+
93
+ [tool.ruff]
94
+ target-version = "py313"
95
+ line-length = 100
96
+
97
+ [tool.ruff.lint]
98
+ select = [
99
+ "E", # pycodestyle errors
100
+ "W", # pycodestyle warnings
101
+ "F", # pyflakes
102
+ "I", # isort
103
+ "B", # flake8-bugbear
104
+ "C4", # flake8-comprehensions
105
+ "UP", # pyupgrade
106
+ ]
107
+ ignore = []
108
+
109
+ [tool.ruff.lint.per-file-ignores]
110
+ "__init__.py" = ["F401"] # Allow unused imports in __init__.py
111
+
112
+ [tool.ruff.lint.flake8-bugbear]
113
+ extend-immutable-calls = [
114
+ "fastapi.Query",
115
+ "fastapi.Depends",
116
+ ]
117
+
118
+ # ============================================================================
119
+ # Pixi Build Configuration (conda package building)
120
+ # ============================================================================
121
+
122
+ [tool.pixi.package]
123
+ name = "wt-runner"
124
+ version = "0.1.3"
125
+
126
+ [tool.pixi.package.build]
127
+ backend = { name = "pixi-build-python", version = "*", channels = ["conda-forge", "https://prefix.dev/pixi-build-backends"] }
128
+
129
+ [tool.pixi.package.build.config]
130
+ noarch = true
131
+
132
+ [tool.pixi.package.host-dependencies]
133
+ python = ">=3.13,<3.16"
134
+ setuptools = ">=64"
135
+ setuptools-scm = ">=8"
136
+ pip = "*"
137
+
138
+ [tool.pixi.package.run-dependencies]
139
+ python = ">=3.13,<3.16"
140
+ fastapi = ">=0.100.0"
141
+ uvicorn = ">=0.20.0"
142
+ pydantic = ">=2.0.0,<3.0.0"
143
+ py-rattler = ">=0.8.0"
144
+ "ruamel.yaml" = ">=0.18.0"
145
+ opentelemetry-api = ">=1.0.0"
146
+ opentelemetry-sdk = ">=1.0.0"
147
+ obstore = ">=0.6.0"
148
+ wt-contracts = ">=0.1.0,<1.0.0"
149
+ wt-invokers = ">=0.1.0,<1.0.0"
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,36 @@
1
+ """wt-runner: FastAPI application for workflow execution.
2
+
3
+ This package provides a FastAPI web service for executing workflows using
4
+ wt-invokers. It includes endpoints for:
5
+ - Running workflows with various configurations
6
+ - Processing Pub/Sub messages
7
+ - Retrieving workflow metadata and schemas
8
+ - Converting between parameter formats
9
+ """
10
+
11
+ from wt_runner.app import app
12
+ from wt_runner.testing import Case, CaseRunner
13
+ from wt_runner.tracing import (
14
+ TraceContextHeaders,
15
+ attach_context,
16
+ build_context_headers,
17
+ configure_tracer,
18
+ )
19
+
20
+ try:
21
+ from wt_runner._version import __version__, __version_tuple__
22
+ except ImportError:
23
+ __version__ = "unknown"
24
+ __version_tuple__ = (0, 0, 0)
25
+
26
+ __all__ = [
27
+ "app",
28
+ "Case",
29
+ "CaseRunner",
30
+ "configure_tracer",
31
+ "attach_context",
32
+ "build_context_headers",
33
+ "TraceContextHeaders",
34
+ "__version__",
35
+ "__version_tuple__",
36
+ ]
@@ -0,0 +1,34 @@
1
+ # file generated by setuptools-scm
2
+ # don't change, don't track in version control
3
+
4
+ __all__ = [
5
+ "__version__",
6
+ "__version_tuple__",
7
+ "version",
8
+ "version_tuple",
9
+ "__commit_id__",
10
+ "commit_id",
11
+ ]
12
+
13
+ TYPE_CHECKING = False
14
+ if TYPE_CHECKING:
15
+ from typing import Tuple
16
+ from typing import Union
17
+
18
+ VERSION_TUPLE = Tuple[Union[int, str], ...]
19
+ COMMIT_ID = Union[str, None]
20
+ else:
21
+ VERSION_TUPLE = object
22
+ COMMIT_ID = object
23
+
24
+ version: str
25
+ __version__: str
26
+ __version_tuple__: VERSION_TUPLE
27
+ version_tuple: VERSION_TUPLE
28
+ commit_id: COMMIT_ID
29
+ __commit_id__: COMMIT_ID
30
+
31
+ __version__ = version = '0.1.3'
32
+ __version_tuple__ = version_tuple = (0, 1, 3)
33
+
34
+ __commit_id__ = commit_id = 'g9ca3e09'