pyworkflow-engine 0.1.9__py3-none-any.whl → 0.1.11__py3-none-any.whl

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.
pyworkflow/__init__.py CHANGED
@@ -29,7 +29,7 @@ Quick Start:
29
29
  >>> run_id = await start(my_workflow, "Alice")
30
30
  """
31
31
 
32
- __version__ = "0.1.9"
32
+ __version__ = "0.1.11"
33
33
 
34
34
  # Configuration
35
35
  from pyworkflow.config import (
pyworkflow/config.py CHANGED
@@ -5,8 +5,9 @@ Provides global configuration for runtime, storage, and default settings.
5
5
 
6
6
  Configuration is loaded in this priority order:
7
7
  1. Values set via pyworkflow.configure() (highest priority)
8
- 2. Values from pyworkflow.config.yaml in current directory
9
- 3. Default values
8
+ 2. Environment variables (PYWORKFLOW_*)
9
+ 3. Values from pyworkflow.config.yaml in current directory
10
+ 4. Default values
10
11
 
11
12
  Usage:
12
13
  >>> import pyworkflow
@@ -15,8 +16,26 @@ Usage:
15
16
  ... default_durable=False,
16
17
  ... storage=InMemoryStorageBackend(),
17
18
  ... )
19
+
20
+ Environment Variables:
21
+ PYWORKFLOW_STORAGE_TYPE: Storage backend type (file, memory, sqlite, postgres, mysql)
22
+ PYWORKFLOW_STORAGE_PATH: Path for file/sqlite backends
23
+ PYWORKFLOW_POSTGRES_HOST: PostgreSQL host
24
+ PYWORKFLOW_POSTGRES_PORT: PostgreSQL port
25
+ PYWORKFLOW_POSTGRES_USER: PostgreSQL user
26
+ PYWORKFLOW_POSTGRES_PASSWORD: PostgreSQL password
27
+ PYWORKFLOW_POSTGRES_DATABASE: PostgreSQL database
28
+ PYWORKFLOW_MYSQL_HOST: MySQL host
29
+ PYWORKFLOW_MYSQL_PORT: MySQL port
30
+ PYWORKFLOW_MYSQL_USER: MySQL user
31
+ PYWORKFLOW_MYSQL_PASSWORD: MySQL password
32
+ PYWORKFLOW_MYSQL_DATABASE: MySQL database
33
+ PYWORKFLOW_CELERY_BROKER: Celery broker URL
34
+ PYWORKFLOW_CELERY_RESULT_BACKEND: Celery result backend URL
35
+ PYWORKFLOW_RUNTIME: Default runtime (local, celery)
18
36
  """
19
37
 
38
+ import os
20
39
  import warnings
21
40
  from dataclasses import dataclass
22
41
  from pathlib import Path
@@ -26,6 +45,54 @@ if TYPE_CHECKING:
26
45
  from pyworkflow.storage.base import StorageBackend
27
46
 
28
47
 
48
+ def _load_env_storage_config() -> dict[str, Any] | None:
49
+ """
50
+ Load storage configuration from environment variables.
51
+
52
+ Returns:
53
+ Storage configuration dict if PYWORKFLOW_STORAGE_TYPE is set, None otherwise
54
+ """
55
+ storage_type = os.getenv("PYWORKFLOW_STORAGE_TYPE") or os.getenv("PYWORKFLOW_STORAGE_BACKEND")
56
+ if not storage_type:
57
+ return None
58
+
59
+ storage_type = storage_type.lower()
60
+
61
+ if storage_type == "postgres":
62
+ return {
63
+ "type": "postgres",
64
+ "host": os.getenv("PYWORKFLOW_POSTGRES_HOST", "localhost"),
65
+ "port": int(os.getenv("PYWORKFLOW_POSTGRES_PORT", "5432")),
66
+ "user": os.getenv("PYWORKFLOW_POSTGRES_USER", "pyworkflow"),
67
+ "password": os.getenv("PYWORKFLOW_POSTGRES_PASSWORD", ""),
68
+ "database": os.getenv("PYWORKFLOW_POSTGRES_DATABASE", "pyworkflow"),
69
+ }
70
+ elif storage_type == "mysql":
71
+ return {
72
+ "type": "mysql",
73
+ "host": os.getenv("PYWORKFLOW_MYSQL_HOST", "localhost"),
74
+ "port": int(os.getenv("PYWORKFLOW_MYSQL_PORT", "3306")),
75
+ "user": os.getenv("PYWORKFLOW_MYSQL_USER", "pyworkflow"),
76
+ "password": os.getenv("PYWORKFLOW_MYSQL_PASSWORD", ""),
77
+ "database": os.getenv("PYWORKFLOW_MYSQL_DATABASE", "pyworkflow"),
78
+ }
79
+ elif storage_type == "sqlite":
80
+ return {
81
+ "type": "sqlite",
82
+ "base_path": os.getenv("PYWORKFLOW_STORAGE_PATH", "./pyworkflow_data/pyworkflow.db"),
83
+ }
84
+ elif storage_type == "memory":
85
+ return {"type": "memory"}
86
+ elif storage_type == "file":
87
+ return {
88
+ "type": "file",
89
+ "base_path": os.getenv("PYWORKFLOW_STORAGE_PATH", "./pyworkflow_data"),
90
+ }
91
+ else:
92
+ # Unknown type, return as-is and let config_to_storage handle it
93
+ return {"type": storage_type}
94
+
95
+
29
96
  def _load_yaml_config() -> dict[str, Any]:
30
97
  """
31
98
  Load configuration from pyworkflow.config.yaml in current directory.
@@ -101,23 +168,33 @@ class PyWorkflowConfig:
101
168
  event_warning_interval: int = 100 # Log warning every N events after soft limit
102
169
 
103
170
 
104
- def _config_from_yaml() -> PyWorkflowConfig:
105
- """Create a PyWorkflowConfig from YAML file settings."""
106
- yaml_config = _load_yaml_config()
171
+ def _config_from_env_and_yaml() -> PyWorkflowConfig:
172
+ """
173
+ Create a PyWorkflowConfig from environment variables and YAML file.
107
174
 
108
- if not yaml_config:
109
- return PyWorkflowConfig()
175
+ Priority:
176
+ 1. Environment variables (PYWORKFLOW_*)
177
+ 2. YAML config file (pyworkflow.config.yaml)
178
+ 3. Defaults
179
+ """
180
+ yaml_config = _load_yaml_config()
181
+ env_storage_config = _load_env_storage_config()
110
182
 
111
- # Map YAML keys to config attributes
112
- runtime = yaml_config.get("runtime", "local")
183
+ # Runtime: env var > yaml > default
184
+ runtime = os.getenv("PYWORKFLOW_RUNTIME") or yaml_config.get("runtime", "local")
113
185
  durable = runtime == "celery" # Celery runtime defaults to durable
114
186
 
115
- # Create storage from config
116
- storage = _create_storage_from_config(yaml_config.get("storage", {}))
187
+ # Storage: env var > yaml > None
188
+ if env_storage_config:
189
+ storage = _create_storage_from_config(env_storage_config)
190
+ elif yaml_config.get("storage"):
191
+ storage = _create_storage_from_config(yaml_config.get("storage", {}))
192
+ else:
193
+ storage = None
117
194
 
118
- # Get celery broker
195
+ # Celery broker: env var > yaml > None
119
196
  celery_config = yaml_config.get("celery", {})
120
- celery_broker = celery_config.get("broker")
197
+ celery_broker = os.getenv("PYWORKFLOW_CELERY_BROKER") or celery_config.get("broker")
121
198
 
122
199
  return PyWorkflowConfig(
123
200
  default_runtime=runtime,
@@ -178,9 +255,11 @@ def configure(
178
255
  >>> # Configure with workflow discovery
179
256
  >>> pyworkflow.configure(module="myapp.workflows")
180
257
  """
181
- global _config
258
+ global _config, _config_loaded_from_yaml
182
259
  if _config is None:
183
- _config = PyWorkflowConfig()
260
+ # Load from env vars and YAML first, then apply overrides
261
+ _config = _config_from_env_and_yaml()
262
+ _config_loaded_from_yaml = True
184
263
 
185
264
  # Warn if user is modifying event limits
186
265
  event_limit_keys = {"event_soft_limit", "event_hard_limit", "event_warning_interval"}
@@ -288,16 +367,16 @@ def get_config() -> PyWorkflowConfig:
288
367
  """
289
368
  Get the current configuration.
290
369
 
291
- If not yet configured, loads from pyworkflow.config.yaml if present,
292
- otherwise creates default configuration.
370
+ If not yet configured, loads from environment variables and
371
+ pyworkflow.config.yaml (env vars take priority).
293
372
 
294
373
  Returns:
295
374
  Current PyWorkflowConfig instance
296
375
  """
297
376
  global _config, _config_loaded_from_yaml
298
377
  if _config is None:
299
- # Try to load from YAML config file first
300
- _config = _config_from_yaml()
378
+ # Load from env vars and YAML config file
379
+ _config = _config_from_env_and_yaml()
301
380
  _config_loaded_from_yaml = True
302
381
  return _config
303
382
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pyworkflow-engine
3
- Version: 0.1.9
3
+ Version: 0.1.11
4
4
  Summary: A Python implementation of durable, event-sourced workflows inspired by Vercel Workflow
5
5
  Author: PyWorkflow Contributors
6
6
  License: MIT
@@ -1,5 +1,5 @@
1
- pyworkflow/__init__.py,sha256=rZwPxo4x875Xx7i17LH4a4A6F1DZ4J9XXinbVewXLLo,6280
2
- pyworkflow/config.py,sha256=a_UvywIwmPtGy0SzeWYVk3DVCEeUlIRkDrt-4KfTtE8,11019
1
+ pyworkflow/__init__.py,sha256=8Flustr4-f69ZOy2pyXr9HyTF8FuxRUgADYW3UwgXQk,6281
2
+ pyworkflow/config.py,sha256=vNx6ETj78P_e4FxTG_zbh54W0IyF1MM1AU4ayuS2Bz8,14305
3
3
  pyworkflow/discovery.py,sha256=snW3l4nvY3Nc067TGlwtn_qdzTU9ybN7YPr8FbvY8iM,8066
4
4
  pyworkflow/aws/__init__.py,sha256=Ak_xHcR9LTRX-CwcS0XecYmzrXZw4EM3V9aKBBDEmIk,1741
5
5
  pyworkflow/aws/context.py,sha256=Vjyjip6U1Emg-WA5TlBaxFhcg15rf9mVJiPfT4VywHc,8217
@@ -83,9 +83,9 @@ pyworkflow/storage/sqlite.py,sha256=oBzJnnOp2uk0-U7hMTQk9QgJq3RBwXPQfrmYpivjdgE,
83
83
  pyworkflow/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
84
84
  pyworkflow/utils/duration.py,sha256=C-itmiSQQlplw7j6XB679hLF9xYGnyCwm7twO88OF8U,3978
85
85
  pyworkflow/utils/schedule.py,sha256=dO_MkGFyfwZpb0LDlW6BGyZzlPuQIA6dc6j9nk9lc4Y,10691
86
- pyworkflow_engine-0.1.9.dist-info/licenses/LICENSE,sha256=Y49RCTZ5ayn_yzBcRxnyIFdcMCyuYm150aty_FIznfY,1080
87
- pyworkflow_engine-0.1.9.dist-info/METADATA,sha256=BxOX2naQ5l2GwKoHXPDclRedUhw3HdclzAq9NI_1nmY,19627
88
- pyworkflow_engine-0.1.9.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
89
- pyworkflow_engine-0.1.9.dist-info/entry_points.txt,sha256=3IGAfuylnS39U0YX0pxnjrj54kB4iT_bNYrmsiDB-dE,51
90
- pyworkflow_engine-0.1.9.dist-info/top_level.txt,sha256=FLTv9pQmLDBXrQdLOhTMIS3njFibliMsQEfumqmdzBE,11
91
- pyworkflow_engine-0.1.9.dist-info/RECORD,,
86
+ pyworkflow_engine-0.1.11.dist-info/licenses/LICENSE,sha256=Y49RCTZ5ayn_yzBcRxnyIFdcMCyuYm150aty_FIznfY,1080
87
+ pyworkflow_engine-0.1.11.dist-info/METADATA,sha256=21A9CRqCgkH3ZcCUlhQ-99-LaSsozsIlAPk-aZK7QPg,19628
88
+ pyworkflow_engine-0.1.11.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
89
+ pyworkflow_engine-0.1.11.dist-info/entry_points.txt,sha256=3IGAfuylnS39U0YX0pxnjrj54kB4iT_bNYrmsiDB-dE,51
90
+ pyworkflow_engine-0.1.11.dist-info/top_level.txt,sha256=FLTv9pQmLDBXrQdLOhTMIS3njFibliMsQEfumqmdzBE,11
91
+ pyworkflow_engine-0.1.11.dist-info/RECORD,,