runnable 0.14.0__py3-none-any.whl → 0.16.0__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.
runnable/utils.py CHANGED
@@ -21,7 +21,6 @@ from runnable import defaults, names
21
21
  from runnable.defaults import TypeMapVariable
22
22
 
23
23
  if TYPE_CHECKING: # pragma: no cover
24
- from extensions.nodes.nodes import TaskNode
25
24
  from runnable.nodes import BaseNode
26
25
 
27
26
 
@@ -428,25 +427,26 @@ def get_node_execution_command(
428
427
  log_level = log_level or logging.getLevelName(logger.getEffectiveLevel())
429
428
 
430
429
  action = (
431
- f"runnable execute_single_node {run_id} "
432
- f"{node._command_friendly_name()}"
433
- f" --log-level {log_level}"
430
+ f"runnable execute-single-node {run_id} "
431
+ f"{context.run_context.pipeline_file} "
432
+ f"{node._command_friendly_name()} "
433
+ f"--log-level {log_level} "
434
434
  )
435
435
 
436
- if context.run_context.pipeline_file:
437
- action = action + f" --file {context.run_context.pipeline_file}"
436
+ if context.run_context.from_sdk:
437
+ action = action + "--mode python "
438
438
 
439
439
  if map_variable:
440
- action = action + f" --map-variable '{json.dumps(map_variable)}'"
440
+ action = action + f"--map-variable '{json.dumps(map_variable)}' "
441
441
 
442
442
  if context.run_context.configuration_file:
443
- action = action + f" --config-file {context.run_context.configuration_file}"
443
+ action = action + f"--config {context.run_context.configuration_file} "
444
444
 
445
445
  if context.run_context.parameters_file:
446
- action = action + f" --parameters-file {context.run_context.parameters_file}"
446
+ action = action + f"--parameters-file {context.run_context.parameters_file} "
447
447
 
448
448
  if context.run_context.tag:
449
- action = action + f" --tag {context.run_context.tag}"
449
+ action = action + f"--tag {context.run_context.tag}"
450
450
 
451
451
  return action
452
452
 
@@ -476,8 +476,8 @@ def get_fan_command(
476
476
  action = (
477
477
  f"runnable fan {run_id} "
478
478
  f"{node._command_friendly_name()} "
479
+ f"{context.run_context.pipeline_file} "
479
480
  f"--mode {mode} "
480
- f"--file {context.run_context.pipeline_file} "
481
481
  f"--log-level {log_level} "
482
482
  )
483
483
  if context.run_context.configuration_file:
@@ -496,18 +496,10 @@ def get_fan_command(
496
496
 
497
497
 
498
498
  # TODO: This is not the right place for this.
499
- def get_job_execution_command(node: TaskNode, over_write_run_id: str = "") -> str:
499
+ def get_job_execution_command(over_write_run_id: str = "") -> str:
500
500
  """Get the execution command to run a job via command line.
501
501
 
502
502
  This function should be used by all executors to submit jobs in remote environment
503
-
504
- Args:
505
- executor (BaseExecutor): The executor class.
506
- node (BaseNode): The node being executed.
507
- over_write_run_id (str, optional): If the node is part of a map step. Defaults to ''.
508
-
509
- Returns:
510
- str: The execution command to run a job via command line.
511
503
  """
512
504
 
513
505
  run_id = context.run_context.run_id
@@ -517,24 +509,23 @@ def get_job_execution_command(node: TaskNode, over_write_run_id: str = "") -> st
517
509
 
518
510
  log_level = logging.getLevelName(logger.getEffectiveLevel())
519
511
 
520
- cli_command, cli_options = node.executable.get_cli_options()
521
-
522
- action = f"runnable execute_{cli_command} {run_id} " f" --log-level {log_level}"
523
-
524
- action = action + f" --entrypoint {defaults.ENTRYPOINT.SYSTEM.value}"
512
+ action = (
513
+ f"runnable execute-job /app/{context.run_context.job_definition_file} {run_id} "
514
+ f" --log-level {log_level}"
515
+ )
525
516
 
526
517
  if context.run_context.configuration_file:
527
- action = action + f" --config-file {context.run_context.configuration_file}"
518
+ action = action + f" --config {context.run_context.configuration_file}"
528
519
 
529
520
  if context.run_context.parameters_file:
530
- action = action + f" --parameters-file {context.run_context.parameters_file}"
521
+ action = action + f" --parameters {context.run_context.parameters_file}"
522
+
523
+ if context.run_context.from_sdk:
524
+ action = action + " --mode python "
531
525
 
532
526
  if context.run_context.tag:
533
527
  action = action + f" --tag {context.run_context.tag}"
534
528
 
535
- for key, value in cli_options.items():
536
- action = action + f" --{key} {value}"
537
-
538
529
  return action
539
530
 
540
531
 
@@ -555,6 +546,7 @@ def get_provider_by_name_and_type(
555
546
  Returns:
556
547
  object: A service object
557
548
  """
549
+
558
550
  namespace = service_type
559
551
 
560
552
  service_name = service_details["type"]
@@ -1,16 +1,17 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: runnable
3
- Version: 0.14.0
3
+ Version: 0.16.0
4
4
  Summary: Add your description here
5
5
  Author-email: "Vammi, Vijay" <vijay.vammi@astrazeneca.com>
6
6
  License-File: LICENSE
7
- Requires-Python: >=3.9
7
+ Requires-Python: >=3.10
8
8
  Requires-Dist: catalog
9
9
  Requires-Dist: click-plugins>=1.1.1
10
10
  Requires-Dist: click<=8.1.3
11
11
  Requires-Dist: dill>=0.3.9
12
- Requires-Dist: executor
12
+ Requires-Dist: job-executor
13
13
  Requires-Dist: nodes
14
+ Requires-Dist: pipeline-executor
14
15
  Requires-Dist: pydantic>=2.10.3
15
16
  Requires-Dist: python-dotenv>=1.0.1
16
17
  Requires-Dist: rich>=13.9.4
@@ -24,6 +25,8 @@ Provides-Extra: docker
24
25
  Requires-Dist: docker>=7.1.0; extra == 'docker'
25
26
  Provides-Extra: examples
26
27
  Requires-Dist: pandas>=2.2.3; extra == 'examples'
28
+ Provides-Extra: k8s
29
+ Requires-Dist: kubernetes>=31.0.0; extra == 'k8s'
27
30
  Provides-Extra: notebook
28
31
  Requires-Dist: ploomber-engine>=0.0.33; extra == 'notebook'
29
32
  Description-Content-Type: text/markdown
@@ -0,0 +1,23 @@
1
+ runnable/__init__.py,sha256=KqpLDTD1CfdEj2aDyEkSn2KW-_83qyrRrrWLc5lZVM4,624
2
+ runnable/catalog.py,sha256=MiEmb-18liAKmgeMdDF41VVn0ZEAVLP8hR33oacQ1zs,4930
3
+ runnable/cli.py,sha256=01zmzOdynEmLI4vWDtSHQ6y1od_Jlc8G1RF69fi2L8g,8446
4
+ runnable/context.py,sha256=pLw_n_5U-FM8-9-41YnkzETX94KrBAZWjxPgjm0O7hk,1305
5
+ runnable/datastore.py,sha256=a1pT_P8TNcqQB-di2_uga7y-zS3TqUCb7sFhdxmVKGY,31907
6
+ runnable/defaults.py,sha256=3o9IVGryyCE6PoQTOoaIaHHTbJGEzmdXMcwzOhwAYoI,3518
7
+ runnable/entrypoints.py,sha256=67gPBiIIS4Kd9g6LdoGCraRJPda8K1i7Lp7XcD2iY5k,18913
8
+ runnable/exceptions.py,sha256=LFbp0-Qxg2PAMLEVt7w2whhBxSG-5pzUEv5qN-Rc4_c,3003
9
+ runnable/executor.py,sha256=cS30EC2Pfz8OzzEVcUYrVIyvGboKVUw5jKG2l72-UfM,15606
10
+ runnable/graph.py,sha256=jVjikRLR-so3b2ufmNKpEQ_Ny68qN4bcGDAdXBRKiCY,16574
11
+ runnable/names.py,sha256=vn92Kv9ANROYSZX6Z4z1v_WA3WiEdIYmG6KEStBFZug,8134
12
+ runnable/nodes.py,sha256=YU9u7r1ESzui1uVtJ1dgwdv1ozyJnF2k-MCFieT8CLI,17519
13
+ runnable/parameters.py,sha256=g_bJurLjuppFDiDpfFqy6BRF36o_EY0OC5APl7HJFok,5450
14
+ runnable/pickler.py,sha256=ydJ_eti_U1F4l-YacFp7BWm6g5vTn04UXye25S1HVok,2684
15
+ runnable/sdk.py,sha256=hwdk2dLmJsOTs2GnOlayw8WfliyeZFpA6Tcnp3tgblg,33370
16
+ runnable/secrets.py,sha256=PXcEJw-4WPzeWRLfsatcPPyr1zkqgHzdRWRcS9vvpvM,2354
17
+ runnable/tasks.py,sha256=JnIIYQf3YUidHXIN6hiUIfDnegc7_rJMNXuHW4WS9ig,29378
18
+ runnable/utils.py,sha256=wqyN7lMW56cBqyE59iDE6_i2HXPkvEUCQ-66UQnIwTA,19993
19
+ runnable-0.16.0.dist-info/METADATA,sha256=JMu8mSsxMWr_wF246saRXV80D8_8cXMOPZrK6Pr9X6k,10102
20
+ runnable-0.16.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
21
+ runnable-0.16.0.dist-info/entry_points.txt,sha256=I92DYldRrCb9HCsoum8GjC2UsQrWpuw2kawXTZpkIz4,1559
22
+ runnable-0.16.0.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
23
+ runnable-0.16.0.dist-info/RECORD,,
@@ -1,16 +1,14 @@
1
1
  [console_scripts]
2
- runnable = runnable.cli:cli
2
+ runnable = runnable.cli:app
3
3
 
4
4
  [catalog]
5
5
  do-nothing = runnable.catalog:DoNothingCatalog
6
6
  file-system = extensions.catalog.file_system:FileSystemCatalog
7
7
 
8
- [executor]
9
- argo = extensions.executor.argo:ArgoExecutor
10
- local = extensions.executor.local:LocalExecutor
11
- local-container = extensions.executor.local_container:LocalContainerExecutor
12
- mocked = extensions.executor.mocked:MockedExecutor
13
- retry = extensions.executor.retry:RetryExecutor
8
+ [job_executor]
9
+ k8s-job = extensions.job_executor.k8s:K8sJobExecutor
10
+ local = extensions.job_executor.local:LocalJobExecutor
11
+ local-container = extensions.job_executor.local_container:LocalContainerJobExecutor
14
12
 
15
13
  [nodes]
16
14
  dag = extensions.nodes.nodes:DagNode
@@ -24,6 +22,13 @@ task = extensions.nodes.nodes:TaskNode
24
22
  [pickler]
25
23
  pickle = runnable.pickler:NativePickler
26
24
 
25
+ [pipeline_executor]
26
+ argo = extensions.pipeline_executor.argo:ArgoExecutor
27
+ local = extensions.pipeline_executor.local:LocalExecutor
28
+ local-container = extensions.pipeline_executor.local_container:LocalContainerExecutor
29
+ mocked = extensions.pipeline_executor.mocked:MockedExecutor
30
+ retry = extensions.pipeline_executor.retry:RetryExecutor
31
+
27
32
  [run_log_store]
28
33
  buffered = runnable.datastore:BufferRunLogstore
29
34
  chunked-fs = extensions.run_log_store.chunked_fs:ChunkedFileSystemRunLogStore
runnable/integration.py DELETED
@@ -1,197 +0,0 @@
1
- import logging
2
-
3
- from stevedore import extension
4
-
5
- from runnable import defaults
6
- from runnable.executor import BaseExecutor
7
-
8
- logger = logging.getLogger(defaults.LOGGER_NAME)
9
- logging.getLogger("stevedore").setLevel(logging.CRITICAL)
10
-
11
- # --8<-- [start:docs]
12
-
13
-
14
- class BaseIntegration:
15
- """
16
- Base class for handling integration between Executor and one of Catalog, Secrets, RunLogStore.
17
- """
18
-
19
- executor_type = ""
20
- service_type = "" # One of secret, catalog, datastore, experiment tracker
21
- service_provider = "" # The actual implementation of the service
22
-
23
- def __init__(self, executor: "BaseExecutor", integration_service: object):
24
- self.executor = executor
25
- self.service = integration_service
26
-
27
- def validate(self, **kwargs):
28
- """
29
- Raise an exception if the executor_type is not compatible with service provider.
30
-
31
- By default, it is considered as compatible.
32
- """
33
-
34
- def configure_for_traversal(self, **kwargs):
35
- """
36
- Do any changes needed to both executor and service provider during traversal of the graph.
37
-
38
- By default, no change is required.
39
- """
40
-
41
- def configure_for_execution(self, **kwargs):
42
- """
43
- Do any changes needed to both executor and service provider during execution of a node.
44
-
45
- By default, no change is required.
46
- """
47
-
48
-
49
- # --8<-- [end:docs]
50
-
51
-
52
- def get_integration_handler(
53
- executor: "BaseExecutor", service: object
54
- ) -> BaseIntegration:
55
- """
56
- Return the integration handler between executor and the service.
57
-
58
- If none found to be implemented, return the BaseIntegration which does nothing.
59
-
60
- Args:
61
- executor (BaseExecutor): The executor
62
- service (object): The service provider
63
-
64
- Returns:
65
- [BaseIntegration]: The implemented integration handler or BaseIntegration if none found
66
-
67
- Raises:
68
- Exception: If multiple integrations are found for the executor and service
69
- """
70
- service_type = service.service_type # type: ignore
71
- service_name = getattr(service, "service_name")
72
- integrations = []
73
-
74
- # Get all the integrations defined by the 3rd party in their pyproject.toml
75
- mgr = extension.ExtensionManager(
76
- namespace="integration",
77
- invoke_on_load=True,
78
- invoke_kwds={"executor": executor, "integration_service": service},
79
- )
80
- for _, kls in mgr.items():
81
- if (
82
- kls.obj.executor_type == executor.service_name
83
- and kls.obj.service_type == service_type
84
- and kls.obj.service_provider == service_name
85
- ):
86
- logger.info(f"Identified an integration pattern {kls.obj}")
87
- integrations.append(kls.obj)
88
-
89
- # Get all the implementations defined by the runnable package
90
- for kls in BaseIntegration.__subclasses__():
91
- # Match the exact service type
92
- if kls.service_type == service_type and kls.service_provider == service_name:
93
- # Match either all executor or specific ones provided
94
- if kls.executor_type == "" or kls.executor_type == executor.service_name:
95
- integrations.append(kls(executor=executor, integration_service=service))
96
-
97
- if len(integrations) > 1:
98
- msg = (
99
- f"Multiple integrations between {executor.service_name} and {service_name} of type {service_type} found. "
100
- "If you defined an integration pattern, please ensure it is specific and does not conflict with runnable "
101
- " implementations."
102
- )
103
- logger.exception(msg)
104
- raise Exception(msg)
105
-
106
- if not integrations:
107
- logger.info(
108
- f"Could not find an integration pattern for {executor.service_name} and {service_name} for {service_type}."
109
- " This implies that there is no need to change the configurations."
110
- )
111
- return BaseIntegration(executor, service)
112
-
113
- return integrations[0]
114
-
115
-
116
- def validate(executor: "BaseExecutor", service: object, **kwargs):
117
- """
118
- Helper function to resolve the Integration class and validate the compatibility between executor and service
119
-
120
- Args:
121
- executor (BaseExecutor) : The executor
122
- service (object): The service provider
123
- """
124
- integration_handler = get_integration_handler(executor, service)
125
- integration_handler.validate(**kwargs)
126
-
127
-
128
- def configure_for_traversal(executor: "BaseExecutor", service: object, **kwargs):
129
- """
130
- Helper function to resolve the Integration class and configure the executor and service for graph traversal
131
-
132
- Args:
133
- executor (BaseExecutor) : The executor
134
- service (object): The service provider
135
- """
136
- integration_handler = get_integration_handler(executor, service)
137
- integration_handler.configure_for_traversal(**kwargs)
138
-
139
-
140
- def configure_for_execution(executor: "BaseExecutor", service: object, **kwargs):
141
- """
142
- Helper function to resolve the Integration class and configure the executor and service for execution
143
-
144
- Args:
145
- executor (BaseExecutor) : The executor
146
- service (object): The service provider
147
- """
148
- integration_handler = get_integration_handler(executor, service)
149
- integration_handler.configure_for_execution(**kwargs)
150
-
151
-
152
- # TODO: Move all of these to the proper locations
153
- class BufferedRunLogStore(BaseIntegration):
154
- """
155
- Integration between any executor and buffered run log store
156
- """
157
-
158
- service_type = "run_log_store" # One of secret, catalog, datastore
159
- service_provider = "buffered" # The actual implementation of the service
160
-
161
- def validate(self, **kwargs):
162
- if not self.executor.service_name == "local":
163
- raise Exception(
164
- "Buffered run log store is only supported for local executor"
165
- )
166
-
167
- msg = (
168
- "Run log generated by buffered run log store are not persisted. "
169
- "Re-running this run, in case of a failure, is not possible"
170
- )
171
- logger.info(msg)
172
-
173
-
174
- class DoNothingCatalog(BaseIntegration):
175
- """
176
- Integration between any executor and do nothing catalog
177
- """
178
-
179
- service_type = "catalog" # One of secret, catalog, datastore
180
- service_provider = "do-nothing" # The actual implementation of the service
181
-
182
- def validate(self, **kwargs):
183
- msg = "A do-nothing catalog does not hold any data and therefore cannot pass data between nodes."
184
- logger.info(msg)
185
-
186
-
187
- class DoNothingSecrets(BaseIntegration):
188
- """
189
- Integration between any executor and do nothing secrets
190
- """
191
-
192
- service_type = "secrets" # One of secret, catalog, datastore
193
- service_provider = "do-nothing" # The actual implementation of the service
194
-
195
- def validate(self, **kwargs):
196
- msg = "A do-nothing secrets does not hold any secrets and therefore cannot return you any secrets."
197
- logger.info(msg)
@@ -1,24 +0,0 @@
1
- runnable/__init__.py,sha256=WuJwXEBxjiz2E1jBapkOkYpIaCAPZ1Udyep0dnN4bkE,666
2
- runnable/catalog.py,sha256=5eTYwZWqfVBXIIn8WbweTMqiXZ9ccvtJBnAiIxSQ3Vk,4835
3
- runnable/cli.py,sha256=rBTvkNDetN6psHmDLa0kko8IHGvND5xMuO30hU_gcvY,9931
4
- runnable/context.py,sha256=QhiXJHRcEBfSKB1ijvL5yB9w44x0HCe7VEiwK1cUJ9U,1124
5
- runnable/datastore.py,sha256=Q_KKb4PNP2IXnUlR2bjOclDFAsAVJ_oNiCd5x0vB5jc,28127
6
- runnable/defaults.py,sha256=HYkXNI2hg0Y-SsXySjliwdc-3FUGJvJV3TnarmMIFFs,4656
7
- runnable/entrypoints.py,sha256=gMywHyoUheSAXCyqLMJ0QWK4IxiFVgEYwRDuZWsk-uI,18612
8
- runnable/exceptions.py,sha256=3gyN2bhqYvaZF_bo8hA7I09u8aQCAeh8NclBp5lCH8w,2574
9
- runnable/executor.py,sha256=Y-yCw4ZIz88nHn47QzCXvXm7VjByTIyBWzsqsaIpNP8,14653
10
- runnable/graph.py,sha256=EuH0210DcbEFlc6J-aSvfXJOb0SqORUiTpgFYyb_KPM,16602
11
- runnable/integration.py,sha256=IXBH20QKpFYW7pQwwbTI0qQvrg4kJseM0KMacQKli74,6791
12
- runnable/names.py,sha256=vn92Kv9ANROYSZX6Z4z1v_WA3WiEdIYmG6KEStBFZug,8134
13
- runnable/nodes.py,sha256=I9C65nj3kAHHXJSwn5QYximFjV7tbjBiTk0ayEgrmK4,16526
14
- runnable/parameters.py,sha256=g_bJurLjuppFDiDpfFqy6BRF36o_EY0OC5APl7HJFok,5450
15
- runnable/pickler.py,sha256=ydJ_eti_U1F4l-YacFp7BWm6g5vTn04UXye25S1HVok,2684
16
- runnable/sdk.py,sha256=tEwTwcfm1KVfnEql3G_yJpgymDWOqoIIA4q3RzKmHp0,30365
17
- runnable/secrets.py,sha256=PXcEJw-4WPzeWRLfsatcPPyr1zkqgHzdRWRcS9vvpvM,2354
18
- runnable/tasks.py,sha256=QPCgH_D7YkN2oAi7-w6Ipt9IZ397SayjhAl_PPyVto8,29822
19
- runnable/utils.py,sha256=THMHnWVrUhNKdIvUbeZdDiXnP1WEOuee9e9OB8zzW5M,20441
20
- runnable-0.14.0.dist-info/METADATA,sha256=n3mrLZadanBuHaUz4h5WgtsfuXmkjaHdtsfOCSAmEEk,9994
21
- runnable-0.14.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
22
- runnable-0.14.0.dist-info/entry_points.txt,sha256=8yBeduXOnO3SUnafZQwzXiE8rQMPXGDbqueyL7G9euM,1297
23
- runnable-0.14.0.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
24
- runnable-0.14.0.dist-info/RECORD,,