polyaxon 2.4.0rc1__py3-none-any.whl → 2.6.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.
Files changed (218) hide show
  1. polyaxon/_auxiliaries/default_scheduling.py +17 -7
  2. polyaxon/_auxiliaries/init.py +14 -6
  3. polyaxon/_auxiliaries/sidecar.py +10 -8
  4. polyaxon/_cli/dashboard.py +2 -5
  5. polyaxon/_cli/run.py +14 -0
  6. polyaxon/_cli/version.py +4 -1
  7. polyaxon/_compiler/contexts/contexts.py +4 -0
  8. polyaxon/_compiler/resolver/agent.py +10 -9
  9. polyaxon/_compiler/resolver/runtime.py +4 -0
  10. polyaxon/_constants/metadata.py +1 -0
  11. polyaxon/_contexts/keys.py +1 -0
  12. polyaxon/_deploy/schemas/auth.py +3 -3
  13. polyaxon/_deploy/schemas/celery.py +10 -8
  14. polyaxon/_deploy/schemas/deployment.py +148 -116
  15. polyaxon/_deploy/schemas/email.py +8 -8
  16. polyaxon/_deploy/schemas/ingress.py +7 -7
  17. polyaxon/_deploy/schemas/intervals.py +3 -1
  18. polyaxon/_deploy/schemas/operators.py +8 -8
  19. polyaxon/_deploy/schemas/proxy.py +9 -9
  20. polyaxon/_deploy/schemas/rbac.py +1 -1
  21. polyaxon/_deploy/schemas/root_user.py +5 -5
  22. polyaxon/_deploy/schemas/security_context.py +25 -15
  23. polyaxon/_deploy/schemas/service.py +73 -69
  24. polyaxon/_deploy/schemas/ssl.py +3 -3
  25. polyaxon/_deploy/schemas/ui.py +10 -6
  26. polyaxon/_docker/builder/builder.py +4 -1
  27. polyaxon/_docker/converter/base/containers.py +4 -7
  28. polyaxon/_docker/converter/base/env_vars.py +5 -5
  29. polyaxon/_docker/converter/base/mounts.py +2 -2
  30. polyaxon/_docker/docker_types.py +57 -30
  31. polyaxon/_env_vars/keys.py +2 -0
  32. polyaxon/_flow/__init__.py +3 -2
  33. polyaxon/_flow/builds/__init__.py +8 -8
  34. polyaxon/_flow/cache/__init__.py +4 -4
  35. polyaxon/_flow/component/base.py +25 -18
  36. polyaxon/_flow/component/component.py +4 -3
  37. polyaxon/_flow/early_stopping/__init__.py +1 -1
  38. polyaxon/_flow/early_stopping/policies.py +12 -10
  39. polyaxon/_flow/environment/__init__.py +42 -24
  40. polyaxon/_flow/events/__init__.py +1 -1
  41. polyaxon/_flow/hooks/__init__.py +11 -11
  42. polyaxon/_flow/init/__init__.py +41 -25
  43. polyaxon/_flow/io/io.py +57 -47
  44. polyaxon/_flow/joins/__init__.py +5 -5
  45. polyaxon/_flow/matrix/bayes.py +23 -17
  46. polyaxon/_flow/matrix/grid_search.py +16 -7
  47. polyaxon/_flow/matrix/hyperband.py +10 -10
  48. polyaxon/_flow/matrix/hyperopt.py +14 -9
  49. polyaxon/_flow/matrix/iterative.py +14 -8
  50. polyaxon/_flow/matrix/mapping.py +4 -4
  51. polyaxon/_flow/matrix/params.py +138 -77
  52. polyaxon/_flow/matrix/random_search.py +10 -5
  53. polyaxon/_flow/matrix/tuner.py +4 -4
  54. polyaxon/_flow/mounts/artifacts_mounts.py +1 -1
  55. polyaxon/_flow/notifications/__init__.py +1 -1
  56. polyaxon/_flow/operations/base.py +10 -8
  57. polyaxon/_flow/operations/compiled_operation.py +5 -4
  58. polyaxon/_flow/operations/operation.py +30 -22
  59. polyaxon/_flow/optimization/__init__.py +2 -2
  60. polyaxon/_flow/params/params.py +10 -9
  61. polyaxon/_flow/plugins/__init__.py +19 -13
  62. polyaxon/_flow/run/dag.py +12 -9
  63. polyaxon/_flow/run/dask/dask.py +4 -4
  64. polyaxon/_flow/run/dask/replica.py +17 -11
  65. polyaxon/_flow/run/job.py +17 -11
  66. polyaxon/_flow/run/kubeflow/mpi_job.py +10 -5
  67. polyaxon/_flow/run/kubeflow/mx_job.py +25 -9
  68. polyaxon/_flow/run/kubeflow/paddle_job.py +16 -9
  69. polyaxon/_flow/run/kubeflow/pytorch_job.py +24 -17
  70. polyaxon/_flow/run/kubeflow/replica.py +17 -11
  71. polyaxon/_flow/run/kubeflow/scheduling_policy.py +7 -5
  72. polyaxon/_flow/run/kubeflow/tf_job.py +15 -8
  73. polyaxon/_flow/run/kubeflow/xgboost_job.py +9 -4
  74. polyaxon/_flow/run/ray/ray.py +9 -6
  75. polyaxon/_flow/run/ray/replica.py +25 -16
  76. polyaxon/_flow/run/resources.py +14 -13
  77. polyaxon/_flow/run/service.py +4 -4
  78. polyaxon/_flow/schedules/cron.py +4 -4
  79. polyaxon/_flow/schedules/interval.py +4 -4
  80. polyaxon/_flow/templates/__init__.py +3 -3
  81. polyaxon/_flow/termination/__init__.py +3 -3
  82. polyaxon/_fs/async_manager.py +1 -1
  83. polyaxon/_fs/watcher.py +26 -27
  84. polyaxon/_k8s/k8s_validation.py +1 -1
  85. polyaxon/_k8s/logging/async_monitor.py +18 -3
  86. polyaxon/_local_process/converter/base/containers.py +4 -7
  87. polyaxon/_local_process/converter/base/env_vars.py +5 -5
  88. polyaxon/_local_process/process_types.py +15 -12
  89. polyaxon/_polyaxonfile/specs/compiled_operation.py +1 -1
  90. polyaxon/_polyaxonfile/specs/libs/parser.py +1 -1
  91. polyaxon/_polyaxonfile/specs/libs/validator.py +1 -1
  92. polyaxon/_polyaxonfile/specs/operation.py +1 -1
  93. polyaxon/_polyaxonfile/specs/sections.py +8 -0
  94. polyaxon/_runner/agent/async_agent.py +9 -6
  95. polyaxon/_runner/agent/base_agent.py +8 -5
  96. polyaxon/_runner/agent/sync_agent.py +8 -5
  97. polyaxon/_runner/converter/converter.py +12 -4
  98. polyaxon/_schemas/agent.py +69 -37
  99. polyaxon/_schemas/authentication.py +4 -4
  100. polyaxon/_schemas/base.py +26 -2
  101. polyaxon/_schemas/checks.py +3 -3
  102. polyaxon/_schemas/cli.py +4 -6
  103. polyaxon/_schemas/client.py +20 -18
  104. polyaxon/_schemas/compatibility.py +4 -4
  105. polyaxon/_schemas/container_resources.py +1 -1
  106. polyaxon/_schemas/home.py +3 -3
  107. polyaxon/_schemas/installation.py +13 -9
  108. polyaxon/_schemas/lifecycle.py +23 -23
  109. polyaxon/_schemas/log_handler.py +2 -2
  110. polyaxon/_schemas/services.py +26 -14
  111. polyaxon/_schemas/types/artifacts.py +3 -3
  112. polyaxon/_schemas/types/dockerfile.py +14 -12
  113. polyaxon/_schemas/types/event.py +2 -2
  114. polyaxon/_schemas/types/file.py +3 -3
  115. polyaxon/_schemas/types/git.py +12 -4
  116. polyaxon/_schemas/types/tensorboard.py +14 -8
  117. polyaxon/_schemas/user.py +3 -3
  118. polyaxon/_schemas/version.py +2 -2
  119. polyaxon/_sdk/api/agents_v1_api.py +45 -45
  120. polyaxon/_sdk/api/artifacts_stores_v1_api.py +3 -3
  121. polyaxon/_sdk/api/auth_v1_api.py +13 -13
  122. polyaxon/_sdk/api/connections_v1_api.py +15 -15
  123. polyaxon/_sdk/api/dashboards_v1_api.py +15 -15
  124. polyaxon/_sdk/api/organizations_v1_api.py +77 -77
  125. polyaxon/_sdk/api/presets_v1_api.py +15 -15
  126. polyaxon/_sdk/api/project_dashboards_v1_api.py +17 -17
  127. polyaxon/_sdk/api/project_searches_v1_api.py +17 -17
  128. polyaxon/_sdk/api/projects_v1_api.py +65 -65
  129. polyaxon/_sdk/api/queues_v1_api.py +19 -19
  130. polyaxon/_sdk/api/runs_v1_api.py +127 -127
  131. polyaxon/_sdk/api/searches_v1_api.py +15 -15
  132. polyaxon/_sdk/api/service_accounts_v1_api.py +27 -27
  133. polyaxon/_sdk/api/tags_v1_api.py +17 -17
  134. polyaxon/_sdk/api/teams_v1_api.py +51 -51
  135. polyaxon/_sdk/api/users_v1_api.py +25 -25
  136. polyaxon/_sdk/api/versions_v1_api.py +7 -7
  137. polyaxon/_sdk/schemas/v1_activity.py +8 -8
  138. polyaxon/_sdk/schemas/v1_agent.py +17 -16
  139. polyaxon/_sdk/schemas/v1_agent_state_response.py +4 -4
  140. polyaxon/_sdk/schemas/v1_agent_state_response_agent_state.py +10 -10
  141. polyaxon/_sdk/schemas/v1_agent_status_body_request.py +3 -3
  142. polyaxon/_sdk/schemas/v1_analytics_spec.py +4 -4
  143. polyaxon/_sdk/schemas/v1_artifact_tree.py +3 -3
  144. polyaxon/_sdk/schemas/v1_auth.py +1 -1
  145. polyaxon/_sdk/schemas/v1_cloning.py +3 -3
  146. polyaxon/_sdk/schemas/v1_connection_response.py +9 -9
  147. polyaxon/_sdk/schemas/v1_dashboard.py +9 -9
  148. polyaxon/_sdk/schemas/v1_dashboard_spec.py +5 -5
  149. polyaxon/_sdk/schemas/v1_entities_tags.py +2 -2
  150. polyaxon/_sdk/schemas/v1_entities_transfer.py +2 -2
  151. polyaxon/_sdk/schemas/v1_entity_notification_body.py +7 -7
  152. polyaxon/_sdk/schemas/v1_entity_stage_body_request.py +5 -5
  153. polyaxon/_sdk/schemas/v1_entity_status_body_request.py +5 -5
  154. polyaxon/_sdk/schemas/v1_events_response.py +2 -2
  155. polyaxon/_sdk/schemas/v1_list_activities_response.py +4 -4
  156. polyaxon/_sdk/schemas/v1_list_agents_response.py +4 -4
  157. polyaxon/_sdk/schemas/v1_list_bookmarks_response.py +4 -4
  158. polyaxon/_sdk/schemas/v1_list_connections_response.py +4 -4
  159. polyaxon/_sdk/schemas/v1_list_dashboards_response.py +4 -4
  160. polyaxon/_sdk/schemas/v1_list_organization_members_response.py +4 -4
  161. polyaxon/_sdk/schemas/v1_list_organizations_response.py +4 -4
  162. polyaxon/_sdk/schemas/v1_list_presets_response.py +4 -4
  163. polyaxon/_sdk/schemas/v1_list_project_versions_response.py +4 -4
  164. polyaxon/_sdk/schemas/v1_list_projects_response.py +4 -4
  165. polyaxon/_sdk/schemas/v1_list_queues_response.py +4 -4
  166. polyaxon/_sdk/schemas/v1_list_run_artifacts_response.py +4 -4
  167. polyaxon/_sdk/schemas/v1_list_run_connections_response.py +4 -4
  168. polyaxon/_sdk/schemas/v1_list_run_edges_response.py +4 -4
  169. polyaxon/_sdk/schemas/v1_list_runs_response.py +4 -4
  170. polyaxon/_sdk/schemas/v1_list_searches_response.py +4 -4
  171. polyaxon/_sdk/schemas/v1_list_service_accounts_response.py +4 -4
  172. polyaxon/_sdk/schemas/v1_list_tags_response.py +4 -4
  173. polyaxon/_sdk/schemas/v1_list_team_members_response.py +4 -4
  174. polyaxon/_sdk/schemas/v1_list_teams_response.py +4 -4
  175. polyaxon/_sdk/schemas/v1_list_token_response.py +4 -4
  176. polyaxon/_sdk/schemas/v1_operation_body.py +8 -8
  177. polyaxon/_sdk/schemas/v1_organization.py +16 -16
  178. polyaxon/_sdk/schemas/v1_organization_member.py +6 -6
  179. polyaxon/_sdk/schemas/v1_password_change.py +3 -3
  180. polyaxon/_sdk/schemas/v1_pipeline.py +3 -3
  181. polyaxon/_sdk/schemas/v1_preset.py +11 -12
  182. polyaxon/_sdk/schemas/v1_project.py +17 -17
  183. polyaxon/_sdk/schemas/v1_project_settings.py +11 -11
  184. polyaxon/_sdk/schemas/v1_project_version.py +20 -20
  185. polyaxon/_sdk/schemas/v1_queue.py +12 -12
  186. polyaxon/_sdk/schemas/v1_run.py +38 -38
  187. polyaxon/_sdk/schemas/v1_run_connection.py +3 -3
  188. polyaxon/_sdk/schemas/v1_run_edge.py +5 -5
  189. polyaxon/_sdk/schemas/v1_run_edge_lineage.py +3 -3
  190. polyaxon/_sdk/schemas/v1_run_edges_graph.py +1 -1
  191. polyaxon/_sdk/schemas/v1_run_reference_catalog.py +4 -4
  192. polyaxon/_sdk/schemas/v1_run_settings.py +9 -9
  193. polyaxon/_sdk/schemas/v1_search.py +10 -10
  194. polyaxon/_sdk/schemas/v1_search_spec.py +14 -14
  195. polyaxon/_sdk/schemas/v1_section_spec.py +12 -12
  196. polyaxon/_sdk/schemas/v1_service_account.py +9 -9
  197. polyaxon/_sdk/schemas/v1_settings_catalog.py +4 -4
  198. polyaxon/_sdk/schemas/v1_tag.py +6 -6
  199. polyaxon/_sdk/schemas/v1_team.py +11 -11
  200. polyaxon/_sdk/schemas/v1_team_member.py +6 -6
  201. polyaxon/_sdk/schemas/v1_team_settings.py +2 -2
  202. polyaxon/_sdk/schemas/v1_token.py +10 -10
  203. polyaxon/_sdk/schemas/v1_trial_start.py +6 -6
  204. polyaxon/_sdk/schemas/v1_user.py +6 -6
  205. polyaxon/_sdk/schemas/v1_user_access.py +7 -7
  206. polyaxon/_sdk/schemas/v1_user_email.py +1 -1
  207. polyaxon/_sdk/schemas/v1_user_singup.py +5 -5
  208. polyaxon/_sdk/schemas/v1_uuids.py +1 -1
  209. polyaxon/_sidecar/container/__init__.py +13 -8
  210. polyaxon/_utils/cli_constants.py +2 -0
  211. polyaxon/_utils/test_utils.py +2 -1
  212. polyaxon/pkg.py +1 -1
  213. {polyaxon-2.4.0rc1.dist-info → polyaxon-2.6.0.dist-info}/METADATA +13 -13
  214. {polyaxon-2.4.0rc1.dist-info → polyaxon-2.6.0.dist-info}/RECORD +218 -218
  215. {polyaxon-2.4.0rc1.dist-info → polyaxon-2.6.0.dist-info}/WHEEL +1 -1
  216. {polyaxon-2.4.0rc1.dist-info → polyaxon-2.6.0.dist-info}/LICENSE +0 -0
  217. {polyaxon-2.4.0rc1.dist-info → polyaxon-2.6.0.dist-info}/entry_points.txt +0 -0
  218. {polyaxon-2.4.0rc1.dist-info → polyaxon-2.6.0.dist-info}/top_level.txt +0 -0
@@ -117,12 +117,17 @@ class V1XGBoostJob(BaseRun, DestinationImageMixin):
117
117
  """
118
118
 
119
119
  _IDENTIFIER = V1RunKind.XGBJOB
120
+ _CUSTOM_DUMP_FIELDS = {"master", "worker"}
120
121
 
121
122
  kind: Literal[_IDENTIFIER] = _IDENTIFIER
122
- clean_pod_policy: Optional[V1CleanPodPolicy] = Field(alias="cleanPodPolicy")
123
- scheduling_policy: Optional[V1SchedulingPolicy] = Field(alias="schedulingPolicy")
124
- master: Optional[Union[V1KFReplica, RefField]]
125
- worker: Optional[Union[V1KFReplica, RefField]]
123
+ clean_pod_policy: Optional[V1CleanPodPolicy] = Field(
124
+ alias="cleanPodPolicy", default=None
125
+ )
126
+ scheduling_policy: Optional[V1SchedulingPolicy] = Field(
127
+ alias="schedulingPolicy", default=None
128
+ )
129
+ master: Optional[Union[V1KFReplica, RefField]] = None
130
+ worker: Optional[Union[V1KFReplica, RefField]] = None
126
131
 
127
132
  def apply_image_destination(self, image: str):
128
133
  if self.chief:
@@ -135,14 +135,17 @@ class V1RayJob(BaseRun, DestinationImageMixin):
135
135
  """
136
136
 
137
137
  _IDENTIFIER = V1RunKind.RAYJOB
138
+ _CUSTOM_DUMP_FIELDS = {"head", "workers"}
138
139
 
139
140
  kind: Literal[_IDENTIFIER] = _IDENTIFIER
140
- entrypoint: Optional[str]
141
- runtime_env: Optional[Union[Dict[str, Any], RefField]] = Field(alias="runtimeEnv")
142
- metadata: Optional[Union[Dict[str, str], RefField]]
143
- ray_version: Optional[str] = Field(alias="rayVersion")
144
- head: Optional[Union[V1RayReplica, RefField]]
145
- workers: Optional[Dict[str, Union[V1RayReplica, RefField]]]
141
+ entrypoint: Optional[str] = None
142
+ runtime_env: Optional[Union[Dict[str, Any], RefField]] = Field(
143
+ alias="runtimeEnv", default=None
144
+ )
145
+ metadata: Optional[Union[Dict[str, str], RefField]] = Field(default=None)
146
+ ray_version: Optional[str] = Field(alias="rayVersion", default=None)
147
+ head: Optional[Union[V1RayReplica, RefField]] = None
148
+ workers: Optional[Dict[str, Union[V1RayReplica, RefField]]] = Field(default=None)
146
149
 
147
150
  def apply_image_destination(self, image: str):
148
151
  if self.head:
@@ -1,6 +1,12 @@
1
1
  from typing import Dict, List, Optional, Union
2
2
 
3
- from clipped.compact.pydantic import Field, StrictStr, validator
3
+ from clipped.compact.pydantic import (
4
+ Field,
5
+ StrictStr,
6
+ field_validator,
7
+ validation_always,
8
+ validation_before,
9
+ )
4
10
  from clipped.types.ref_or_obj import IntOrRef, RefField
5
11
 
6
12
  from polyaxon._flow.environment import V1Environment
@@ -210,31 +216,34 @@ class V1RayReplica(BaseSchemaModel):
210
216
 
211
217
  _IDENTIFIER = "replica"
212
218
  _SWAGGER_FIELDS = ["volumes", "sidecars", "container"]
213
-
214
- replicas: Optional[IntOrRef]
215
- min_replicas: Optional[IntOrRef] = Field(alias="minReplicas")
216
- max_replicas: Optional[IntOrRef] = Field(alias="maxReplicas")
217
- ray_start_params: Optional[Dict[str, str]] = Field(alias="rayStartParams")
218
- environment: Optional[Union[V1Environment, RefField]]
219
- connections: Optional[Union[List[StrictStr], RefField]]
220
- volumes: Optional[Union[List[k8s_schemas.V1Volume], RefField]]
221
- init: Optional[Union[List[V1Init], RefField]]
222
- sidecars: Optional[Union[List[k8s_schemas.V1Container], RefField]]
223
- container: Optional[Union[k8s_schemas.V1Container, RefField]]
224
-
225
- @validator("volumes", always=True, pre=True)
219
+ _CUSTOM_DUMP_FIELDS = {"environment"}
220
+
221
+ replicas: Optional[IntOrRef] = None
222
+ min_replicas: Optional[IntOrRef] = Field(alias="minReplicas", default=None)
223
+ max_replicas: Optional[IntOrRef] = Field(alias="maxReplicas", default=None)
224
+ ray_start_params: Optional[Dict[str, str]] = Field(
225
+ alias="rayStartParams", default=None
226
+ )
227
+ environment: Optional[Union[V1Environment, RefField]] = None
228
+ connections: Optional[Union[List[StrictStr], RefField]] = None
229
+ volumes: Optional[Union[List[k8s_schemas.V1Volume], RefField]] = None
230
+ init: Optional[Union[List[V1Init], RefField]] = None
231
+ sidecars: Optional[Union[List[k8s_schemas.V1Container], RefField]] = None
232
+ container: Optional[Union[k8s_schemas.V1Container, RefField]] = None
233
+
234
+ @field_validator("volumes", **validation_always, **validation_before)
226
235
  def validate_volumes(cls, v):
227
236
  if not v:
228
237
  return v
229
238
  return [k8s_validation.validate_k8s_volume(vi) for vi in v]
230
239
 
231
- @validator("sidecars", always=True, pre=True)
240
+ @field_validator("sidecars", **validation_always, **validation_before)
232
241
  def validate_helper_containers(cls, v):
233
242
  if not v:
234
243
  return v
235
244
  return [k8s_validation.validate_k8s_container(vi) for vi in v]
236
245
 
237
- @validator("container", always=True, pre=True)
246
+ @field_validator("container", **validation_always, **validation_before)
238
247
  def validate_container(cls, v):
239
248
  return k8s_validation.validate_k8s_container(v)
240
249
 
@@ -1,4 +1,4 @@
1
- from typing import Optional, Union
1
+ from typing import ClassVar, Optional, Set, Union
2
2
 
3
3
  from clipped.compact.pydantic import StrictStr
4
4
  from clipped.types.numbers import StrictIntOrFloat
@@ -9,18 +9,19 @@ from polyaxon._schemas.base import BaseSchemaModel
9
9
 
10
10
 
11
11
  class V1RunResources(BaseSchemaModel):
12
- cpu: Optional[Union[StrictIntOrFloat, StrictStr]]
13
- memory: Optional[Union[StrictIntOrFloat, StrictStr]]
14
- gpu: Optional[Union[StrictIntOrFloat, StrictStr]]
15
- custom: Optional[Union[StrictIntOrFloat, StrictStr]]
16
- cost: Optional[Union[StrictIntOrFloat, StrictStr]]
17
-
18
- _MEMORY = "memory"
19
- _CPU = "cpu"
20
- _GPU = "gpu"
21
- _CUSTOM_RESOURCE = "custom"
22
- _COST = "cost"
23
- _VALUES = {_MEMORY, _CPU, _GPU, _CUSTOM_RESOURCE, _COST}
12
+ cpu: Optional[Union[StrictIntOrFloat, StrictStr]] = None
13
+ memory: Optional[Union[StrictIntOrFloat, StrictStr]] = None
14
+ gpu: Optional[Union[StrictIntOrFloat, StrictStr]] = None
15
+ custom: Optional[Union[StrictIntOrFloat, StrictStr]] = None
16
+ cost: Optional[Union[StrictIntOrFloat, StrictStr]] = None
17
+
18
+ _MEMORY: ClassVar[str] = "memory"
19
+ _CPU: ClassVar[str] = "cpu"
20
+ _GPU: ClassVar[str] = "gpu"
21
+ _CUSTOM_RESOURCE: ClassVar[str] = "custom"
22
+ _COST: ClassVar[str] = "cost"
23
+
24
+ _VALUES: ClassVar[Set[str]] = {_MEMORY, _CPU, _GPU, _CUSTOM_RESOURCE, _COST}
24
25
 
25
26
  @classmethod
26
27
  def validate_memory(cls, value):
@@ -272,7 +272,7 @@ class V1Service(V1Job):
272
272
  _IDENTIFIER = V1RunKind.SERVICE
273
273
 
274
274
  kind: Literal[_IDENTIFIER] = _IDENTIFIER
275
- ports: Optional[Union[List[StrictInt], RefField]]
276
- rewrite_path: Optional[BoolOrRef] = Field(alias="rewritePath")
277
- is_external: Optional[BoolOrRef] = Field(alias="isExternal")
278
- replicas: Optional[IntOrRef]
275
+ ports: Optional[Union[List[StrictInt], RefField]] = None
276
+ rewrite_path: Optional[BoolOrRef] = Field(alias="rewritePath", default=None)
277
+ is_external: Optional[BoolOrRef] = Field(alias="isExternal", default=None)
278
+ replicas: Optional[IntOrRef] = None
@@ -114,7 +114,7 @@ class V1CronSchedule(BaseSchemaModel):
114
114
 
115
115
  kind: Literal[_IDENTIFIER] = _IDENTIFIER
116
116
  cron: StrictStr
117
- start_at: Optional[DatetimeOrRef] = Field(alias="startAt")
118
- end_at: Optional[DatetimeOrRef] = Field(alias="endAt")
119
- max_runs: Optional[IntOrRef] = Field(alias="maxRuns")
120
- depends_on_past: Optional[BoolOrRef] = Field(alias="dependsOnPast")
117
+ start_at: Optional[DatetimeOrRef] = Field(alias="startAt", default=None)
118
+ end_at: Optional[DatetimeOrRef] = Field(alias="endAt", default=None)
119
+ max_runs: Optional[IntOrRef] = Field(alias="maxRuns", default=None)
120
+ depends_on_past: Optional[BoolOrRef] = Field(alias="dependsOnPast", default=None)
@@ -117,8 +117,8 @@ class V1IntervalSchedule(BaseSchemaModel):
117
117
  _USE_DISCRIMINATOR = True
118
118
 
119
119
  kind: Literal[_IDENTIFIER] = _IDENTIFIER
120
- start_at: Optional[DatetimeOrRef] = Field(alias="startAt")
121
- end_at: Optional[DatetimeOrRef] = Field(alias="endAt")
122
- max_runs: Optional[IntOrRef] = Field(alias="maxRuns")
120
+ start_at: Optional[DatetimeOrRef] = Field(alias="startAt", default=None)
121
+ end_at: Optional[DatetimeOrRef] = Field(alias="endAt", default=None)
122
+ max_runs: Optional[IntOrRef] = Field(alias="maxRuns", default=None)
123
123
  frequency: TimeDeltaOrRef
124
- depends_on_past: Optional[BoolOrRef] = Field(alias="dependsOnPast")
124
+ depends_on_past: Optional[BoolOrRef] = Field(alias="dependsOnPast", default=None)
@@ -80,9 +80,9 @@ class V1Template(BaseSchemaModel):
80
80
 
81
81
  _IDENTIFIER = "template"
82
82
 
83
- enabled: Optional[BoolOrRef]
84
- description: Optional[StrictStr]
85
- fields: Optional[Union[List[StrictStr], RefField]]
83
+ enabled: Optional[BoolOrRef] = None
84
+ description: Optional[StrictStr] = None
85
+ fields: Optional[Union[List[StrictStr], RefField]] = None
86
86
 
87
87
 
88
88
  class TemplateMixinConfig:
@@ -99,6 +99,6 @@ class V1Termination(BaseSchemaModel):
99
99
 
100
100
  _IDENTIFIER = "termination"
101
101
 
102
- max_retries: Optional[IntOrRef] = Field(alias="maxRetries")
103
- ttl: Optional[IntOrRef]
104
- timeout: Optional[IntOrRef]
102
+ max_retries: Optional[IntOrRef] = Field(alias="maxRetries", default=None)
103
+ ttl: Optional[IntOrRef] = None
104
+ timeout: Optional[IntOrRef] = None
@@ -314,7 +314,7 @@ async def list_files(
314
314
 
315
315
 
316
316
  async def delete_file_or_dir(
317
- fs: FSSystem, store_path: str, subpath: Union[str], is_file: bool
317
+ fs: FSSystem, store_path: str, subpath: Optional[str], is_file: bool
318
318
  ) -> bool:
319
319
  try:
320
320
  await ensure_async_execution(
polyaxon/_fs/watcher.py CHANGED
@@ -3,36 +3,43 @@ import os
3
3
  from datetime import datetime
4
4
  from typing import Dict, List, Optional, Set, Tuple
5
5
 
6
+ from clipped.compact.pydantic import PYDANTIC_VERSION
6
7
  from clipped.utils.dates import path_last_modified
7
8
  from clipped.utils.paths import get_files_and_dirs_in_path
8
9
 
9
10
  from polyaxon._contexts import paths as ctx_paths
10
- from polyaxon._schemas.base import BaseSchemaModel
11
+ from polyaxon._schemas.base import BaseSchemaModel, RootModel
11
12
 
12
13
 
13
- class PathData(BaseSchemaModel):
14
- __root__: Tuple[str, datetime, str]
14
+ class PathData(RootModel):
15
+ if PYDANTIC_VERSION.startswith("2."):
16
+ root: Tuple[str, datetime, str]
17
+ else:
18
+ __root__: Tuple[str, datetime, str]
15
19
 
16
- class Config(BaseSchemaModel.Config):
20
+ class Config:
17
21
  validate_assignment = False
18
22
 
19
23
  @property
20
24
  def base(self) -> str:
21
- return self.__root__[0]
25
+ return self.get_root()[0]
22
26
 
23
27
  @property
24
28
  def ts(self) -> datetime:
25
- if isinstance(self.__root__[1], str):
26
- self.__root__ = (
27
- self.__root__[0],
28
- datetime.fromisoformat(self.__root__[1]),
29
- self.__root__[1],
29
+ root = self.get_root()
30
+ if isinstance(root[1], str):
31
+ self.set_root(
32
+ (
33
+ root[0],
34
+ datetime.fromisoformat(root[1]),
35
+ root[1],
36
+ )
30
37
  )
31
- return self.__root__[1]
38
+ return root[1]
32
39
 
33
40
  @property
34
41
  def op(self) -> str:
35
- return self.__root__[2]
42
+ return self.get_root()[2]
36
43
 
37
44
 
38
45
  class FSWatcher(BaseSchemaModel):
@@ -42,8 +49,8 @@ class FSWatcher(BaseSchemaModel):
42
49
  _RM = "rm"
43
50
  _NOOP = ""
44
51
 
45
- dir_mapping: Optional[Dict[str, PathData]]
46
- file_mapping: Optional[Dict[str, PathData]]
52
+ dir_mapping: Optional[Dict[str, PathData]] = None
53
+ file_mapping: Optional[Dict[str, PathData]] = None
47
54
 
48
55
  @property
49
56
  def dirs_mp(self) -> Dict[str, PathData]:
@@ -71,17 +78,11 @@ class FSWatcher(BaseSchemaModel):
71
78
  data = mapping.get(rel_path)
72
79
  if data:
73
80
  if current_ts > data.ts:
74
- mapping[rel_path] = PathData.construct(
75
- __root__=(base_path, current_ts, self._PUT)
76
- )
81
+ mapping[rel_path] = PathData.make((base_path, current_ts, self._PUT))
77
82
  else:
78
- mapping[rel_path] = PathData.construct(
79
- __root__=(base_path, data.ts, self._NOOP)
80
- )
83
+ mapping[rel_path] = PathData.make((base_path, data.ts, self._NOOP))
81
84
  else:
82
- mapping[rel_path] = PathData.construct(
83
- __root__=(base_path, current_ts, self._PUT)
84
- )
85
+ mapping[rel_path] = PathData.make((base_path, current_ts, self._PUT))
85
86
  return mapping
86
87
 
87
88
  def sync_file(self, path: str, base_path: str):
@@ -92,12 +93,10 @@ class FSWatcher(BaseSchemaModel):
92
93
 
93
94
  def init(self):
94
95
  self.dir_mapping = {
95
- p: PathData.construct(__root__=(d.base, d.ts, self._RM))
96
- for p, d in self.dirs_mp.items()
96
+ p: PathData.make((d.base, d.ts, self._RM)) for p, d in self.dirs_mp.items()
97
97
  }
98
98
  self.file_mapping = {
99
- p: PathData.construct(__root__=(d.base, d.ts, self._RM))
100
- for p, d in self.files_mp.items()
99
+ p: PathData.make((d.base, d.ts, self._RM)) for p, d in self.files_mp.items()
101
100
  }
102
101
 
103
102
  def sync(self, path: str, exclude: Optional[List[str]] = None):
@@ -14,7 +14,7 @@ def _validate_schema(value: Optional[Union[Swagger, Dict]], cls: Type[Swagger]):
14
14
  return cls(**{to_snake_case(k): value[k] for k in value})
15
15
  if isinstance(value, cls):
16
16
  return value
17
- raise TypeError(
17
+ raise ValueError(
18
18
  "This field expects a dict or an instance of {}.".format(cls.__name__)
19
19
  )
20
20
 
@@ -1,4 +1,5 @@
1
1
  import datetime
2
+ import logging
2
3
 
3
4
  from typing import List, Optional, Tuple
4
5
 
@@ -10,6 +11,8 @@ from polyaxon._flow import V1RunKind
10
11
  from polyaxon._k8s.manager.async_manager import AsyncK8sManager
11
12
  from traceml.logging import V1Log, V1Logs
12
13
 
14
+ _logger = logging.getLogger("haupt.k8s.logs")
15
+
13
16
 
14
17
  async def handle_container_logs(
15
18
  k8s_manager: AsyncK8sManager, pod: V1Pod, container_name: str, **params
@@ -23,8 +26,20 @@ async def handle_container_logs(
23
26
  timestamps=True,
24
27
  **params,
25
28
  )
26
- except ApiException:
27
- pass
29
+ except ApiException as e:
30
+ _logger.warning(
31
+ "Error collecting logs for %s - container %s: %s",
32
+ pod.metadata.name,
33
+ container_name,
34
+ e,
35
+ )
36
+ except Exception as e:
37
+ _logger.warning(
38
+ "Unexpected error collecting logs for %s - container %s: %s",
39
+ pod.metadata.name,
40
+ container_name,
41
+ e,
42
+ )
28
43
  if not resp:
29
44
  return []
30
45
 
@@ -108,7 +123,7 @@ async def collect_agent_service_logs(
108
123
  async def query_k8s_pod_logs(
109
124
  k8s_manager: AsyncK8sManager,
110
125
  pod: V1Pod,
111
- last_time: Optional[datetime.datetime],
126
+ last_time: Optional[datetime.datetime] = None,
112
127
  stream: bool = False,
113
128
  ) -> Tuple[List[V1Log], Optional[datetime.datetime]]:
114
129
  new_time = now()
@@ -36,11 +36,8 @@ class ContainerMixin(BaseConverter):
36
36
  env: List[process_types.V1EnvVar],
37
37
  ) -> List[process_types.V1EnvVar]:
38
38
  def sanitize_env_dict(d: Dict):
39
- return process_types.V1EnvVar(
40
- __root__={
41
- d_k: sanitize_value(d_v, handle_dict=False)
42
- for d_k, d_v in d.items()
43
- }
39
+ return process_types.V1EnvVar.make(
40
+ {d_k: sanitize_value(d_v, handle_dict=False) for d_k, d_v in d.items()}
44
41
  )
45
42
 
46
43
  results = []
@@ -50,8 +47,8 @@ class ContainerMixin(BaseConverter):
50
47
  results.append(e)
51
48
  elif isinstance(e, tuple):
52
49
  if e[1] is not None:
53
- e = process_types.V1EnvVar(
54
- __root__=(e[0], sanitize_value(e[1], handle_dict=False))
50
+ e = process_types.V1EnvVar.make(
51
+ (e[0], sanitize_value(e[1], handle_dict=False))
55
52
  )
56
53
  results.append(e)
57
54
  elif isinstance(e, process_types.V1EnvVar):
@@ -42,7 +42,7 @@ class EnvMixin(BaseConverter):
42
42
  except (ValueError, TypeError) as e:
43
43
  raise PolyaxonConverterError(e)
44
44
 
45
- return process_types.V1EnvVar(__root__=(name, value))
45
+ return process_types.V1EnvVar.make((name, value))
46
46
 
47
47
  @staticmethod
48
48
  def _get_from_json_resource(
@@ -59,7 +59,7 @@ class EnvMixin(BaseConverter):
59
59
  except Exception as e:
60
60
  raise PolyaxonConverterError from e
61
61
 
62
- return [process_types.V1EnvVar(__root__=k) for k in (secret_value.items())]
62
+ return [process_types.V1EnvVar.make(k) for k in (secret_value.items())]
63
63
 
64
64
  @classmethod
65
65
  def _get_env_from_json_resources(
@@ -82,10 +82,10 @@ class EnvMixin(BaseConverter):
82
82
  try:
83
83
  secret_value = orjson_loads(secret)
84
84
  except orjson.JSONDecodeError:
85
- return process_types.V1EnvVar(__root__=(key, secret))
85
+ return process_types.V1EnvVar.make((key, secret))
86
86
 
87
87
  value = secret_value.get(key)
88
- return process_types.V1EnvVar(__root__=(key, value))
88
+ return process_types.V1EnvVar.make((key, value))
89
89
 
90
90
  @classmethod
91
91
  def _get_items_from_json_resource(
@@ -104,7 +104,7 @@ class EnvMixin(BaseConverter):
104
104
  for item in resource.items:
105
105
  value = secret_value.get(item)
106
106
  if value:
107
- items_from.append(process_types.V1EnvVar(__root__=(item, value)))
107
+ items_from.append(process_types.V1EnvVar.make((item, value)))
108
108
  return items_from
109
109
 
110
110
  @classmethod
@@ -1,27 +1,30 @@
1
1
  from typing import Dict, List, Optional, Tuple, Union
2
2
 
3
- from clipped.compact.pydantic import Field
3
+ from clipped.compact.pydantic import PYDANTIC_VERSION, Field
4
4
 
5
- from polyaxon._schemas.base import BaseSchemaModel
5
+ from polyaxon._schemas.base import BaseSchemaModel, RootModel
6
6
 
7
7
 
8
- class V1EnvVar(BaseSchemaModel):
9
- __root__: Union[Tuple[str, str], Dict[str, str]]
8
+ class V1EnvVar(RootModel):
9
+ if PYDANTIC_VERSION.startswith("2."):
10
+ root: Union[Tuple[str, str], Dict[str, str]]
11
+ else:
12
+ __root__: Union[Tuple[str, str], Dict[str, str]]
10
13
 
11
14
  def to_cmd(self):
12
- if isinstance(self.__root__, tuple):
13
- value = self.__root__
15
+ if isinstance(self._root, tuple):
16
+ value = self._root
14
17
  else:
15
- value = self.__root__.items()
18
+ value = self._root.items()
16
19
  return [f"{value[0]}={value[1]}"]
17
20
 
18
21
 
19
22
  class V1Container(BaseSchemaModel):
20
- name: Optional[str]
21
- command: Optional[List[str]]
22
- args: Optional[List[str]]
23
- env: Optional[List[V1EnvVar]]
24
- working_dir: Optional[str] = Field(alias="workingDir")
23
+ name: Optional[str] = None
24
+ command: Optional[List[str]] = None
25
+ args: Optional[List[str]] = None
26
+ env: Optional[List[V1EnvVar]] = None
27
+ working_dir: Optional[str] = Field(alias="workingDir", default=None)
25
28
 
26
29
  def get_cmd_args(self):
27
30
  cmd_args = ["run", "--rm"]
@@ -348,7 +348,7 @@ class CompiledOperationSpecification(BaseSpecification):
348
348
  "conditions",
349
349
  "skip_on_upstream_skip",
350
350
  }
351
- patch_keys = patch_keys.intersection(preset.__fields_set__)
351
+ patch_keys = patch_keys.intersection(preset.model_fields_set)
352
352
  patch_data = {k: getattr(preset, k) for k in patch_keys}
353
353
  patch_compiled = V1CompiledOperation.construct(**patch_data)
354
354
  return config.patch(patch_compiled, strategy=preset.patch_strategy)
@@ -93,7 +93,7 @@ class PolyaxonfileParser:
93
93
  # Check workflow
94
94
  for section in Sections.PARSING_SECTIONS:
95
95
  config_section = cls._get_section(config, section)
96
- if config_section:
96
+ if config_section is not None:
97
97
  parsed_data[section] = cls.parse_expression(
98
98
  config_section, parsed_params
99
99
  )
@@ -11,7 +11,7 @@ def validate(spec, data):
11
11
 
12
12
  def validate_keys(section, config, section_data):
13
13
  extra_args = [
14
- key for key in section_data.keys() if key not in config.__fields__.keys()
14
+ key for key in section_data.keys() if key not in config.model_fields.keys()
15
15
  ]
16
16
  if extra_args:
17
17
  raise PolyaxonfileError(
@@ -107,7 +107,7 @@ class OperationSpecification(BaseSpecification):
107
107
  "conditions",
108
108
  "skip_on_upstream_skip",
109
109
  }
110
- patch_keys = patch_keys.intersection(config.__fields_set__)
110
+ patch_keys = patch_keys.intersection(config.model_fields_set)
111
111
  patch_data = {k: getattr(config, k) for k in patch_keys}
112
112
  patch_compiled = V1CompiledOperation.construct(contexts=contexts, **patch_data)
113
113
 
@@ -99,6 +99,14 @@ class Sections:
99
99
  CONDITIONS,
100
100
  SKIP_ON_UPSTREAM_SKIP,
101
101
  PATCH_STRATEGY,
102
+ "is_approved",
103
+ "patch_strategy",
104
+ "is_preset",
105
+ "hub_ref",
106
+ "dag_ref",
107
+ "path_ref",
108
+ "url_ref",
109
+ "skip_on_upstream_skip",
102
110
  )
103
111
 
104
112
  REQUIRED_SECTIONS = (VERSION, KIND)
@@ -24,10 +24,10 @@ class BaseAsyncAgent(BaseAgent):
24
24
  IS_ASYNC = True
25
25
 
26
26
  async def _enter(self):
27
- if not self.client._is_managed:
28
- return self
29
27
  logger.warning("Agent is starting.")
30
28
  await self.executor.refresh()
29
+ if not self.client._is_managed:
30
+ return self
31
31
  try:
32
32
  agent = await self.client.get_info()
33
33
  self._check_status(agent)
@@ -81,13 +81,16 @@ class BaseAsyncAgent(BaseAgent):
81
81
 
82
82
  async def reconcile(self):
83
83
  if (
84
- now() - self._last_reconciled_at
84
+ now() - self._last_data_collected_at
85
85
  ).total_seconds() > self.SLEEP_AGENT_DATA_COLLECT_TIME:
86
+ await self.collect_agent_data()
87
+ if (
88
+ now() - self._last_reconciled_at
89
+ ).total_seconds() < self.SLEEP_AGENT_DATA_RECONCILE_TIME:
86
90
  return
87
91
 
88
- # Collect data
89
- await self.collect_agent_data()
90
-
92
+ logger.info("Checking cluster state.")
93
+ self._last_reconciled_at = now()
91
94
  # Update reconcile
92
95
  namespaces = [settings.AGENT_CONFIG.namespace]
93
96
  namespaces += settings.AGENT_CONFIG.additional_namespaces or []
@@ -4,7 +4,7 @@ import traceback
4
4
  from concurrent.futures import ThreadPoolExecutor
5
5
  from typing import Any, Dict, Optional, Tuple, Type
6
6
 
7
- from clipped.utils.tz import now
7
+ from clipped.utils.tz import get_datetime_from_now, now
8
8
 
9
9
  from polyaxon import settings
10
10
  from polyaxon._auxiliaries import V1PolyaxonInitContainer, V1PolyaxonSidecarContainer
@@ -24,7 +24,8 @@ class BaseAgent:
24
24
  HEALTH_FILE = "/tmp/.healthz"
25
25
  SLEEP_STOP_TIME = 60 * 5
26
26
  SLEEP_ARCHIVED_TIME = 60 * 60
27
- SLEEP_AGENT_DATA_COLLECT_TIME = 60 * 30
27
+ SLEEP_AGENT_DATA_COLLECT_TIME = 60 * 15
28
+ SLEEP_AGENT_DATA_RECONCILE_TIME = 60 * 5
28
29
  IS_ASYNC = False
29
30
 
30
31
  def __init__(
@@ -38,11 +39,13 @@ class BaseAgent:
38
39
  self.max_interval = max(max_interval, 3)
39
40
  if not agent_uuid and not owner:
40
41
  owner = DEFAULT
42
+ last_hour = get_datetime_from_now(days=0, hours=1)
41
43
  self.executor = None
42
44
  self._default_auth = bool(agent_uuid)
43
- self._executor_refreshed_at = now()
45
+ self._executor_refreshed_at = last_hour
44
46
  self._graceful_shutdown = False
45
- self._last_reconciled_at = now()
47
+ self._last_data_collected_at = last_hour
48
+ self._last_reconciled_at = last_hour
46
49
  self.client = AgentClient(
47
50
  owner=owner, agent_uuid=agent_uuid, is_async=self.IS_ASYNC
48
51
  )
@@ -60,7 +63,7 @@ class BaseAgent:
60
63
 
61
64
  def collect_agent_data(self):
62
65
  logger.info("Collecting agent data.")
63
- self._last_reconciled_at = now()
66
+ self._last_data_collected_at = now()
64
67
  try:
65
68
  return self.client.collect_agent_data(
66
69
  namespace=settings.CLIENT_CONFIG.namespace