6565 _warn_on_overwriting_operations ,
6666)
6767from ._inference_endpoints import InferenceEndpoint , InferenceEndpointType
68- from ._jobs_api import JobInfo , ScheduledJobInfo , _create_job_spec
68+ from ._jobs_api import JobInfo , JobSpec , ScheduledJobInfo , _create_job_spec
6969from ._space_api import SpaceHardware , SpaceRuntime , SpaceStorage , SpaceVariable
7070from ._upload_large_folder import upload_large_folder_internal
7171from .community import (
@@ -503,11 +503,15 @@ class WebhookWatchedItem:
503503class WebhookInfo :
504504 """Data structure containing information about a webhook.
505505
506+ One of `url` or `job` is specified, but not both.
507+
506508 Attributes:
507509 id (`str`):
508510 ID of the webhook.
509- url (`str`):
511+ url (`str`, *optional* ):
510512 URL of the webhook.
513+ job (`JobSpec`, *optional*):
514+ Specifications of the Job to trigger.
511515 watched (`List[WebhookWatchedItem]`):
512516 List of items watched by the webhook, see [`WebhookWatchedItem`].
513517 domains (`List[WEBHOOK_DOMAIN_T]`):
@@ -519,7 +523,8 @@ class WebhookInfo:
519523 """
520524
521525 id : str
522- url : str
526+ url : Optional [str ]
527+ job : Optional [JobSpec ]
523528 watched : List [WebhookWatchedItem ]
524529 domains : List [constants .WEBHOOK_DOMAIN_T ]
525530 secret : Optional [str ]
@@ -9035,6 +9040,7 @@ def get_webhook(self, webhook_id: str, *, token: Union[bool, str, None] = None)
90359040 >>> print(webhook)
90369041 WebhookInfo(
90379042 id="654bbbc16f2ec14d77f109cc",
9043+ job=None,
90389044 watched=[WebhookWatchedItem(type="user", name="julien-c"), WebhookWatchedItem(type="org", name="HuggingFaceH4")],
90399045 url="https://webhook.site/a2176e82-5720-43ee-9e06-f91cb4c91548",
90409046 secret="my-secret",
@@ -9054,7 +9060,8 @@ def get_webhook(self, webhook_id: str, *, token: Union[bool, str, None] = None)
90549060
90559061 webhook = WebhookInfo (
90569062 id = webhook_data ["id" ],
9057- url = webhook_data ["url" ],
9063+ url = webhook_data .get ("url" ),
9064+ job = JobSpec (** webhook_data ["job" ]) if webhook_data .get ("job" ) else None ,
90589065 watched = watched_items ,
90599066 domains = webhook_data ["domains" ],
90609067 secret = webhook_data .get ("secret" ),
@@ -9104,7 +9111,8 @@ def list_webhooks(self, *, token: Union[bool, str, None] = None) -> List[Webhook
91049111 return [
91059112 WebhookInfo (
91069113 id = webhook ["id" ],
9107- url = webhook ["url" ],
9114+ url = webhook .get ("url" ),
9115+ job = JobSpec (** webhook ["job" ]) if webhook .get ("job" ) else None ,
91089116 watched = [WebhookWatchedItem (type = item ["type" ], name = item ["name" ]) for item in webhook ["watched" ]],
91099117 domains = webhook ["domains" ],
91109118 secret = webhook .get ("secret" ),
@@ -9117,17 +9125,24 @@ def list_webhooks(self, *, token: Union[bool, str, None] = None) -> List[Webhook
91179125 def create_webhook (
91189126 self ,
91199127 * ,
9120- url : str ,
9128+ url : Optional [str ] = None ,
9129+ job_id : Optional [str ] = None ,
91219130 watched : List [Union [Dict , WebhookWatchedItem ]],
91229131 domains : Optional [List [constants .WEBHOOK_DOMAIN_T ]] = None ,
91239132 secret : Optional [str ] = None ,
91249133 token : Union [bool , str , None ] = None ,
91259134 ) -> WebhookInfo :
91269135 """Create a new webhook.
91279136
9137+ The webhook can either send a payload to a URL, or trigger a Job to run on Hugging Face infrastructure.
9138+ This function should be called with one of `url` or `job_id`, but not both.
9139+
91289140 Args:
91299141 url (`str`):
91309142 URL to send the payload to.
9143+ job_id (`str`):
9144+ ID of the source Job to trigger with the webhook payload in the environment variable WEBHOOK_PAYLOAD.
9145+ Additional environment variables are available for convenience: WEBHOOK_REPO_ID, WEBHOOK_REPO_TYPE and WEBHOOK_SECRET.
91319146 watched (`List[WebhookWatchedItem]`):
91329147 List of [`WebhookWatchedItem`] to be watched by the webhook. It can be users, orgs, models, datasets or spaces.
91339148 Watched items can also be provided as plain dictionaries.
@@ -9145,6 +9160,8 @@ def create_webhook(
91459160 Info about the newly created webhook.
91469161
91479162 Example:
9163+
9164+ Create a webhook that sends a payload to a URL
91489165 ```python
91499166 >>> from huggingface_hub import create_webhook
91509167 >>> payload = create_webhook(
@@ -9157,6 +9174,43 @@ def create_webhook(
91579174 WebhookInfo(
91589175 id="654bbbc16f2ec14d77f109cc",
91599176 url="https://webhook.site/a2176e82-5720-43ee-9e06-f91cb4c91548",
9177+ job=None,
9178+ watched=[WebhookWatchedItem(type="user", name="julien-c"), WebhookWatchedItem(type="org", name="HuggingFaceH4")],
9179+ domains=["repo", "discussion"],
9180+ secret="my-secret",
9181+ disabled=False,
9182+ )
9183+ ```
9184+
9185+ Run a Job and then create a webhook that triggers this Job
9186+ ```python
9187+ >>> from huggingface_hub import create_webhook, run_job
9188+ >>> job = run_job(
9189+ ... image="ubuntu",
9190+ ... command=["bash", "-c", r"echo An event occured in $WEBHOOK_REPO_ID: $WEBHOOK_PAYLOAD"],
9191+ ... )
9192+ >>> payload = create_webhook(
9193+ ... watched=[{"type": "user", "name": "julien-c"}, {"type": "org", "name": "HuggingFaceH4"}],
9194+ ... job_id=job.id,
9195+ ... domains=["repo", "discussion"],
9196+ ... secret="my-secret",
9197+ ... )
9198+ >>> print(payload)
9199+ WebhookInfo(
9200+ id="654bbbc16f2ec14d77f109cc",
9201+ url=None,
9202+ job=JobSpec(
9203+ docker_image='ubuntu',
9204+ space_id=None,
9205+ command=['bash', '-c', 'echo An event occured in $WEBHOOK_REPO_ID: $WEBHOOK_PAYLOAD'],
9206+ arguments=[],
9207+ environment={},
9208+ secrets=[],
9209+ flavor='cpu-basic',
9210+ timeout=None,
9211+ tags=None,
9212+ arch=None
9213+ ),
91609214 watched=[WebhookWatchedItem(type="user", name="julien-c"), WebhookWatchedItem(type="org", name="HuggingFaceH4")],
91619215 domains=["repo", "discussion"],
91629216 secret="my-secret",
@@ -9166,9 +9220,19 @@ def create_webhook(
91669220 """
91679221 watched_dicts = [asdict (item ) if isinstance (item , WebhookWatchedItem ) else item for item in watched ]
91689222
9223+ post_webhooks_json = {"watched" : watched_dicts , "domains" : domains , "secret" : secret }
9224+ if url is not None and job_id is not None :
9225+ raise ValueError ("Set `url` or `job_id` but not both." )
9226+ elif url is not None :
9227+ post_webhooks_json ["url" ] = url
9228+ elif job_id is not None :
9229+ post_webhooks_json ["jobSourceId" ] = job_id
9230+ else :
9231+ raise ValueError ("Missing argument for webhook: `url` or `job_id`." )
9232+
91699233 response = get_session ().post (
91709234 f"{ constants .ENDPOINT } /api/settings/webhooks" ,
9171- json = { "watched" : watched_dicts , "url" : url , "domains" : domains , "secret" : secret } ,
9235+ json = post_webhooks_json ,
91729236 headers = self ._build_hf_headers (token = token ),
91739237 )
91749238 hf_raise_for_status (response )
@@ -9177,7 +9241,8 @@ def create_webhook(
91779241
91789242 webhook = WebhookInfo (
91799243 id = webhook_data ["id" ],
9180- url = webhook_data ["url" ],
9244+ url = webhook_data .get ("url" ),
9245+ job = JobSpec (** webhook_data ["job" ]) if webhook_data .get ("job" ) else None ,
91819246 watched = watched_items ,
91829247 domains = webhook_data ["domains" ],
91839248 secret = webhook_data .get ("secret" ),
@@ -9233,6 +9298,7 @@ def update_webhook(
92339298 >>> print(updated_payload)
92349299 WebhookInfo(
92359300 id="654bbbc16f2ec14d77f109cc",
9301+ job=None,
92369302 url="https://new.webhook.site/a2176e82-5720-43ee-9e06-f91cb4c91548",
92379303 watched=[WebhookWatchedItem(type="user", name="julien-c"), WebhookWatchedItem(type="org", name="HuggingFaceH4")],
92389304 domains=["repo"],
@@ -9256,7 +9322,8 @@ def update_webhook(
92569322
92579323 webhook = WebhookInfo (
92589324 id = webhook_data ["id" ],
9259- url = webhook_data ["url" ],
9325+ url = webhook_data .get ("url" ),
9326+ job = JobSpec (** webhook_data ["job" ]) if webhook_data .get ("job" ) else None ,
92609327 watched = watched_items ,
92619328 domains = webhook_data ["domains" ],
92629329 secret = webhook_data .get ("secret" ),
@@ -9288,6 +9355,7 @@ def enable_webhook(self, webhook_id: str, *, token: Union[bool, str, None] = Non
92889355 >>> enabled_webhook
92899356 WebhookInfo(
92909357 id="654bbbc16f2ec14d77f109cc",
9358+ job=None,
92919359 url="https://webhook.site/a2176e82-5720-43ee-9e06-f91cb4c91548",
92929360 watched=[WebhookWatchedItem(type="user", name="julien-c"), WebhookWatchedItem(type="org", name="HuggingFaceH4")],
92939361 domains=["repo", "discussion"],
@@ -9307,7 +9375,8 @@ def enable_webhook(self, webhook_id: str, *, token: Union[bool, str, None] = Non
93079375
93089376 webhook = WebhookInfo (
93099377 id = webhook_data ["id" ],
9310- url = webhook_data ["url" ],
9378+ url = webhook_data .get ("url" ),
9379+ job = JobSpec (** webhook_data ["job" ]) if webhook_data .get ("job" ) else None ,
93119380 watched = watched_items ,
93129381 domains = webhook_data ["domains" ],
93139382 secret = webhook_data .get ("secret" ),
@@ -9340,6 +9409,7 @@ def disable_webhook(self, webhook_id: str, *, token: Union[bool, str, None] = No
93409409 WebhookInfo(
93419410 id="654bbbc16f2ec14d77f109cc",
93429411 url="https://webhook.site/a2176e82-5720-43ee-9e06-f91cb4c91548",
9412+ jon=None,
93439413 watched=[WebhookWatchedItem(type="user", name="julien-c"), WebhookWatchedItem(type="org", name="HuggingFaceH4")],
93449414 domains=["repo", "discussion"],
93459415 secret="my-secret",
@@ -9358,7 +9428,8 @@ def disable_webhook(self, webhook_id: str, *, token: Union[bool, str, None] = No
93589428
93599429 webhook = WebhookInfo (
93609430 id = webhook_data ["id" ],
9361- url = webhook_data ["url" ],
9431+ url = webhook_data .get ("url" ),
9432+ job = JobSpec (** webhook_data ["job" ]) if webhook_data .get ("job" ) else None ,
93629433 watched = watched_items ,
93639434 domains = webhook_data ["domains" ],
93649435 secret = webhook_data .get ("secret" ),
0 commit comments