frogml 1.1.62__py3-none-any.whl → 1.2.19__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 (530) hide show
  1. frogml/__init__.py +3 -1
  2. frogml/_proto/jfml/hosting_gateway/v1/build_upload_url_pb2.py +3 -3
  3. frogml/_proto/jfml/hosting_gateway/v1/build_upload_url_pb2.pyi +6 -4
  4. frogml/_proto/jfml/hosting_gateway/v1/hosting_gateway_service_pb2.py +3 -3
  5. frogml/_proto/jfml/hosting_gateway/v1/hosting_gateway_service_pb2.pyi +8 -9
  6. frogml/_proto/jfml/model_version/v1/artifact_pb2.py +3 -3
  7. frogml/_proto/jfml/model_version/v1/artifact_pb2.pyi +8 -9
  8. frogml/_proto/jfml/model_version/v1/build_spec_pb2.py +3 -3
  9. frogml/_proto/jfml/model_version/v1/build_spec_pb2.pyi +24 -20
  10. frogml/_proto/jfml/model_version/v1/model_repository_spec_pb2.py +3 -3
  11. frogml/_proto/jfml/model_version/v1/model_repository_spec_pb2.pyi +6 -9
  12. frogml/_proto/jfml/model_version/v1/model_version_framework_pb2.py +3 -3
  13. frogml/_proto/jfml/model_version/v1/model_version_framework_pb2.pyi +13 -10
  14. frogml/_proto/jfml/model_version/v1/model_version_manager_service_pb2.py +3 -3
  15. frogml/_proto/jfml/model_version/v1/model_version_manager_service_pb2.pyi +43 -30
  16. frogml/_proto/jfml/model_version/v1/model_version_pb2.py +11 -11
  17. frogml/_proto/jfml/model_version/v1/model_version_pb2.pyi +48 -32
  18. frogml/_proto/qwak/administration/account/v1/account_pb2.py +25 -23
  19. frogml/_proto/qwak/administration/account/v1/account_pb2.pyi +55 -21
  20. frogml/_proto/qwak/administration/account/v1/account_service_pb2.py +3 -3
  21. frogml/_proto/qwak/administration/account/v1/account_service_pb2.pyi +63 -36
  22. frogml/_proto/qwak/administration/account/v1/jfrog_tenant_details_pb2.py +5 -5
  23. frogml/_proto/qwak/administration/account/v1/jfrog_tenant_details_pb2.pyi +35 -22
  24. frogml/_proto/qwak/administration/account/v1/personalization_pb2.py +3 -3
  25. frogml/_proto/qwak/administration/account/v1/personalization_pb2.pyi +7 -9
  26. frogml/_proto/qwak/administration/account/v1/preferences_pb2.py +3 -3
  27. frogml/_proto/qwak/administration/account/v1/preferences_pb2.pyi +6 -8
  28. frogml/_proto/qwak/administration/account/v1/terms_pb2.py +3 -3
  29. frogml/_proto/qwak/administration/account/v1/terms_pb2.pyi +16 -11
  30. frogml/_proto/qwak/administration/authenticated_user/v1/authenticated_user_service_pb2.py +3 -3
  31. frogml/_proto/qwak/administration/authenticated_user/v1/authenticated_user_service_pb2.pyi +20 -14
  32. frogml/_proto/qwak/administration/authenticated_user/v1/credentials_pb2.py +3 -3
  33. frogml/_proto/qwak/administration/authenticated_user/v1/credentials_pb2.pyi +11 -12
  34. frogml/_proto/qwak/administration/authenticated_user/v1/details_pb2.py +3 -3
  35. frogml/_proto/qwak/administration/authenticated_user/v1/details_pb2.pyi +18 -15
  36. frogml/_proto/qwak/administration/cluster/v2/cluster_pb2.py +3 -3
  37. frogml/_proto/qwak/administration/cluster/v2/cluster_pb2.pyi +62 -39
  38. frogml/_proto/qwak/administration/runtime_configuration/v0/container_registry_config_pb2.py +3 -3
  39. frogml/_proto/qwak/administration/runtime_configuration/v0/container_registry_config_pb2.pyi +12 -13
  40. frogml/_proto/qwak/administration/runtime_configuration/v0/creds/auth_pb2.py +3 -3
  41. frogml/_proto/qwak/administration/runtime_configuration/v0/creds/auth_pb2.pyi +5 -8
  42. frogml/_proto/qwak/administration/runtime_configuration/v0/creds/secret_pb2.py +3 -3
  43. frogml/_proto/qwak/administration/runtime_configuration/v0/creds/secret_pb2.pyi +8 -10
  44. frogml/_proto/qwak/administration/runtime_configuration/v0/data_catalog_config_pb2.py +3 -3
  45. frogml/_proto/qwak/administration/runtime_configuration/v0/data_catalog_config_pb2.pyi +11 -11
  46. frogml/_proto/qwak/administration/runtime_configuration/v0/external/databricks/auth_pb2.py +11 -7
  47. frogml/_proto/qwak/administration/runtime_configuration/v0/external/databricks/auth_pb2.pyi +58 -12
  48. frogml/_proto/qwak/administration/runtime_configuration/v0/external/elasticsearch_config_pb2.py +3 -3
  49. frogml/_proto/qwak/administration/runtime_configuration/v0/external/elasticsearch_config_pb2.pyi +8 -11
  50. frogml/_proto/qwak/administration/runtime_configuration/v0/external/kafka_config_pb2.py +3 -3
  51. frogml/_proto/qwak/administration/runtime_configuration/v0/external/kafka_config_pb2.pyi +12 -12
  52. frogml/_proto/qwak/administration/runtime_configuration/v0/external/prometheus_config_pb2.py +3 -3
  53. frogml/_proto/qwak/administration/runtime_configuration/v0/external/prometheus_config_pb2.pyi +8 -10
  54. frogml/_proto/qwak/administration/runtime_configuration/v0/external/redis_config_pb2.py +3 -3
  55. frogml/_proto/qwak/administration/runtime_configuration/v0/external/redis_config_pb2.pyi +8 -11
  56. frogml/_proto/qwak/administration/runtime_configuration/v0/external/victoriametrics_config_pb2.py +3 -3
  57. frogml/_proto/qwak/administration/runtime_configuration/v0/external/victoriametrics_config_pb2.pyi +6 -9
  58. frogml/_proto/qwak/administration/runtime_configuration/v0/feature_store_config_pb2.py +3 -3
  59. frogml/_proto/qwak/administration/runtime_configuration/v0/feature_store_config_pb2.pyi +13 -14
  60. frogml/_proto/qwak/administration/runtime_configuration/v0/hosting/aws/auth_pb2.py +3 -3
  61. frogml/_proto/qwak/administration/runtime_configuration/v0/hosting/aws/auth_pb2.pyi +29 -25
  62. frogml/_proto/qwak/administration/runtime_configuration/v0/hosting/azure/auth_pb2.py +11 -7
  63. frogml/_proto/qwak/administration/runtime_configuration/v0/hosting/azure/auth_pb2.pyi +57 -17
  64. frogml/_proto/qwak/administration/runtime_configuration/v0/hosting_config_pb2.py +5 -5
  65. frogml/_proto/qwak/administration/runtime_configuration/v0/hosting_config_pb2.pyi +29 -24
  66. frogml/_proto/qwak/administration/runtime_configuration/v0/logs_storage_config_pb2.py +3 -3
  67. frogml/_proto/qwak/administration/runtime_configuration/v0/logs_storage_config_pb2.pyi +6 -9
  68. frogml/_proto/qwak/administration/runtime_configuration/v0/model_analytics_storage_config_pb2.py +3 -3
  69. frogml/_proto/qwak/administration/runtime_configuration/v0/model_analytics_storage_config_pb2.pyi +6 -9
  70. frogml/_proto/qwak/administration/runtime_configuration/v0/network_config_pb2.py +3 -3
  71. frogml/_proto/qwak/administration/runtime_configuration/v0/network_config_pb2.pyi +22 -21
  72. frogml/_proto/qwak/administration/runtime_configuration/v0/object_storage_config_pb2.py +3 -3
  73. frogml/_proto/qwak/administration/runtime_configuration/v0/object_storage_config_pb2.pyi +12 -12
  74. frogml/_proto/qwak/administration/runtime_configuration/v0/observability_config_pb2.py +3 -3
  75. frogml/_proto/qwak/administration/runtime_configuration/v0/observability_config_pb2.pyi +13 -14
  76. frogml/_proto/qwak/administration/runtime_configuration/v0/runtime_config_pb2.py +3 -3
  77. frogml/_proto/qwak/administration/runtime_configuration/v0/runtime_config_pb2.pyi +5 -8
  78. frogml/_proto/qwak/administration/runtime_configuration/v0/sql_engine_config_pb2.py +3 -3
  79. frogml/_proto/qwak/administration/runtime_configuration/v0/sql_engine_config_pb2.pyi +11 -11
  80. frogml/_proto/qwak/administration/v0/authentication/authentication_service_pb2.py +3 -3
  81. frogml/_proto/qwak/administration/v0/authentication/authentication_service_pb2.pyi +14 -13
  82. frogml/_proto/qwak/administration/v0/environments/configuration_pb2.py +3 -3
  83. frogml/_proto/qwak/administration/v0/environments/configuration_pb2.pyi +33 -20
  84. frogml/_proto/qwak/administration/v0/environments/environment_pb2.py +5 -5
  85. frogml/_proto/qwak/administration/v0/environments/environment_pb2.pyi +17 -8
  86. frogml/_proto/qwak/administration/v0/environments/environment_service_pb2.py +5 -5
  87. frogml/_proto/qwak/administration/v0/environments/environment_service_pb2.pyi +46 -26
  88. frogml/_proto/qwak/administration/v0/environments/personalization_pb2.py +3 -3
  89. frogml/_proto/qwak/administration/v0/environments/personalization_pb2.pyi +7 -9
  90. frogml/_proto/qwak/administration/v0/users/user_pb2.py +7 -7
  91. frogml/_proto/qwak/administration/v0/users/user_pb2.pyi +18 -11
  92. frogml/_proto/qwak/admiral/secret/v0/secret_pb2.py +21 -19
  93. frogml/_proto/qwak/admiral/secret/v0/secret_pb2.pyi +65 -24
  94. frogml/_proto/qwak/admiral/secret/v0/secret_service_pb2.py +3 -3
  95. frogml/_proto/qwak/admiral/secret/v0/secret_service_pb2.pyi +16 -12
  96. frogml/_proto/qwak/admiral/secret/v0/system_secret_service_pb2.py +3 -3
  97. frogml/_proto/qwak/admiral/secret/v0/system_secret_service_pb2.pyi +19 -14
  98. frogml/_proto/qwak/admiral/user_application_instance/v0/user_application_instance_pb2.py +3 -3
  99. frogml/_proto/qwak/admiral/user_application_instance/v0/user_application_instance_pb2.pyi +83 -48
  100. frogml/_proto/qwak/admiral/user_application_instance/v0/user_application_instance_service_pb2.py +3 -3
  101. frogml/_proto/qwak/admiral/user_application_instance/v0/user_application_instance_service_pb2.pyi +25 -16
  102. frogml/_proto/qwak/analytics/analytics_pb2.py +3 -3
  103. frogml/_proto/qwak/analytics/analytics_pb2.pyi +33 -16
  104. frogml/_proto/qwak/analytics/analytics_service_pb2.py +3 -3
  105. frogml/_proto/qwak/analytics/analytics_service_pb2.pyi +46 -26
  106. frogml/_proto/qwak/artifactory_settings/artifactory_settings_pb2.py +3 -3
  107. frogml/_proto/qwak/artifactory_settings/artifactory_settings_pb2.pyi +7 -9
  108. frogml/_proto/qwak/audience/v1/audience_api_pb2.py +3 -3
  109. frogml/_proto/qwak/audience/v1/audience_api_pb2.pyi +25 -17
  110. frogml/_proto/qwak/audience/v1/audience_pb2.py +5 -5
  111. frogml/_proto/qwak/audience/v1/audience_pb2.pyi +38 -23
  112. frogml/_proto/qwak/auto_scaling/v1/auto_scaling_pb2.py +3 -3
  113. frogml/_proto/qwak/auto_scaling/v1/auto_scaling_pb2.pyi +22 -13
  114. frogml/_proto/qwak/auto_scaling/v1/auto_scaling_service_pb2.py +3 -3
  115. frogml/_proto/qwak/auto_scaling/v1/auto_scaling_service_pb2.pyi +8 -9
  116. frogml/_proto/qwak/automation/v1/action_pb2.py +17 -17
  117. frogml/_proto/qwak/automation/v1/action_pb2.pyi +76 -47
  118. frogml/_proto/qwak/automation/v1/auto_scaling_pb2.py +3 -3
  119. frogml/_proto/qwak/automation/v1/auto_scaling_pb2.pyi +22 -13
  120. frogml/_proto/qwak/automation/v1/automation_execution_pb2.py +3 -3
  121. frogml/_proto/qwak/automation/v1/automation_execution_pb2.pyi +23 -13
  122. frogml/_proto/qwak/automation/v1/automation_management_service_pb2.py +5 -5
  123. frogml/_proto/qwak/automation/v1/automation_management_service_pb2.pyi +56 -32
  124. frogml/_proto/qwak/automation/v1/automation_pb2.py +3 -3
  125. frogml/_proto/qwak/automation/v1/automation_pb2.pyi +28 -25
  126. frogml/_proto/qwak/automation/v1/common_pb2.py +3 -3
  127. frogml/_proto/qwak/automation/v1/common_pb2.pyi +8 -5
  128. frogml/_proto/qwak/automation/v1/notification_pb2.py +7 -7
  129. frogml/_proto/qwak/automation/v1/notification_pb2.pyi +14 -8
  130. frogml/_proto/qwak/automation/v1/trigger_pb2.py +3 -3
  131. frogml/_proto/qwak/automation/v1/trigger_pb2.pyi +17 -16
  132. frogml/_proto/qwak/batch_job/v1/batch_job_events_pb2.py +13 -13
  133. frogml/_proto/qwak/batch_job/v1/batch_job_events_pb2.pyi +22 -14
  134. frogml/_proto/qwak/batch_job/v1/batch_job_resources_pb2.py +3 -3
  135. frogml/_proto/qwak/batch_job/v1/batch_job_resources_pb2.pyi +4 -2
  136. frogml/_proto/qwak/batch_job/v1/batch_job_service_pb2.py +127 -127
  137. frogml/_proto/qwak/batch_job/v1/batch_job_service_pb2.pyi +196 -101
  138. frogml/_proto/qwak/build/v1/build_api_pb2.py +17 -17
  139. frogml/_proto/qwak/build/v1/build_api_pb2.pyi +87 -46
  140. frogml/_proto/qwak/build/v1/build_pb2.py +9 -9
  141. frogml/_proto/qwak/build/v1/build_pb2.pyi +187 -118
  142. frogml/_proto/qwak/build_settings/build_settings_api_pb2.py +3 -3
  143. frogml/_proto/qwak/build_settings/build_settings_api_pb2.pyi +15 -13
  144. frogml/_proto/qwak/build_settings/build_settings_pb2.py +3 -3
  145. frogml/_proto/qwak/build_settings/build_settings_pb2.pyi +24 -19
  146. frogml/_proto/qwak/builds/build_pb2.py +49 -48
  147. frogml/_proto/qwak/builds/build_pb2.pyi +113 -53
  148. frogml/_proto/qwak/builds/build_url_pb2.py +5 -5
  149. frogml/_proto/qwak/builds/build_url_pb2.pyi +39 -21
  150. frogml/_proto/qwak/builds/build_values_pb2.py +82 -0
  151. frogml/_proto/qwak/builds/build_values_pb2.pyi +582 -0
  152. frogml/_proto/qwak/builds/build_values_pb2_grpc.py +4 -0
  153. frogml/_proto/qwak/builds/builds_orchestrator_service_pb2.py +80 -52
  154. frogml/_proto/qwak/builds/builds_orchestrator_service_pb2.pyi +261 -40
  155. frogml/_proto/qwak/builds/builds_orchestrator_service_pb2_grpc.py +66 -0
  156. frogml/_proto/qwak/builds/builds_pb2.py +7 -7
  157. frogml/_proto/qwak/builds/builds_pb2.pyi +177 -105
  158. frogml/_proto/qwak/builds/internal_builds_orchestrator_service_pb2.py +3 -3
  159. frogml/_proto/qwak/builds/internal_builds_orchestrator_service_pb2.pyi +12 -10
  160. frogml/_proto/qwak/data_versioning/data_versioning_pb2.py +3 -3
  161. frogml/_proto/qwak/data_versioning/data_versioning_pb2.pyi +8 -10
  162. frogml/_proto/qwak/data_versioning/data_versioning_service_pb2.py +3 -3
  163. frogml/_proto/qwak/data_versioning/data_versioning_service_pb2.pyi +12 -11
  164. frogml/_proto/qwak/deployment/alert_pb2.py +5 -5
  165. frogml/_proto/qwak/deployment/alert_pb2.pyi +31 -20
  166. frogml/_proto/qwak/deployment/alert_service_pb2.py +7 -7
  167. frogml/_proto/qwak/deployment/alert_service_pb2.pyi +34 -21
  168. frogml/_proto/qwak/deployment/deployment_messages_pb2.py +3 -3
  169. frogml/_proto/qwak/deployment/deployment_messages_pb2.pyi +9 -11
  170. frogml/_proto/qwak/deployment/deployment_pb2.py +33 -33
  171. frogml/_proto/qwak/deployment/deployment_pb2.pyi +225 -139
  172. frogml/_proto/qwak/deployment/deployment_service_pb2.py +81 -81
  173. frogml/_proto/qwak/deployment/deployment_service_pb2.pyi +139 -78
  174. frogml/_proto/qwak/ecosystem/jfrog/v0/jfrog_tenant_info_service_pb2.py +3 -3
  175. frogml/_proto/qwak/ecosystem/jfrog/v0/jfrog_tenant_info_service_pb2.pyi +11 -9
  176. frogml/_proto/qwak/ecosystem/jfrog/v0/jfrog_tenant_pb2.py +3 -3
  177. frogml/_proto/qwak/ecosystem/jfrog/v0/jfrog_tenant_pb2.pyi +6 -8
  178. frogml/_proto/qwak/ecosystem/jfrog/v0/token_pb2.py +41 -31
  179. frogml/_proto/qwak/ecosystem/jfrog/v0/token_pb2.pyi +168 -36
  180. frogml/_proto/qwak/ecosystem/jfrog/v0/token_service_pb2.py +3 -3
  181. frogml/_proto/qwak/ecosystem/jfrog/v0/token_service_pb2.pyi +29 -19
  182. frogml/_proto/qwak/ecosystem/v0/auth_pb2.py +28 -0
  183. frogml/_proto/qwak/ecosystem/v0/auth_pb2.pyi +35 -0
  184. frogml/_proto/qwak/ecosystem/v0/auth_pb2_grpc.py +4 -0
  185. frogml/_proto/qwak/ecosystem/v0/azure_credentials_pb2.py +37 -0
  186. frogml/_proto/qwak/ecosystem/v0/azure_credentials_pb2.pyi +119 -0
  187. frogml/_proto/qwak/ecosystem/v0/azure_credentials_pb2_grpc.py +4 -0
  188. frogml/_proto/qwak/ecosystem/v0/credentials_pb2.py +11 -10
  189. frogml/_proto/qwak/ecosystem/v0/credentials_pb2.pyi +21 -15
  190. frogml/_proto/qwak/ecosystem/v0/ecosystem_pb2.py +11 -11
  191. frogml/_proto/qwak/ecosystem/v0/ecosystem_pb2.pyi +63 -40
  192. frogml/_proto/qwak/ecosystem/v0/ecosystem_runtime_service_pb2.py +5 -5
  193. frogml/_proto/qwak/ecosystem/v0/ecosystem_runtime_service_pb2.pyi +74 -41
  194. frogml/_proto/qwak/execution/v1/backfill_pb2.py +3 -3
  195. frogml/_proto/qwak/execution/v1/backfill_pb2.pyi +34 -24
  196. frogml/_proto/qwak/execution/v1/batch_pb2.py +3 -3
  197. frogml/_proto/qwak/execution/v1/batch_pb2.pyi +16 -13
  198. frogml/_proto/qwak/execution/v1/deletion_pb2.py +3 -3
  199. frogml/_proto/qwak/execution/v1/deletion_pb2.pyi +9 -9
  200. frogml/_proto/qwak/execution/v1/execution_pb2.py +3 -3
  201. frogml/_proto/qwak/execution/v1/execution_pb2.pyi +28 -12
  202. frogml/_proto/qwak/execution/v1/execution_service_pb2.py +5 -5
  203. frogml/_proto/qwak/execution/v1/execution_service_pb2.pyi +69 -43
  204. frogml/_proto/qwak/execution/v1/internal/deployment/platform_details_pb2.py +3 -3
  205. frogml/_proto/qwak/execution/v1/internal/deployment/platform_details_pb2.pyi +4 -7
  206. frogml/_proto/qwak/execution/v1/jobs/job_pb2.py +5 -5
  207. frogml/_proto/qwak/execution/v1/jobs/job_pb2.pyi +45 -22
  208. frogml/_proto/qwak/execution/v1/jobs/job_service_pb2.py +3 -3
  209. frogml/_proto/qwak/execution/v1/jobs/job_service_pb2.pyi +62 -37
  210. frogml/_proto/qwak/execution/v1/jobs/reports/report_pb2.py +5 -5
  211. frogml/_proto/qwak/execution/v1/jobs/reports/report_pb2.pyi +49 -29
  212. frogml/_proto/qwak/execution/v1/state/execution_state_pb2.py +3 -3
  213. frogml/_proto/qwak/execution/v1/state/execution_state_pb2.pyi +6 -9
  214. frogml/_proto/qwak/execution/v1/state/execution_state_service_pb2.py +3 -3
  215. frogml/_proto/qwak/execution/v1/state/execution_state_service_pb2.pyi +27 -19
  216. frogml/_proto/qwak/execution/v1/state/featureset_state_pb2.py +3 -3
  217. frogml/_proto/qwak/execution/v1/state/featureset_state_pb2.pyi +4 -7
  218. frogml/_proto/qwak/execution/v1/state/spark_execution_state_pb2.py +5 -5
  219. frogml/_proto/qwak/execution/v1/state/spark_execution_state_pb2.pyi +13 -7
  220. frogml/_proto/qwak/execution/v1/streaming_aggregation_pb2.py +21 -14
  221. frogml/_proto/qwak/execution/v1/streaming_aggregation_pb2.pyi +83 -11
  222. frogml/_proto/qwak/execution/v1/streaming_pb2.py +3 -3
  223. frogml/_proto/qwak/execution/v1/streaming_pb2.pyi +10 -10
  224. frogml/_proto/qwak/feature_store/entities/entity_pb2.py +3 -3
  225. frogml/_proto/qwak/feature_store/entities/entity_pb2.pyi +29 -16
  226. frogml/_proto/qwak/feature_store/entities/entity_service_pb2.py +3 -3
  227. frogml/_proto/qwak/feature_store/entities/entity_service_pb2.pyi +37 -22
  228. frogml/_proto/qwak/feature_store/features/aggregation_pb2.py +3 -3
  229. frogml/_proto/qwak/feature_store/features/aggregation_pb2.pyi +39 -21
  230. frogml/_proto/qwak/feature_store/features/deployment_pb2.py +3 -3
  231. frogml/_proto/qwak/feature_store/features/deployment_pb2.pyi +51 -27
  232. frogml/_proto/qwak/feature_store/features/deployment_service_pb2.py +3 -3
  233. frogml/_proto/qwak/feature_store/features/deployment_service_pb2.pyi +5 -7
  234. frogml/_proto/qwak/feature_store/features/execution_pb2.py +3 -3
  235. frogml/_proto/qwak/feature_store/features/execution_pb2.pyi +18 -13
  236. frogml/_proto/qwak/feature_store/features/feature_set_attribute_pb2.py +3 -3
  237. frogml/_proto/qwak/feature_store/features/feature_set_attribute_pb2.pyi +6 -8
  238. frogml/_proto/qwak/feature_store/features/feature_set_pb2.py +21 -21
  239. frogml/_proto/qwak/feature_store/features/feature_set_pb2.pyi +85 -48
  240. frogml/_proto/qwak/feature_store/features/feature_set_service_pb2.py +9 -9
  241. frogml/_proto/qwak/feature_store/features/feature_set_service_pb2.pyi +107 -53
  242. frogml/_proto/qwak/feature_store/features/feature_set_state_pb2.py +3 -3
  243. frogml/_proto/qwak/feature_store/features/feature_set_state_pb2.pyi +46 -23
  244. frogml/_proto/qwak/feature_store/features/feature_set_state_service_pb2.py +3 -3
  245. frogml/_proto/qwak/feature_store/features/feature_set_state_service_pb2.pyi +27 -17
  246. frogml/_proto/qwak/feature_store/features/feature_set_types_pb2.py +73 -71
  247. frogml/_proto/qwak/feature_store/features/feature_set_types_pb2.pyi +181 -99
  248. frogml/_proto/qwak/feature_store/features/monitoring_pb2.py +3 -3
  249. frogml/_proto/qwak/feature_store/features/monitoring_pb2.pyi +11 -11
  250. frogml/_proto/qwak/feature_store/features/real_time_feature_extractor_pb2.py +3 -3
  251. frogml/_proto/qwak/feature_store/features/real_time_feature_extractor_pb2.pyi +63 -37
  252. frogml/_proto/qwak/feature_store/jobs/job_pb2.py +3 -3
  253. frogml/_proto/qwak/feature_store/jobs/job_pb2.pyi +26 -14
  254. frogml/_proto/qwak/feature_store/jobs/job_service_pb2.py +3 -3
  255. frogml/_proto/qwak/feature_store/jobs/job_service_pb2.pyi +36 -25
  256. frogml/_proto/qwak/feature_store/jobs/v1/job_pb2.py +3 -3
  257. frogml/_proto/qwak/feature_store/jobs/v1/job_pb2.pyi +23 -12
  258. frogml/_proto/qwak/feature_store/jobs/v1/job_service_pb2.py +3 -3
  259. frogml/_proto/qwak/feature_store/jobs/v1/job_service_pb2.pyi +51 -30
  260. frogml/_proto/qwak/feature_store/platform/platform_details_pb2.py +3 -3
  261. frogml/_proto/qwak/feature_store/platform/platform_details_pb2.pyi +11 -11
  262. frogml/_proto/qwak/feature_store/reports/report_pb2.py +3 -3
  263. frogml/_proto/qwak/feature_store/reports/report_pb2.pyi +28 -18
  264. frogml/_proto/qwak/feature_store/repository/common/platform_pb2.py +3 -3
  265. frogml/_proto/qwak/feature_store/repository/common/platform_pb2.pyi +13 -12
  266. frogml/_proto/qwak/feature_store/serving/management_pb2.py +3 -3
  267. frogml/_proto/qwak/feature_store/serving/management_pb2.pyi +10 -10
  268. frogml/_proto/qwak/feature_store/serving/metadata_pb2.py +3 -3
  269. frogml/_proto/qwak/feature_store/serving/metadata_pb2.pyi +21 -15
  270. frogml/_proto/qwak/feature_store/serving/serving_pb2.py +13 -13
  271. frogml/_proto/qwak/feature_store/serving/serving_pb2.pyi +67 -37
  272. frogml/_proto/qwak/feature_store/serving/v1/value_pb2.py +3 -3
  273. frogml/_proto/qwak/feature_store/serving/v1/value_pb2.pyi +8 -10
  274. frogml/_proto/qwak/feature_store/sinks/sink_pb2.py +3 -3
  275. frogml/_proto/qwak/feature_store/sinks/sink_pb2.pyi +20 -16
  276. frogml/_proto/qwak/feature_store/sources/batch_pb2.py +83 -77
  277. frogml/_proto/qwak/feature_store/sources/batch_pb2.pyi +188 -62
  278. frogml/_proto/qwak/feature_store/sources/data_source_attribute_pb2.py +3 -3
  279. frogml/_proto/qwak/feature_store/sources/data_source_attribute_pb2.pyi +6 -8
  280. frogml/_proto/qwak/feature_store/sources/data_source_pb2.py +7 -7
  281. frogml/_proto/qwak/feature_store/sources/data_source_pb2.pyi +37 -30
  282. frogml/_proto/qwak/feature_store/sources/data_source_service_pb2.py +5 -5
  283. frogml/_proto/qwak/feature_store/sources/data_source_service_pb2.pyi +45 -25
  284. frogml/_proto/qwak/feature_store/sources/streaming_pb2.py +11 -11
  285. frogml/_proto/qwak/feature_store/sources/streaming_pb2.pyi +41 -21
  286. frogml/_proto/qwak/feature_store/v1/common/jfrog_artifact/jfrog_artifact_pb2.py +3 -3
  287. frogml/_proto/qwak/feature_store/v1/common/jfrog_artifact/jfrog_artifact_pb2.pyi +4 -7
  288. frogml/_proto/qwak/feature_store/v1/common/source_code/source_code_pb2.py +3 -3
  289. frogml/_proto/qwak/feature_store/v1/common/source_code/source_code_pb2.pyi +17 -17
  290. frogml/_proto/qwak/feature_store/v1/internal/data_source/data_source_service_pb2.py +5 -5
  291. frogml/_proto/qwak/feature_store/v1/internal/data_source/data_source_service_pb2.pyi +15 -13
  292. frogml/_proto/qwak/feature_store/v1/internal/featureset/featureset_token_service_pb2.py +3 -3
  293. frogml/_proto/qwak/feature_store/v1/internal/featureset/featureset_token_service_pb2.pyi +6 -8
  294. frogml/_proto/qwak/features_operator/v1/features_operator_pb2.py +3 -3
  295. frogml/_proto/qwak/features_operator/v1/features_operator_pb2.pyi +15 -11
  296. frogml/_proto/qwak/features_operator/v1/features_operator_service_pb2.py +3 -3
  297. frogml/_proto/qwak/features_operator/v1/features_operator_service_pb2.pyi +18 -16
  298. frogml/_proto/qwak/features_operator/v2/features_operator_pb2.py +3 -3
  299. frogml/_proto/qwak/features_operator/v2/features_operator_pb2.pyi +16 -11
  300. frogml/_proto/qwak/features_operator/v2/features_operator_service_pb2.py +3 -3
  301. frogml/_proto/qwak/features_operator/v2/features_operator_service_pb2.pyi +20 -19
  302. frogml/_proto/qwak/features_operator/v3/features_operator_async_service_pb2.py +3 -3
  303. frogml/_proto/qwak/features_operator/v3/features_operator_async_service_pb2.pyi +41 -34
  304. frogml/_proto/qwak/features_operator/v3/features_operator_pb2.py +3 -3
  305. frogml/_proto/qwak/features_operator/v3/features_operator_pb2.pyi +19 -13
  306. frogml/_proto/qwak/file_versioning/file_versioning_pb2.py +5 -5
  307. frogml/_proto/qwak/file_versioning/file_versioning_pb2.pyi +8 -5
  308. frogml/_proto/qwak/file_versioning/file_versioning_service_pb2.py +3 -3
  309. frogml/_proto/qwak/file_versioning/file_versioning_service_pb2.pyi +12 -11
  310. frogml/_proto/qwak/fitness_service/constructs_pb2.py +5 -5
  311. frogml/_proto/qwak/fitness_service/constructs_pb2.pyi +51 -16
  312. frogml/_proto/qwak/fitness_service/fitness_pb2.py +3 -3
  313. frogml/_proto/qwak/fitness_service/fitness_pb2.pyi +24 -18
  314. frogml/_proto/qwak/fitness_service/fitness_service_pb2.py +3 -3
  315. frogml/_proto/qwak/fitness_service/fitness_service_pb2.pyi +18 -13
  316. frogml/_proto/qwak/fitness_service/status_pb2.py +3 -3
  317. frogml/_proto/qwak/fitness_service/status_pb2.pyi +26 -16
  318. frogml/_proto/qwak/inference/feedback/feedback_pb2.py +3 -3
  319. frogml/_proto/qwak/inference/feedback/feedback_pb2.pyi +28 -15
  320. frogml/_proto/qwak/instance_template/instance_template_pb2.py +11 -11
  321. frogml/_proto/qwak/instance_template/instance_template_pb2.pyi +13 -7
  322. frogml/_proto/qwak/instance_template/instance_template_service_pb2.py +3 -3
  323. frogml/_proto/qwak/instance_template/instance_template_service_pb2.pyi +12 -12
  324. frogml/_proto/qwak/integration/hugging_face_integration_pb2.py +3 -3
  325. frogml/_proto/qwak/integration/hugging_face_integration_pb2.pyi +19 -17
  326. frogml/_proto/qwak/integration/integration_pb2.py +3 -3
  327. frogml/_proto/qwak/integration/integration_pb2.pyi +50 -32
  328. frogml/_proto/qwak/integration/integration_service_pb2.py +3 -3
  329. frogml/_proto/qwak/integration/integration_service_pb2.pyi +39 -23
  330. frogml/_proto/qwak/integration/open_a_i_integration_pb2.py +3 -3
  331. frogml/_proto/qwak/integration/open_a_i_integration_pb2.pyi +20 -17
  332. frogml/_proto/qwak/integration/opsgenie_integration_pb2.py +5 -5
  333. frogml/_proto/qwak/integration/opsgenie_integration_pb2.pyi +29 -16
  334. frogml/_proto/qwak/integration/pagerduty_integration_pb2.py +5 -5
  335. frogml/_proto/qwak/integration/pagerduty_integration_pb2.pyi +39 -26
  336. frogml/_proto/qwak/integration/slack_app_integration_pb2.py +5 -5
  337. frogml/_proto/qwak/integration/slack_app_integration_pb2.pyi +30 -20
  338. frogml/_proto/qwak/jfrog/gateway/v0/repository_pb2.py +3 -3
  339. frogml/_proto/qwak/jfrog/gateway/v0/repository_pb2.pyi +19 -16
  340. frogml/_proto/qwak/jfrog/gateway/v0/repository_service_pb2.py +3 -3
  341. frogml/_proto/qwak/jfrog/gateway/v0/repository_service_pb2.pyi +11 -11
  342. frogml/_proto/qwak/kube_deployment_captain/alert_pb2.py +5 -5
  343. frogml/_proto/qwak/kube_deployment_captain/alert_pb2.pyi +25 -15
  344. frogml/_proto/qwak/kube_deployment_captain/alerting_pb2.py +3 -3
  345. frogml/_proto/qwak/kube_deployment_captain/alerting_pb2.pyi +14 -12
  346. frogml/_proto/qwak/kube_deployment_captain/batch_job_pb2.py +67 -67
  347. frogml/_proto/qwak/kube_deployment_captain/batch_job_pb2.pyi +106 -59
  348. frogml/_proto/qwak/kube_deployment_captain/deployment_pb2.py +3 -3
  349. frogml/_proto/qwak/kube_deployment_captain/deployment_pb2.pyi +63 -40
  350. frogml/_proto/qwak/kube_deployment_captain/feature_set_deployment_pb2.py +7 -7
  351. frogml/_proto/qwak/kube_deployment_captain/feature_set_deployment_pb2.pyi +63 -39
  352. frogml/_proto/qwak/kube_deployment_captain/kube_deployment_captain_service_pb2.py +17 -17
  353. frogml/_proto/qwak/kube_deployment_captain/kube_deployment_captain_service_pb2.pyi +146 -72
  354. frogml/_proto/qwak/kube_deployment_captain/traffic_mapping_pb2.py +3 -3
  355. frogml/_proto/qwak/kube_deployment_captain/traffic_mapping_pb2.pyi +8 -10
  356. frogml/_proto/qwak/logging/log_filter_pb2.py +3 -3
  357. frogml/_proto/qwak/logging/log_filter_pb2.pyi +18 -13
  358. frogml/_proto/qwak/logging/log_line_pb2.py +5 -5
  359. frogml/_proto/qwak/logging/log_line_pb2.pyi +7 -8
  360. frogml/_proto/qwak/logging/log_reader_service_pb2.py +3 -3
  361. frogml/_proto/qwak/logging/log_reader_service_pb2.pyi +19 -18
  362. frogml/_proto/qwak/logging/log_source_pb2.py +3 -3
  363. frogml/_proto/qwak/logging/log_source_pb2.pyi +39 -29
  364. frogml/_proto/qwak/model_descriptor/open_ai_descriptor_pb2.py +3 -3
  365. frogml/_proto/qwak/model_descriptor/open_ai_descriptor_pb2.pyi +48 -44
  366. frogml/_proto/qwak/model_group/model_group_pb2.py +24 -16
  367. frogml/_proto/qwak/model_group/model_group_pb2.pyi +90 -12
  368. frogml/_proto/qwak/model_group/model_group_pb2_grpc.py +37 -0
  369. frogml/_proto/qwak/model_group/model_group_repository_details_pb2.py +3 -3
  370. frogml/_proto/qwak/model_group/model_group_repository_details_pb2.pyi +28 -18
  371. frogml/_proto/qwak/models/models_pb2.py +38 -28
  372. frogml/_proto/qwak/models/models_pb2.pyi +229 -84
  373. frogml/_proto/qwak/models/models_pb2_grpc.py +34 -0
  374. frogml/_proto/qwak/models/models_query_pb2.py +3 -3
  375. frogml/_proto/qwak/models/models_query_pb2.pyi +18 -13
  376. frogml/_proto/qwak/monitoring/v0/alerting_channel_management_service_pb2.py +3 -3
  377. frogml/_proto/qwak/monitoring/v0/alerting_channel_management_service_pb2.pyi +31 -18
  378. frogml/_proto/qwak/monitoring/v0/alerting_channel_pb2.py +3 -3
  379. frogml/_proto/qwak/monitoring/v0/alerting_channel_pb2.pyi +62 -28
  380. frogml/_proto/qwak/monitoring/v0/alerting_channel_sync_service_pb2.py +3 -3
  381. frogml/_proto/qwak/monitoring/v0/alerting_channel_sync_service_pb2.pyi +18 -14
  382. frogml/_proto/qwak/offline/serving/v1/feature_values_pb2.py +3 -3
  383. frogml/_proto/qwak/offline/serving/v1/feature_values_pb2.pyi +5 -7
  384. frogml/_proto/qwak/offline/serving/v1/offline_serving_async_service_pb2.py +3 -3
  385. frogml/_proto/qwak/offline/serving/v1/offline_serving_async_service_pb2.pyi +43 -23
  386. frogml/_proto/qwak/offline/serving/v1/options_pb2.py +3 -3
  387. frogml/_proto/qwak/offline/serving/v1/options_pb2.pyi +4 -7
  388. frogml/_proto/qwak/offline/serving/v1/population_pb2.py +3 -3
  389. frogml/_proto/qwak/offline/serving/v1/population_pb2.pyi +18 -15
  390. frogml/_proto/qwak/projects/jfrog_project_spec_pb2.py +3 -3
  391. frogml/_proto/qwak/projects/jfrog_project_spec_pb2.pyi +6 -9
  392. frogml/_proto/qwak/projects/projects_pb2.py +22 -20
  393. frogml/_proto/qwak/projects/projects_pb2.pyi +74 -36
  394. frogml/_proto/qwak/secret_service/secret_service_pb2.py +3 -3
  395. frogml/_proto/qwak/secret_service/secret_service_pb2.pyi +13 -11
  396. frogml/_proto/qwak/self_service/account/v0/account_membership_pb2.py +7 -7
  397. frogml/_proto/qwak/self_service/account/v0/account_membership_pb2.pyi +44 -22
  398. frogml/_proto/qwak/self_service/account/v0/account_membership_service_pb2.py +3 -3
  399. frogml/_proto/qwak/self_service/account/v0/account_membership_service_pb2.pyi +48 -24
  400. frogml/_proto/qwak/self_service/account/v0/account_status_pb2.py +5 -5
  401. frogml/_proto/qwak/self_service/account/v0/account_status_pb2.pyi +30 -23
  402. frogml/_proto/qwak/self_service/account/v0/managing_account_pb2.py +31 -25
  403. frogml/_proto/qwak/self_service/account/v0/managing_account_pb2.pyi +84 -22
  404. frogml/_proto/qwak/self_service/account/v0/managing_account_service_pb2.py +3 -3
  405. frogml/_proto/qwak/self_service/account/v0/managing_account_service_pb2.pyi +25 -16
  406. frogml/_proto/qwak/self_service/user/v1/api_key_pb2.py +3 -3
  407. frogml/_proto/qwak/self_service/user/v1/api_key_pb2.pyi +4 -7
  408. frogml/_proto/qwak/self_service/user/v1/user_pb2.py +3 -3
  409. frogml/_proto/qwak/self_service/user/v1/user_pb2.pyi +16 -16
  410. frogml/_proto/qwak/self_service/user/v1/user_service_pb2.py +5 -5
  411. frogml/_proto/qwak/self_service/user/v1/user_service_pb2.pyi +27 -14
  412. frogml/_proto/qwak/service_discovery/service_discovery_location_pb2.py +3 -3
  413. frogml/_proto/qwak/service_discovery/service_discovery_location_pb2.pyi +11 -11
  414. frogml/_proto/qwak/service_discovery/service_discovery_location_service_pb2.py +3 -3
  415. frogml/_proto/qwak/service_discovery/service_discovery_location_service_pb2.pyi +6 -8
  416. frogml/_proto/qwak/traffic/v1/traffic_api_pb2.py +3 -3
  417. frogml/_proto/qwak/traffic/v1/traffic_api_pb2.pyi +19 -14
  418. frogml/_proto/qwak/traffic/v1/traffic_pb2.py +3 -3
  419. frogml/_proto/qwak/traffic/v1/traffic_pb2.pyi +35 -22
  420. frogml/_proto/qwak/user_application/common/v0/resources_pb2.py +9 -9
  421. frogml/_proto/qwak/user_application/common/v0/resources_pb2.pyi +53 -19
  422. frogml/_proto/qwak/user_application/v0/user_application_pb2.py +7 -7
  423. frogml/_proto/qwak/user_application/v0/user_application_pb2.pyi +8 -5
  424. frogml/core/automations/batch_execution_action.py +4 -1
  425. frogml/core/clients/batch_job_management/client.py +1 -0
  426. frogml/core/clients/batch_job_management/executions_config.py +2 -0
  427. frogml/core/clients/build_orchestrator/build_model_request_getter.py +6 -2
  428. frogml/core/clients/build_orchestrator/client.py +56 -5
  429. frogml/core/clients/feature_store/management_client.py +159 -220
  430. frogml/core/clients/feature_store/operator_client.py +21 -2
  431. frogml/core/clients/jfrog_gateway/client.py +0 -20
  432. frogml/core/clients/model_group_management/client.py +20 -1
  433. frogml/core/exceptions/__init__.py +1 -0
  434. frogml/core/exceptions/frogml_grpc_address_exception.py +9 -0
  435. frogml/core/exceptions/frogml_token_exception.py +7 -0
  436. frogml/core/feature_store/_common/source_code_spec.py +60 -14
  437. frogml/core/feature_store/data_sources/attributes.py +5 -8
  438. frogml/core/feature_store/data_sources/source_authentication.py +5 -6
  439. frogml/core/feature_store/data_sources/time_partition_columns.py +28 -41
  440. frogml/core/feature_store/execution/backfill.py +17 -28
  441. frogml/core/feature_store/feature_sets/transformations/__init__.py +0 -2
  442. frogml/core/feature_store/feature_sets/transformations/transformations.py +0 -69
  443. frogml/core/feature_store/validations/validation_decorators.py +72 -0
  444. frogml/core/inner/build_config/build_config_v1.py +4 -5
  445. frogml/core/inner/build_logic/phases/phase_010_fetch_model/post_fetch_validation_step.py +10 -10
  446. frogml/core/inner/build_logic/phases/phase_020_remote_register_frogml_build/upload_step.py +92 -43
  447. frogml/core/inner/const.py +2 -0
  448. frogml/core/inner/di_configuration/__init__.py +1 -67
  449. frogml/core/inner/di_configuration/account.py +4 -5
  450. frogml/core/inner/di_configuration/containers.py +7 -0
  451. frogml/core/inner/di_configuration/dependency_wiring.py +95 -0
  452. frogml/core/inner/tool/auth/TOKEN_ROTATION.md +51 -0
  453. frogml/core/inner/tool/auth/__init__.py +3 -0
  454. frogml/core/inner/tool/auth/auth_client.py +192 -0
  455. frogml/core/inner/tool/auth/token_maintainer.py +119 -0
  456. frogml/core/inner/tool/grpc/grpc_auth.py +22 -23
  457. frogml/core/inner/tool/grpc/grpc_tools.py +126 -6
  458. frogml/core/inner/tool/grpc/grpc_try_wrapping.py +123 -5
  459. frogml/core/model_loggers/artifact_logger.py +5 -4
  460. frogml/core/utils/proto_utils.py +0 -40
  461. frogml/feature_store/_common/artifact_utils.py +10 -8
  462. frogml/feature_store/_common/packaging.py +40 -22
  463. frogml/feature_store/_common/source_code_spec_factory.py +59 -9
  464. frogml/feature_store/data_sources/__init__.py +2 -0
  465. frogml/feature_store/data_sources/base.py +20 -21
  466. frogml/feature_store/data_sources/batch/_batch.py +0 -3
  467. frogml/feature_store/data_sources/batch/_jdbc.py +6 -7
  468. frogml/feature_store/data_sources/batch/athena.py +6 -7
  469. frogml/feature_store/data_sources/batch/big_query.py +8 -5
  470. frogml/feature_store/data_sources/batch/clickhouse.py +8 -8
  471. frogml/feature_store/data_sources/batch/csv.py +2 -4
  472. frogml/feature_store/data_sources/batch/elastic_search.py +2 -4
  473. frogml/feature_store/data_sources/batch/filesystem/aws.py +21 -22
  474. frogml/feature_store/data_sources/batch/filesystem/base_config.py +3 -3
  475. frogml/feature_store/data_sources/batch/filesystem/gcp.py +3 -7
  476. frogml/feature_store/data_sources/batch/mongodb.py +2 -4
  477. frogml/feature_store/data_sources/batch/mysql.py +2 -3
  478. frogml/feature_store/data_sources/batch/parquet.py +6 -6
  479. frogml/feature_store/data_sources/batch/postgres.py +2 -3
  480. frogml/feature_store/data_sources/batch/redshift.py +8 -6
  481. frogml/feature_store/data_sources/batch/snowflake.py +17 -11
  482. frogml/feature_store/data_sources/batch/unity_catalog.py +113 -0
  483. frogml/feature_store/data_sources/batch/vertica.py +10 -6
  484. frogml/feature_store/data_sources/streaming/_streaming.py +0 -2
  485. frogml/feature_store/data_sources/streaming/kafka/authentication.py +13 -19
  486. frogml/feature_store/data_sources/streaming/kafka/deserialization.py +22 -23
  487. frogml/feature_store/data_sources/streaming/kafka/kafka.py +13 -14
  488. frogml/feature_store/feature_sets/base_feature_set.py +1 -0
  489. frogml/feature_store/online/client.py +20 -4
  490. frogml/feature_store/validations/validator.py +11 -3
  491. frogml/sdk/frogml_client/builds/build.py +8 -7
  492. frogml/sdk/frogml_client/client.py +3 -71
  493. frogml/sdk/model_version/__init__.py +0 -2
  494. frogml/sdk/model_version/catboost/__init__.py +3 -0
  495. frogml/sdk/model_version/files/__init__.py +4 -0
  496. frogml/sdk/model_version/huggingface/__init__.py +9 -3
  497. frogml/sdk/model_version/model_loggers/base_model_version_manager.py +5 -0
  498. frogml/sdk/model_version/onnx/__init__.py +3 -0
  499. frogml/sdk/model_version/pytorch/__init__.py +3 -0
  500. frogml/sdk/model_version/scikit_learn/__init__.py +3 -0
  501. frogml/sdk/model_version/utils/files_tools.py +2 -3
  502. frogml/sdk/model_version/utils/jml/customer_client.py +47 -14
  503. frogml/sdk/model_version/utils/model_log_config.py +5 -0
  504. frogml/sdk/model_version/utils/storage.py +57 -41
  505. frogml/storage/artifactory/_artifactory_api.py +6 -0
  506. frogml/storage/authentication/login/_login_cli.py +21 -21
  507. frogml/storage/authentication/models/_auth_config.py +22 -1
  508. frogml/storage/authentication/utils/_authentication_utils.py +31 -34
  509. frogml/storage/constants.py +19 -0
  510. frogml/storage/frog_ml.py +10 -20
  511. frogml/storage/models/frogml_dataset_version.py +3 -3
  512. frogml/storage/models/frogml_model_version.py +6 -3
  513. frogml/storage/utils/_input_checks_utility.py +3 -1
  514. {frogml-1.1.62.dist-info → frogml-1.2.19.dist-info}/METADATA +39 -9
  515. {frogml-1.1.62.dist-info → frogml-1.2.19.dist-info}/RECORD +525 -512
  516. frogml_services_mock/mocks/authentication_service.py +3 -3
  517. frogml_services_mock/mocks/build_orchestrator_service_api.py +5 -2
  518. frogml_services_mock/mocks/ecosystem_service_api.py +15 -3
  519. frogml_services_mock/mocks/feature_store_data_sources_manager_api.py +55 -14
  520. frogml_services_mock/mocks/feature_store_entities_manager_api.py +31 -30
  521. frogml_services_mock/mocks/features_operator_v3_service.py +20 -0
  522. frogml_services_mock/mocks/frogml_mocks.py +1 -1
  523. frogml_services_mock/mocks/project_manager_service.py +31 -56
  524. frogml_services_mock/services_mock.py +42 -35
  525. frogml/core/clients/project/__init__.py +0 -0
  526. frogml/core/clients/project/client.py +0 -72
  527. frogml/core/inner/tool/auth.py +0 -84
  528. frogml/sdk/frogml_client/projects/__init__.py +0 -0
  529. frogml/sdk/frogml_client/projects/project.py +0 -56
  530. {frogml-1.1.62.dist-info → frogml-1.2.19.dist-info}/WHEEL +0 -0
@@ -0,0 +1,192 @@
1
+ import os
2
+ from typing import Callable, Optional, Union
3
+ from urllib.parse import urljoin
4
+
5
+ import requests
6
+ from cachetools import LRUCache, TTLCache, cached, cachedmethod
7
+ from frogml.core.exceptions import FrogmlLoginException
8
+ from frogml.core.exceptions.frogml_token_exception import FrogMLTokenException
9
+ from frogml.core.inner.tool.auth.token_maintainer import TokenMaintainer
10
+ from frogml.storage.authentication.models import AuthConfig, BearerAuth, EmptyAuth
11
+ from frogml.storage.authentication.utils import get_credentials
12
+ from frogml.storage.constants import (
13
+ JF_ACCESS_TOKEN_RELOAD_INTERVAL_SECONDS,
14
+ JF_SHORT_TOKEN_ROTATION_GENERATION_TIMEOUT_SECONDS,
15
+ JF_SHORT_TOKEN_ROTATION_GENERATION_TIMEOUT_SECONDS_DEFAULT,
16
+ JF_SHORT_TOKEN_ROTATION_GRACE_PERIOD_SECONDS,
17
+ JF_SHORT_TOKEN_ROTATION_GRACE_PERIOD_SECONDS_DEFAULT,
18
+ JF_SHORT_TOKEN_ROTATION_INTERVAL_SECONDS,
19
+ JF_SHORT_TOKEN_ROTATION_INTERVAL_SECONDS_DEFAULT,
20
+ JF_USE_SHORT_TOKEN_ROTATION,
21
+ JF_USE_SHORT_TOKEN_ROTATION_DEFAULT,
22
+ )
23
+ from requests import Response
24
+ from requests.exceptions import RequestException
25
+
26
+
27
+ class FrogMLAuthClient:
28
+ __MIN_TOKEN_LENGTH: int = 64
29
+
30
+ def __init__(self, auth_config: Optional[AuthConfig] = None):
31
+ self.__auth_config: Optional[AuthConfig] = auth_config
32
+ self.__token: Optional[str] = None
33
+ self.__tenant_id: Optional[str] = None
34
+
35
+ # Initialize instance-level caches
36
+ self.__token_maintainer_cache = LRUCache(maxsize=1)
37
+ self.__tenant_id_cache = LRUCache(maxsize=1)
38
+ self.__jpd_id_cache = LRUCache(maxsize=10)
39
+
40
+ self.__base_token_retriever: Callable[[], str] = (
41
+ self.__get_base_token_retriever()
42
+ )
43
+ self.__use_token_maintainer: bool = self.__should_use_token_maintainer()
44
+
45
+ # best-effort to prime the token maintainer (if used)
46
+ if self.__use_token_maintainer:
47
+ self.get_token()
48
+
49
+ def __should_use_token_maintainer(self) -> bool:
50
+ return (
51
+ str(
52
+ os.getenv(
53
+ JF_USE_SHORT_TOKEN_ROTATION, JF_USE_SHORT_TOKEN_ROTATION_DEFAULT
54
+ )
55
+ ).upper()
56
+ == "TRUE"
57
+ )
58
+
59
+ def get_token(self) -> str:
60
+ base_token: str = self.__base_token_retriever()
61
+
62
+ if not self.__use_token_maintainer:
63
+ return base_token
64
+
65
+ return self._get_token_maintainer(base_token).get_token()
66
+
67
+ @cachedmethod(
68
+ cache=lambda self: self.__token_maintainer_cache,
69
+ )
70
+ def _get_token_maintainer(self, base_token: str) -> TokenMaintainer:
71
+ token_rotation_interval_seconds: int = int(
72
+ os.getenv(
73
+ JF_SHORT_TOKEN_ROTATION_INTERVAL_SECONDS,
74
+ JF_SHORT_TOKEN_ROTATION_INTERVAL_SECONDS_DEFAULT,
75
+ )
76
+ )
77
+ token_rotation_grace_period_seconds: int = int(
78
+ os.getenv(
79
+ JF_SHORT_TOKEN_ROTATION_GRACE_PERIOD_SECONDS,
80
+ JF_SHORT_TOKEN_ROTATION_GRACE_PERIOD_SECONDS_DEFAULT,
81
+ )
82
+ )
83
+ token_rotation_generation_timeout_seconds: int = int(
84
+ os.getenv(
85
+ JF_SHORT_TOKEN_ROTATION_GENERATION_TIMEOUT_SECONDS,
86
+ JF_SHORT_TOKEN_ROTATION_GENERATION_TIMEOUT_SECONDS_DEFAULT,
87
+ )
88
+ )
89
+
90
+ return TokenMaintainer(
91
+ base_token=base_token,
92
+ base_url=self.get_base_url(),
93
+ token_rotation_interval_seconds=token_rotation_interval_seconds,
94
+ token_rotation_grace_period_seconds=token_rotation_grace_period_seconds,
95
+ token_rotation_generation_timeout_seconds=token_rotation_generation_timeout_seconds,
96
+ )
97
+
98
+ def get_base_token(self) -> str:
99
+ auth: Union[EmptyAuth, BearerAuth] = self.get_auth()
100
+
101
+ if isinstance(auth, BearerAuth):
102
+ self.validate_token(auth.token)
103
+ self.__token = auth.token
104
+
105
+ else:
106
+ raise FrogMLTokenException(
107
+ message="Token not found in the authentication configurations."
108
+ )
109
+
110
+ return self.__token
111
+
112
+ @cachedmethod(lambda self: self.__tenant_id_cache)
113
+ def get_tenant_id(self) -> str:
114
+ base_url: str = self.get_base_url()
115
+ url: str = urljoin(base_url, "/ui/api/v1/system/auth/screen/footer")
116
+
117
+ try:
118
+ response: Response = requests.get(url, timeout=15, auth=self.get_auth())
119
+ response.raise_for_status() # Raises an HTTPError for bad responses
120
+ response_data: dict = response.json()
121
+
122
+ if "serverId" in response_data:
123
+ self.__tenant_id = response_data["serverId"]
124
+ else:
125
+ self.__tenant_id = self.__get_jpd_id(base_url)
126
+
127
+ return self.__tenant_id
128
+
129
+ except (RequestException, ValueError) as exc:
130
+ raise FrogmlLoginException(
131
+ "Failed to authenticate with JFrog. Please check your credentials"
132
+ ) from exc
133
+
134
+ def get_base_url(self) -> str:
135
+ artifactory_url, _ = get_credentials(self.__auth_config)
136
+ return self.__remove_artifactory_path_from_url(artifactory_url)
137
+
138
+ def get_auth(self) -> Union[EmptyAuth, BearerAuth]:
139
+ return get_credentials(self.__auth_config)[1]
140
+
141
+ def validate_token(self, token: Optional[str]):
142
+ if token is None or len(token) <= self.__MIN_TOKEN_LENGTH or token.isspace():
143
+ raise FrogmlLoginException(
144
+ "Authentication with JFrog failed: Only JWT Access Tokens are supported. "
145
+ "Please ensure you are using a valid JWT Access Token."
146
+ )
147
+
148
+ @cachedmethod(cache=lambda self: self.__jpd_id_cache)
149
+ def __get_jpd_id(self, base_url: str) -> str:
150
+ url: str = urljoin(base_url, "/jfconnect/api/v1/system/jpd_id")
151
+ response: Response = requests.get(url=url, timeout=15, auth=self.get_auth())
152
+
153
+ if response.status_code == 200:
154
+ return response.text
155
+
156
+ if response.status_code == 401:
157
+ raise FrogmlLoginException(
158
+ "Failed to authenticate with JFrog. Please check your credentials"
159
+ )
160
+ else:
161
+ raise FrogmlLoginException(
162
+ "Failed to authenticate with JFrog. Please check your artifactory configuration"
163
+ )
164
+
165
+ def __get_base_token_retriever(self) -> Callable[[], str]:
166
+ if JF_ACCESS_TOKEN_RELOAD_INTERVAL_SECONDS not in os.environ:
167
+ # no reload interval configured, preserve the original behavior of reading each time
168
+ return self.get_base_token
169
+
170
+ # base token reload interval is configured, wrap the basic retrieval with a cache
171
+ try:
172
+ ttl: int = int(os.getenv(JF_ACCESS_TOKEN_RELOAD_INTERVAL_SECONDS))
173
+ except ValueError:
174
+ raise FrogmlLoginException(
175
+ f"Value of {JF_ACCESS_TOKEN_RELOAD_INTERVAL_SECONDS} should be an integer"
176
+ )
177
+
178
+ cache: TTLCache = TTLCache(ttl=ttl, maxsize=1)
179
+
180
+ # Use a constant key since this is a nested function with no parameters
181
+ @cached(cache=cache)
182
+ def get_token() -> str:
183
+ return self.get_base_token()
184
+
185
+ return get_token
186
+
187
+ @staticmethod
188
+ def __remove_artifactory_path_from_url(artifactory_url: str) -> str:
189
+ # Remove '/artifactory' from the URL
190
+ base_url: str = artifactory_url.replace("/artifactory", "", 1)
191
+ # Remove trailing slash if exists
192
+ return base_url.rstrip("/")
@@ -0,0 +1,119 @@
1
+ import threading
2
+ import time
3
+ from typing import Any, Optional
4
+ from urllib.parse import urljoin
5
+
6
+ import requests
7
+ from frogml.core.exceptions import FrogmlLoginException
8
+ from frogml.storage.authentication.models import BearerAuth
9
+ from pydantic import BaseModel, ConfigDict, Field, PrivateAttr
10
+ from requests import Response
11
+
12
+
13
+ class TokenMaintainer(BaseModel):
14
+ model_config = ConfigDict(frozen=True)
15
+
16
+ token_rotation_interval_seconds: int = Field(ge=0)
17
+ token_rotation_grace_period_seconds: int = Field(ge=0)
18
+ token_rotation_generation_timeout_seconds: int = Field(ge=0)
19
+ base_token: str
20
+ base_url: str
21
+ __token_scope: str = ""
22
+ __curr_token: Optional[str] = None
23
+ __curr_token_cache_expiration: float
24
+ __lock: threading.RLock = PrivateAttr(default_factory=threading.RLock)
25
+ __refreshing: bool = False
26
+
27
+ def model_post_init(self, context: Any, /) -> None:
28
+ self.__curr_token_cache_expiration = (
29
+ -2
30
+ * (
31
+ self.token_rotation_interval_seconds
32
+ + self.token_rotation_grace_period_seconds
33
+ )
34
+ - 1.0
35
+ )
36
+
37
+ self.__extract_token_scope()
38
+
39
+ def get_token(self) -> str:
40
+ curr_time = time.monotonic()
41
+
42
+ if curr_time > self.__curr_token_cache_expiration:
43
+ # need to refresh (either because it's about to expire it was never loaded)
44
+ # note that this does not necessarily mean the current value can't be used
45
+ self.trigger_background_load()
46
+
47
+ if (
48
+ curr_time
49
+ > self.__curr_token_cache_expiration
50
+ + self.token_rotation_grace_period_seconds
51
+ ):
52
+ # the current value is either no longer valid (passed its grace) or was never loaded, return the base token
53
+ return self.base_token
54
+
55
+ return self.__curr_token
56
+
57
+ def __refresh(self):
58
+ next_curr_value_expiration: float = (
59
+ time.monotonic() + self.token_rotation_interval_seconds
60
+ )
61
+ try:
62
+ token = self.__generate_token()
63
+ with self.__lock:
64
+ self.__curr_token = token
65
+ self.__curr_token_cache_expiration = next_curr_value_expiration
66
+ finally:
67
+ with self.__lock:
68
+ self.__refreshing = False
69
+
70
+ def __generate_token(self) -> str:
71
+ try:
72
+ url: str = urljoin(self.base_url, "/access/api/v1/tokens")
73
+ token_life_duration: int = int(
74
+ self.token_rotation_interval_seconds
75
+ + self.token_rotation_grace_period_seconds
76
+ )
77
+ resp: Response = requests.post(
78
+ url,
79
+ data={"expires_in": token_life_duration, "scope": self.__token_scope},
80
+ auth=BearerAuth(self.base_token),
81
+ timeout=self.token_rotation_generation_timeout_seconds,
82
+ )
83
+ resp.raise_for_status()
84
+ return resp.json()["access_token"]
85
+ except Exception as e:
86
+ raise FrogmlLoginException("Failed to generate token: {}".format(e)) from e
87
+
88
+ def trigger_background_load(self):
89
+ with self.__lock:
90
+ if self.__refreshing:
91
+ # another refresh is ongoing, do not disturb it
92
+ return
93
+ # first start a thread for refreshing the token,
94
+ # then mark self as refreshing (to prevent a phantom refresh)
95
+ threading.Thread(target=self.__refresh, daemon=True).start()
96
+ self.__refreshing = True
97
+
98
+ def __extract_token_scope(self):
99
+ # parsing the base token to get its scope (which is used for generating new ones)
100
+ # note that here it does not matter whether the token is valid or not, we care
101
+ # only about the scope
102
+ try:
103
+ import jwt
104
+
105
+ parsed_token = jwt.decode(
106
+ self.base_token,
107
+ options={
108
+ "verify_signature": False
109
+ }, # NOSONAR(S5659) we only parse the token, no authentication happens here
110
+ )
111
+ except Exception as e:
112
+ raise FrogmlLoginException(
113
+ "Failed to decode JWT token: {}".format(e)
114
+ ) from e
115
+
116
+ if "scp" not in parsed_token:
117
+ raise FrogmlLoginException("Invalid token - missing scp claim")
118
+
119
+ self.__token_scope = parsed_token["scp"]
@@ -1,42 +1,41 @@
1
- from typing import TYPE_CHECKING, Callable, Optional, Tuple
2
-
3
1
  import grpc
2
+ from typing_extensions import Self
4
3
 
5
4
  from frogml.core.inner.const import FrogMLConstants
6
-
7
- if TYPE_CHECKING:
8
- from frogml.core.inner.tool.auth import FrogMLAuthClient
9
-
10
- _SIGNATURE_HEADER_KEY = "authorization"
5
+ from frogml.core.inner.tool.auth import FrogMLAuthClient
11
6
 
12
7
 
13
8
  class FrogMLAuthMetadataPlugin(grpc.AuthMetadataPlugin):
14
- def __init__(self):
15
- self._auth_client: Optional["FrogMLAuthClient"] = None
9
+ def __init__(self: Self, should_pass_jf_tenant_id: bool = True):
10
+ self.__auth_client = FrogMLAuthClient()
11
+ self.__should_pass_jf_tenant_id: bool = should_pass_jf_tenant_id
16
12
 
17
13
  def __call__(
18
14
  self,
19
15
  context: grpc.AuthMetadataContext,
20
- callback: Callable[[Tuple[Tuple[str, str], Tuple[str, str]], None], None],
16
+ callback: grpc.AuthMetadataPluginCallback,
21
17
  ):
22
18
  """Implements authentication by passing metadata to a callback.
23
19
 
24
20
  Args:
25
21
  context: An AuthMetadataContext providing information on the RPC that
26
22
  the plugin is being called to authenticate.
27
- callback: A callback that accepts a tuple of metadata key/value pairs and a None
23
+ callback: A callback that accepts a sequence of metadata key/value pairs and a None
28
24
  parameter.
29
25
  """
30
- # Get token from FrogML client
31
- if not self._auth_client:
32
- from frogml.core.inner.tool.auth import FrogMLAuthClient
33
-
34
- self._auth_client = FrogMLAuthClient()
35
-
36
- token = self._auth_client.get_token()
37
- jfrog_tenant_id = self._auth_client.get_tenant_id()
38
- metadata = (
39
- (_SIGNATURE_HEADER_KEY, f"Bearer {token}"),
40
- (FrogMLConstants.JFROG_TENANT_HEADER_KEY.lower(), jfrog_tenant_id),
41
- )
26
+ token: str = self.__auth_client.get_token()
27
+ metadata: list[tuple[str, str]] = [
28
+ (FrogMLConstants.SIGNATURE_HEADER_KEY, f"Bearer {token}")
29
+ ]
30
+
31
+ if self.__should_pass_jf_tenant_id:
32
+ jfrog_tenant_id: str = self.__auth_client.get_tenant_id()
33
+ metadata.append(
34
+ (FrogMLConstants.JFROG_TENANT_HEADER_KEY.lower(), jfrog_tenant_id)
35
+ )
36
+
42
37
  callback(metadata, None)
38
+
39
+ @property
40
+ def should_pass_jf_tenant_id(self: Self) -> bool:
41
+ return self.__should_pass_jf_tenant_id
@@ -1,15 +1,18 @@
1
1
  import logging
2
+ import re
2
3
  import time
3
4
  from abc import ABC, abstractmethod
4
5
  from random import randint
5
6
  from typing import Callable, Optional, Tuple
7
+ from urllib.parse import urlparse, ParseResult
6
8
 
7
9
  import grpc
8
10
 
9
- from frogml.core.exceptions import FrogmlException
11
+ from frogml.core.exceptions import FrogmlGrpcAddressException, FrogmlException
10
12
  from frogml.core.inner.tool.grpc.grpc_auth import FrogMLAuthMetadataPlugin
11
13
 
12
14
  logger = logging.getLogger()
15
+ HOSTNAME_REGEX: str = r"^(?!-)(?:[A-Za-z0-9-]{1,63}\.)*[A-Za-z0-9-]{1,63}(?<!-)$"
13
16
 
14
17
 
15
18
  def create_grpc_channel(
@@ -23,6 +26,7 @@ def create_grpc_channel(
23
26
  max_attempts=4,
24
27
  status_for_retry=(grpc.StatusCode.UNAVAILABLE,),
25
28
  attempt=0,
29
+ should_pass_jf_tenant_id: bool = True,
26
30
  ) -> grpc.Channel:
27
31
  """
28
32
  Create a gRPC channel
@@ -36,16 +40,17 @@ def create_grpc_channel(
36
40
  options: An optional list of key-value pairs (channel_arguments in gRPC Core runtime) to configure the channel.
37
41
  backoff_options: dictionary - init_backoff_ms: default 50, max_backoff_ms: default 500, multiplier: default 2
38
42
  max_attempts: max number of retry attempts
39
- attempt: current retry attempts
40
43
  status_for_retry: grpc statuses to retry upon
44
+ attempt: current retry attempts
45
+ should_pass_jf_tenant_id: Whether to pass JFrog tenant ID in metadata (if auth is enabled)
41
46
  Returns: Returns a grpc.Channel
42
47
  """
43
48
  if backoff_options is None:
44
49
  backoff_options = {}
45
50
 
46
51
  if not url:
47
- raise FrogmlException(
48
- "Unable to create gRPC channel. URL has not been defined."
52
+ raise FrogmlGrpcAddressException(
53
+ "Unable to create gRPC channel. URL has not been defined.", url
49
54
  )
50
55
 
51
56
  if enable_ssl or url.endswith(":443"):
@@ -53,7 +58,9 @@ def create_grpc_channel(
53
58
 
54
59
  if enable_auth:
55
60
  if auth_metadata_plugin is None:
56
- auth_metadata_plugin = FrogMLAuthMetadataPlugin()
61
+ auth_metadata_plugin = FrogMLAuthMetadataPlugin(
62
+ should_pass_jf_tenant_id
63
+ )
57
64
 
58
65
  credentials = grpc.composite_channel_credentials(
59
66
  credentials, grpc.metadata_call_credentials(auth_metadata_plugin)
@@ -99,7 +106,7 @@ def create_grpc_channel(
99
106
  return intercept_channel
100
107
  except grpc.FutureTimeoutError as e:
101
108
  raise FrogmlException(
102
- f"Connection timed out while attempting to connect to {url}, with: {repr(e)}"
109
+ f"Connection timed out while attempting to connect to {url}, with: {repr(e)}",
103
110
  ) from e
104
111
 
105
112
 
@@ -114,6 +121,7 @@ def create_grpc_channel_or_none(
114
121
  max_attempts=2,
115
122
  status_for_retry=(grpc.StatusCode.UNAVAILABLE,),
116
123
  attempt=0,
124
+ should_pass_jf_tenant_id: bool = True,
117
125
  ) -> Callable[[Optional[str], Optional[bool]], Optional[grpc.Channel]]:
118
126
  final_backoff_options = backoff_options if backoff_options else {}
119
127
 
@@ -132,6 +140,7 @@ def create_grpc_channel_or_none(
132
140
  max_attempts,
133
141
  status_for_retry,
134
142
  attempt,
143
+ should_pass_jf_tenant_id,
135
144
  )
136
145
  except Exception as e:
137
146
  logger.debug(f"create_grpc_channel error: {repr(e)}")
@@ -140,6 +149,117 @@ def create_grpc_channel_or_none(
140
149
  return deferred_channel
141
150
 
142
151
 
152
+ def validate_grpc_address(
153
+ grpc_address: str,
154
+ is_port_specification_allowed: bool = False,
155
+ is_url_scheme_allowed: bool = False,
156
+ ):
157
+ """
158
+ Validate gRPC address format
159
+ Args:
160
+ grpc_address (str): gRPC address to validate
161
+ is_port_specification_allowed (bool): Whether to allow port specification in the address
162
+ is_url_scheme_allowed (bool): Whether to allow URL scheme in the address
163
+ Raises:
164
+ FrogmlGrpcAddressException: If the gRPC address is invalid
165
+ """
166
+ parsed_grpc_address: ParseResult = parse_address(grpc_address)
167
+ hostname: str = get_hostname_from_address(parsed_grpc_address)
168
+ validate_paths_are_not_included_in_address(parsed_grpc_address)
169
+
170
+ if not is_url_scheme_allowed:
171
+ __validate_url_scheme_not_included_in_address(parsed_grpc_address)
172
+
173
+ if not is_port_specification_allowed:
174
+ __validate_port_not_included_in_address(parsed_grpc_address)
175
+
176
+ if not is_valid_hostname(hostname):
177
+ raise FrogmlGrpcAddressException(
178
+ "gRPC address must be a simple hostname or fully qualified domain name.",
179
+ parsed_grpc_address,
180
+ )
181
+
182
+
183
+ def validate_paths_are_not_included_in_address(
184
+ parsed_grpc_address: ParseResult,
185
+ ) -> None:
186
+ has_invalid_path: bool = (
187
+ parsed_grpc_address.path not in {"", "/"}
188
+ or parsed_grpc_address.query
189
+ or parsed_grpc_address.fragment
190
+ )
191
+
192
+ if has_invalid_path:
193
+ raise FrogmlGrpcAddressException(
194
+ "gRPC address must not contain paths, queries, or fragments.",
195
+ parsed_grpc_address,
196
+ )
197
+
198
+
199
+ def get_hostname_from_address(parsed_grpc_address: ParseResult) -> str:
200
+ hostname: Optional[str] = parsed_grpc_address.hostname
201
+ if not hostname:
202
+ raise FrogmlGrpcAddressException(
203
+ "gRPC address must contain a valid hostname.", parsed_grpc_address
204
+ )
205
+
206
+ return hostname
207
+
208
+
209
+ def __validate_url_scheme_not_included_in_address(
210
+ parsed_grpc_address: ParseResult,
211
+ ) -> None:
212
+ if parsed_grpc_address.scheme:
213
+ raise FrogmlGrpcAddressException(
214
+ "URL scheme is not allowed in the gRPC address.", parsed_grpc_address
215
+ )
216
+
217
+
218
+ def __validate_port_not_included_in_address(parsed_grpc_address: ParseResult):
219
+ try:
220
+ port: Optional[int] = parsed_grpc_address.port
221
+ except ValueError as exc:
222
+ raise FrogmlGrpcAddressException(
223
+ "Invalid port specification in the gRPC address.", parsed_grpc_address
224
+ ) from exc
225
+
226
+ if port:
227
+ raise FrogmlGrpcAddressException(
228
+ "Port specification is not allowed in the gRPC address.",
229
+ parsed_grpc_address,
230
+ )
231
+
232
+
233
+ def parse_address(grpc_address: str) -> ParseResult:
234
+ if not grpc_address or not grpc_address.strip():
235
+ raise FrogmlGrpcAddressException(
236
+ "gRPC address must not be empty or whitespace.", grpc_address
237
+ )
238
+
239
+ trimmed_address: str = grpc_address.strip()
240
+ parsed_address: ParseResult = urlparse(
241
+ trimmed_address if "://" in trimmed_address else f"//{trimmed_address}"
242
+ )
243
+
244
+ return parsed_address
245
+
246
+
247
+ def is_valid_hostname(hostname: str) -> bool:
248
+ """
249
+ Validate that the supplied hostname conforms to RFC-style label rules:
250
+ anchored pattern enforces full-string validation, negative lookahead/lookbehind block
251
+ leading or trailing hyphens per label, and each dot-separated label must be 1-63
252
+ alphanumeric/hyphen characters.
253
+
254
+ Args:
255
+ hostname (str): The hostname to validate.
256
+ Returns:
257
+ bool: True if the hostname is valid, False otherwise.
258
+ """
259
+ hostname_pattern: re.Pattern = re.compile(HOSTNAME_REGEX)
260
+ return bool(hostname_pattern.fullmatch(hostname))
261
+
262
+
143
263
  class SleepingPolicy(ABC):
144
264
  @abstractmethod
145
265
  def sleep(self, try_i: int):