huggingface-hub 0.34.5__py3-none-any.whl → 0.35.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.

Potentially problematic release.


This version of huggingface-hub might be problematic. Click here for more details.

Files changed (40) hide show
  1. huggingface_hub/__init__.py +19 -1
  2. huggingface_hub/_jobs_api.py +159 -2
  3. huggingface_hub/_tensorboard_logger.py +9 -10
  4. huggingface_hub/cli/auth.py +1 -1
  5. huggingface_hub/cli/cache.py +3 -9
  6. huggingface_hub/cli/jobs.py +551 -1
  7. huggingface_hub/cli/repo.py +6 -4
  8. huggingface_hub/commands/delete_cache.py +2 -2
  9. huggingface_hub/commands/scan_cache.py +1 -1
  10. huggingface_hub/commands/user.py +1 -1
  11. huggingface_hub/hf_api.py +522 -78
  12. huggingface_hub/hf_file_system.py +3 -1
  13. huggingface_hub/hub_mixin.py +5 -3
  14. huggingface_hub/inference/_client.py +18 -181
  15. huggingface_hub/inference/_common.py +72 -70
  16. huggingface_hub/inference/_generated/_async_client.py +35 -201
  17. huggingface_hub/inference/_generated/types/chat_completion.py +2 -0
  18. huggingface_hub/inference/_mcp/_cli_hacks.py +3 -3
  19. huggingface_hub/inference/_mcp/cli.py +1 -1
  20. huggingface_hub/inference/_mcp/constants.py +1 -1
  21. huggingface_hub/inference/_mcp/mcp_client.py +28 -11
  22. huggingface_hub/inference/_mcp/types.py +3 -0
  23. huggingface_hub/inference/_mcp/utils.py +7 -3
  24. huggingface_hub/inference/_providers/__init__.py +5 -0
  25. huggingface_hub/inference/_providers/_common.py +28 -4
  26. huggingface_hub/inference/_providers/black_forest_labs.py +1 -1
  27. huggingface_hub/inference/_providers/fal_ai.py +2 -2
  28. huggingface_hub/inference/_providers/hf_inference.py +15 -7
  29. huggingface_hub/inference/_providers/publicai.py +6 -0
  30. huggingface_hub/inference/_providers/replicate.py +1 -1
  31. huggingface_hub/repocard.py +2 -1
  32. huggingface_hub/utils/_git_credential.py +1 -1
  33. huggingface_hub/utils/_typing.py +24 -4
  34. huggingface_hub/utils/_xet_progress_reporting.py +31 -10
  35. {huggingface_hub-0.34.5.dist-info → huggingface_hub-0.35.0.dist-info}/METADATA +7 -4
  36. {huggingface_hub-0.34.5.dist-info → huggingface_hub-0.35.0.dist-info}/RECORD +40 -39
  37. {huggingface_hub-0.34.5.dist-info → huggingface_hub-0.35.0.dist-info}/LICENSE +0 -0
  38. {huggingface_hub-0.34.5.dist-info → huggingface_hub-0.35.0.dist-info}/WHEEL +0 -0
  39. {huggingface_hub-0.34.5.dist-info → huggingface_hub-0.35.0.dist-info}/entry_points.txt +0 -0
  40. {huggingface_hub-0.34.5.dist-info → huggingface_hub-0.35.0.dist-info}/top_level.txt +0 -0
huggingface_hub/hf_api.py CHANGED
@@ -67,7 +67,7 @@ from ._commit_api import (
67
67
  _warn_on_overwriting_operations,
68
68
  )
69
69
  from ._inference_endpoints import InferenceEndpoint, InferenceEndpointType
70
- from ._jobs_api import JobInfo
70
+ from ._jobs_api import JobInfo, ScheduledJobInfo, _create_job_spec
71
71
  from ._space_api import SpaceHardware, SpaceRuntime, SpaceStorage, SpaceVariable
72
72
  from ._upload_large_folder import upload_large_folder_internal
73
73
  from .community import (
@@ -137,7 +137,7 @@ from .utils._auth import (
137
137
  _get_token_from_file,
138
138
  _get_token_from_google_colab,
139
139
  )
140
- from .utils._deprecation import _deprecate_method
140
+ from .utils._deprecation import _deprecate_arguments, _deprecate_method
141
141
  from .utils._runtime import is_xet_available
142
142
  from .utils._typing import CallableT
143
143
  from .utils.endpoint_helpers import _is_emission_within_threshold
@@ -1855,6 +1855,9 @@ class HfApi:
1855
1855
  hf_raise_for_status(r)
1856
1856
  return r.json()
1857
1857
 
1858
+ @_deprecate_arguments(
1859
+ version="1.0", deprecated_args=["language", "library", "task", "tags"], custom_message="Use `filter` instead."
1860
+ )
1858
1861
  @validate_hf_hub_args
1859
1862
  def list_models(
1860
1863
  self,
@@ -1862,15 +1865,12 @@ class HfApi:
1862
1865
  # Search-query parameter
1863
1866
  filter: Union[str, Iterable[str], None] = None,
1864
1867
  author: Optional[str] = None,
1868
+ apps: Optional[Union[str, List[str]]] = None,
1865
1869
  gated: Optional[bool] = None,
1866
1870
  inference: Optional[Literal["warm"]] = None,
1867
1871
  inference_provider: Optional[Union[Literal["all"], "PROVIDER_T", List["PROVIDER_T"]]] = None,
1868
- library: Optional[Union[str, List[str]]] = None,
1869
- language: Optional[Union[str, List[str]]] = None,
1870
1872
  model_name: Optional[str] = None,
1871
- task: Optional[Union[str, List[str]]] = None,
1872
1873
  trained_dataset: Optional[Union[str, List[str]]] = None,
1873
- tags: Optional[Union[str, List[str]]] = None,
1874
1874
  search: Optional[str] = None,
1875
1875
  pipeline_tag: Optional[str] = None,
1876
1876
  emissions_thresholds: Optional[Tuple[float, float]] = None,
@@ -1884,6 +1884,11 @@ class HfApi:
1884
1884
  cardData: bool = False,
1885
1885
  fetch_config: bool = False,
1886
1886
  token: Union[bool, str, None] = None,
1887
+ # Deprecated arguments - use `filter` instead
1888
+ language: Optional[Union[str, List[str]]] = None,
1889
+ library: Optional[Union[str, List[str]]] = None,
1890
+ tags: Optional[Union[str, List[str]]] = None,
1891
+ task: Optional[Union[str, List[str]]] = None,
1887
1892
  ) -> Iterable[ModelInfo]:
1888
1893
  """
1889
1894
  List models hosted on the Huggingface Hub, given some filters.
@@ -1891,9 +1896,13 @@ class HfApi:
1891
1896
  Args:
1892
1897
  filter (`str` or `Iterable[str]`, *optional*):
1893
1898
  A string or list of string to filter models on the Hub.
1899
+ Models can be filtered by library, language, task, tags, and more.
1894
1900
  author (`str`, *optional*):
1895
1901
  A string which identify the author (user or organization) of the
1896
1902
  returned models.
1903
+ apps (`str` or `List`, *optional*):
1904
+ A string or list of strings to filter models on the Hub that
1905
+ support the specified apps. Example values include `"ollama"` or `["ollama", "vllm"]`.
1897
1906
  gated (`bool`, *optional*):
1898
1907
  A boolean to filter models on the Hub that are gated or not. By default, all models are returned.
1899
1908
  If `gated=True` is passed, only gated models are returned.
@@ -1904,23 +1913,19 @@ class HfApi:
1904
1913
  A string to filter models on the Hub that are served by a specific provider.
1905
1914
  Pass `"all"` to get all models served by at least one provider.
1906
1915
  library (`str` or `List`, *optional*):
1907
- A string or list of strings of foundational libraries models were
1908
- originally trained from, such as pytorch, tensorflow, or allennlp.
1916
+ Deprecated. Pass a library name in `filter` to filter models by library.
1909
1917
  language (`str` or `List`, *optional*):
1910
- A string or list of strings of languages, both by name and country
1911
- code, such as "en" or "English"
1918
+ Deprecated. Pass a language in `filter` to filter models by language.
1912
1919
  model_name (`str`, *optional*):
1913
1920
  A string that contain complete or partial names for models on the
1914
1921
  Hub, such as "bert" or "bert-base-cased"
1915
1922
  task (`str` or `List`, *optional*):
1916
- A string or list of strings of tasks models were designed for, such
1917
- as: "fill-mask" or "automatic-speech-recognition"
1923
+ Deprecated. Pass a task in `filter` to filter models by task.
1918
1924
  trained_dataset (`str` or `List`, *optional*):
1919
1925
  A string tag or a list of string tags of the trained dataset for a
1920
1926
  model on the Hub.
1921
1927
  tags (`str` or `List`, *optional*):
1922
- A string tag or a list of tags to filter models on the Hub by, such
1923
- as `text-generation` or `spacy`.
1928
+ Deprecated. Pass tags in `filter` to filter models by tags.
1924
1929
  search (`str`, *optional*):
1925
1930
  A string that will be contained in the returned model ids.
1926
1931
  pipeline_tag (`str`, *optional*):
@@ -1991,7 +1996,7 @@ class HfApi:
1991
1996
  if expand and (full or cardData or fetch_config):
1992
1997
  raise ValueError("`expand` cannot be used if `full`, `cardData` or `fetch_config` are passed.")
1993
1998
 
1994
- if emissions_thresholds is not None and cardData is None:
1999
+ if emissions_thresholds is not None and not cardData:
1995
2000
  raise ValueError("`emissions_thresholds` were passed without setting `cardData=True`.")
1996
2001
 
1997
2002
  path = f"{self.endpoint}/api/models"
@@ -2023,6 +2028,10 @@ class HfApi:
2023
2028
  # Handle other query params
2024
2029
  if author:
2025
2030
  params["author"] = author
2031
+ if apps:
2032
+ if isinstance(apps, str):
2033
+ apps = [apps]
2034
+ params["apps"] = apps
2026
2035
  if gated is not None:
2027
2036
  params["gated"] = gated
2028
2037
  if inference is not None:
@@ -2074,6 +2083,7 @@ class HfApi:
2074
2083
  if emissions_thresholds is None or _is_emission_within_threshold(model_info, *emissions_thresholds):
2075
2084
  yield model_info
2076
2085
 
2086
+ @_deprecate_arguments(version="1.0", deprecated_args=["tags"], custom_message="Use `filter` instead.")
2077
2087
  @validate_hf_hub_args
2078
2088
  def list_datasets(
2079
2089
  self,
@@ -2088,7 +2098,6 @@ class HfApi:
2088
2098
  language: Optional[Union[str, List[str]]] = None,
2089
2099
  multilinguality: Optional[Union[str, List[str]]] = None,
2090
2100
  size_categories: Optional[Union[str, List[str]]] = None,
2091
- tags: Optional[Union[str, List[str]]] = None,
2092
2101
  task_categories: Optional[Union[str, List[str]]] = None,
2093
2102
  task_ids: Optional[Union[str, List[str]]] = None,
2094
2103
  search: Optional[str] = None,
@@ -2100,6 +2109,8 @@ class HfApi:
2100
2109
  expand: Optional[List[ExpandDatasetProperty_T]] = None,
2101
2110
  full: Optional[bool] = None,
2102
2111
  token: Union[bool, str, None] = None,
2112
+ # Deprecated arguments - use `filter` instead
2113
+ tags: Optional[Union[str, List[str]]] = None,
2103
2114
  ) -> Iterable[DatasetInfo]:
2104
2115
  """
2105
2116
  List datasets hosted on the Huggingface Hub, given some filters.
@@ -2134,7 +2145,7 @@ class HfApi:
2134
2145
  the Hub by the size of the dataset such as `100K<n<1M` or
2135
2146
  `1M<n<10M`.
2136
2147
  tags (`str` or `List`, *optional*):
2137
- A string tag or a list of tags to filter datasets on the Hub.
2148
+ Deprecated. Pass tags in `filter` to filter datasets by tags.
2138
2149
  task_categories (`str` or `List`, *optional*):
2139
2150
  A string or list of strings that can be used to identify datasets on
2140
2151
  the Hub by the designed task, such as `audio_classification` or
@@ -10004,7 +10015,7 @@ class HfApi:
10004
10015
 
10005
10016
  ```python
10006
10017
  >>> from huggingface_hub import run_job
10007
- >>> run_job("python:3.12", ["python", "-c" ,"print('Hello from HF compute!')"])
10018
+ >>> run_job(image="python:3.12", command=["python", "-c" ,"print('Hello from HF compute!')"])
10008
10019
  ```
10009
10020
 
10010
10021
  Run a GPU Job:
@@ -10013,47 +10024,23 @@ class HfApi:
10013
10024
  >>> from huggingface_hub import run_job
10014
10025
  >>> image = "pytorch/pytorch:2.6.0-cuda12.4-cudnn9-devel"
10015
10026
  >>> command = ["python", "-c", "import torch; print(f"This code ran with the following GPU: {torch.cuda.get_device_name()}")"]
10016
- >>> run_job(image, command, flavor="a10g-small")
10027
+ >>> run_job(image=image, command=command, flavor="a10g-small")
10017
10028
  ```
10018
10029
 
10019
10030
  """
10020
- if flavor is None:
10021
- flavor = SpaceHardware.CPU_BASIC
10022
-
10023
- # prepare payload to send to HF Jobs API
10024
- input_json: Dict[str, Any] = {
10025
- "command": command,
10026
- "arguments": [],
10027
- "environment": env or {},
10028
- "flavor": flavor,
10029
- }
10030
- # secrets are optional
10031
- if secrets:
10032
- input_json["secrets"] = secrets
10033
- # timeout is optional
10034
- if timeout:
10035
- time_units_factors = {"s": 1, "m": 60, "h": 3600, "d": 3600 * 24}
10036
- if isinstance(timeout, str) and timeout[-1] in time_units_factors:
10037
- input_json["timeoutSeconds"] = int(float(timeout[:-1]) * time_units_factors[timeout[-1]])
10038
- else:
10039
- input_json["timeoutSeconds"] = int(timeout)
10040
- # input is either from docker hub or from HF spaces
10041
- for prefix in (
10042
- "https://huggingface.co/spaces/",
10043
- "https://hf.co/spaces/",
10044
- "huggingface.co/spaces/",
10045
- "hf.co/spaces/",
10046
- ):
10047
- if image.startswith(prefix):
10048
- input_json["spaceId"] = image[len(prefix) :]
10049
- break
10050
- else:
10051
- input_json["dockerImage"] = image
10052
10031
  if namespace is None:
10053
10032
  namespace = self.whoami(token=token)["name"]
10033
+ job_spec = _create_job_spec(
10034
+ image=image,
10035
+ command=command,
10036
+ env=env,
10037
+ secrets=secrets,
10038
+ flavor=flavor,
10039
+ timeout=timeout,
10040
+ )
10054
10041
  response = get_session().post(
10055
10042
  f"https://huggingface.co/api/jobs/{namespace}",
10056
- json=input_json,
10043
+ json=job_spec,
10057
10044
  headers=self._build_hf_headers(token=token),
10058
10045
  )
10059
10046
  hf_raise_for_status(response)
@@ -10086,8 +10073,8 @@ class HfApi:
10086
10073
 
10087
10074
  ```python
10088
10075
  >>> from huggingface_hub import fetch_job_logs, run_job
10089
- >>> job = run_job("python:3.12", ["python", "-c" ,"print('Hello from HF compute!')"])
10090
- >>> for log in fetch_job_logs(job.job_id):
10076
+ >>> job = run_job(image="python:3.12", command=["python", "-c" ,"print('Hello from HF compute!')"])
10077
+ >>> for log in fetch_job_logs(job.id):
10091
10078
  ... print(log)
10092
10079
  Hello from HF compute!
10093
10080
  ```
@@ -10210,8 +10197,8 @@ class HfApi:
10210
10197
 
10211
10198
  ```python
10212
10199
  >>> from huggingface_hub import inspect_job, run_job
10213
- >>> job = run_job("python:3.12", ["python", "-c" ,"print('Hello from HF compute!')"])
10214
- >>> inspect_job(job.job_id)
10200
+ >>> job = run_job(image="python:3.12", command=["python", "-c" ,"print('Hello from HF compute!')"])
10201
+ >>> inspect_job(job.id)
10215
10202
  JobInfo(
10216
10203
  id='68780d00bbe36d38803f645f',
10217
10204
  created_at=datetime.datetime(2025, 7, 16, 20, 35, 12, 808000, tzinfo=datetime.timezone.utc),
@@ -10286,10 +10273,10 @@ class HfApi:
10286
10273
 
10287
10274
  Args:
10288
10275
  script (`str`):
10289
- Path or URL of the UV script.
10276
+ Path or URL of the UV script, or a command.
10290
10277
 
10291
10278
  script_args (`List[str]`, *optional*)
10292
- Arguments to pass to the script.
10279
+ Arguments to pass to the script or command.
10293
10280
 
10294
10281
  dependencies (`List[str]`, *optional*)
10295
10282
  Dependencies to use to run the UV script.
@@ -10324,13 +10311,474 @@ class HfApi:
10324
10311
 
10325
10312
  Example:
10326
10313
 
10314
+ Run a script from a URL:
10315
+
10316
+ ```python
10317
+ >>> from huggingface_hub import run_uv_job
10318
+ >>> script = "https://raw.githubusercontent.com/huggingface/trl/refs/heads/main/trl/scripts/sft.py"
10319
+ >>> script_args = ["--model_name_or_path", "Qwen/Qwen2-0.5B", "--dataset_name", "trl-lib/Capybara", "--push_to_hub"]
10320
+ >>> run_uv_job(script, script_args=script_args, dependencies=["trl"], flavor="a10g-small")
10321
+ ```
10322
+
10323
+ Run a local script:
10324
+
10327
10325
  ```python
10328
10326
  >>> from huggingface_hub import run_uv_job
10327
+ >>> script = "my_sft.py"
10328
+ >>> script_args = ["--model_name_or_path", "Qwen/Qwen2-0.5B", "--dataset_name", "trl-lib/Capybara", "--push_to_hub"]
10329
+ >>> run_uv_job(script, script_args=script_args, dependencies=["trl"], flavor="a10g-small")
10330
+ ```
10331
+
10332
+ Run a command:
10333
+
10334
+ ```python
10335
+ >>> from huggingface_hub import run_uv_job
10336
+ >>> script = "lighteval"
10337
+ >>> script_args= ["endpoint", "inference-providers", "model_name=openai/gpt-oss-20b,provider=auto", "lighteval|gsm8k|0|0"]
10338
+ >>> run_uv_job(script, script_args=script_args, dependencies=["lighteval"], flavor="a10g-small")
10339
+ ```
10340
+ """
10341
+ image = image or "ghcr.io/astral-sh/uv:python3.12-bookworm"
10342
+ env = env or {}
10343
+ secrets = secrets or {}
10344
+
10345
+ # Build command
10346
+ command, env, secrets = self._create_uv_command_env_and_secrets(
10347
+ script=script,
10348
+ script_args=script_args,
10349
+ dependencies=dependencies,
10350
+ python=python,
10351
+ env=env,
10352
+ secrets=secrets,
10353
+ namespace=namespace,
10354
+ token=token,
10355
+ _repo=_repo,
10356
+ )
10357
+ # Create RunCommand args
10358
+ return self.run_job(
10359
+ image=image,
10360
+ command=command,
10361
+ env=env,
10362
+ secrets=secrets,
10363
+ flavor=flavor,
10364
+ timeout=timeout,
10365
+ namespace=namespace,
10366
+ token=token,
10367
+ )
10368
+
10369
+ def create_scheduled_job(
10370
+ self,
10371
+ *,
10372
+ image: str,
10373
+ command: List[str],
10374
+ schedule: str,
10375
+ suspend: Optional[bool] = None,
10376
+ concurrency: Optional[bool] = None,
10377
+ env: Optional[Dict[str, Any]] = None,
10378
+ secrets: Optional[Dict[str, Any]] = None,
10379
+ flavor: Optional[SpaceHardware] = None,
10380
+ timeout: Optional[Union[int, float, str]] = None,
10381
+ namespace: Optional[str] = None,
10382
+ token: Union[bool, str, None] = None,
10383
+ ) -> ScheduledJobInfo:
10384
+ """
10385
+ Create scheduled compute Jobs on Hugging Face infrastructure.
10386
+
10387
+ Args:
10388
+ image (`str`):
10389
+ The Docker image to use.
10390
+ Examples: `"ubuntu"`, `"python:3.12"`, `"pytorch/pytorch:2.6.0-cuda12.4-cudnn9-devel"`.
10391
+ Example with an image from a Space: `"hf.co/spaces/lhoestq/duckdb"`.
10392
+
10393
+ command (`List[str]`):
10394
+ The command to run. Example: `["echo", "hello"]`.
10395
+
10396
+ schedule (`str`):
10397
+ One of "@annually", "@yearly", "@monthly", "@weekly", "@daily", "@hourly", or a
10398
+ CRON schedule expression (e.g., '0 9 * * 1' for 9 AM every Monday).
10399
+
10400
+ suspend (`bool`, *optional*):
10401
+ If True, the scheduled Job is suspended (paused). Defaults to False.
10402
+
10403
+ concurrency (`bool`, *optional*):
10404
+ If True, multiple instances of this Job can run concurrently. Defaults to False.
10405
+
10406
+ env (`Dict[str, Any]`, *optional*):
10407
+ Defines the environment variables for the Job.
10408
+
10409
+ secrets (`Dict[str, Any]`, *optional*):
10410
+ Defines the secret environment variables for the Job.
10411
+
10412
+ flavor (`str`, *optional*):
10413
+ Flavor for the hardware, as in Hugging Face Spaces. See [`SpaceHardware`] for possible values.
10414
+ Defaults to `"cpu-basic"`.
10415
+
10416
+ timeout (`Union[int, float, str]`, *optional*):
10417
+ Max duration for the Job: int/float with s (seconds, default), m (minutes), h (hours) or d (days).
10418
+ Example: `300` or `"5m"` for 5 minutes.
10419
+
10420
+ namespace (`str`, *optional*):
10421
+ The namespace where the Job will be created. Defaults to the current user's namespace.
10422
+
10423
+ token `(Union[bool, str, None]`, *optional*):
10424
+ A valid user access token. If not provided, the locally saved token will be used, which is the
10425
+ recommended authentication method. Set to `False` to disable authentication.
10426
+ Refer to: https://huggingface.co/docs/huggingface_hub/quick-start#authentication.
10427
+
10428
+ Example:
10429
+ Create your first scheduled Job:
10430
+
10431
+ ```python
10432
+ >>> from huggingface_hub import create_scheduled_job
10433
+ >>> create_scheduled_job(image="python:3.12", command=["python", "-c" ,"print('Hello from HF compute!')"], schedule="@hourly")
10434
+ ```
10435
+
10436
+ Use a CRON schedule expression:
10437
+
10438
+ ```python
10439
+ >>> from huggingface_hub import create_scheduled_job
10440
+ >>> create_scheduled_job(image="python:3.12", command=["python", "-c" ,"print('this runs every 5min')"], schedule="*/5 * * * *")
10441
+ ```
10442
+
10443
+ Create a scheduled GPU Job:
10444
+
10445
+ ```python
10446
+ >>> from huggingface_hub import create_scheduled_job
10447
+ >>> image = "pytorch/pytorch:2.6.0-cuda12.4-cudnn9-devel"
10448
+ >>> command = ["python", "-c", "import torch; print(f"This code ran with the following GPU: {torch.cuda.get_device_name()}")"]
10449
+ >>> create_scheduled_job(image, command, flavor="a10g-small", schedule="@hourly")
10450
+ ```
10451
+
10452
+ """
10453
+ if namespace is None:
10454
+ namespace = self.whoami(token=token)["name"]
10455
+
10456
+ # prepare payload to send to HF Jobs API
10457
+ job_spec = _create_job_spec(
10458
+ image=image,
10459
+ command=command,
10460
+ env=env,
10461
+ secrets=secrets,
10462
+ flavor=flavor,
10463
+ timeout=timeout,
10464
+ )
10465
+ input_json: Dict[str, Any] = {
10466
+ "jobSpec": job_spec,
10467
+ "schedule": schedule,
10468
+ }
10469
+ if concurrency is not None:
10470
+ input_json["concurrency"] = concurrency
10471
+ if suspend is not None:
10472
+ input_json["suspend"] = suspend
10473
+ response = get_session().post(
10474
+ f"https://huggingface.co/api/scheduled-jobs/{namespace}",
10475
+ json=input_json,
10476
+ headers=self._build_hf_headers(token=token),
10477
+ )
10478
+ hf_raise_for_status(response)
10479
+ scheduled_job_info = response.json()
10480
+ return ScheduledJobInfo(**scheduled_job_info)
10481
+
10482
+ def list_scheduled_jobs(
10483
+ self,
10484
+ *,
10485
+ timeout: Optional[int] = None,
10486
+ namespace: Optional[str] = None,
10487
+ token: Union[bool, str, None] = None,
10488
+ ) -> List[ScheduledJobInfo]:
10489
+ """
10490
+ List scheduled compute Jobs on Hugging Face infrastructure.
10491
+
10492
+ Args:
10493
+ timeout (`float`, *optional*):
10494
+ Whether to set a timeout for the request to the Hub.
10495
+
10496
+ namespace (`str`, *optional*):
10497
+ The namespace from where it lists the jobs. Defaults to the current user's namespace.
10498
+
10499
+ token `(Union[bool, str, None]`, *optional*):
10500
+ A valid user access token. If not provided, the locally saved token will be used, which is the
10501
+ recommended authentication method. Set to `False` to disable authentication.
10502
+ Refer to: https://huggingface.co/docs/huggingface_hub/quick-start#authentication.
10503
+ """
10504
+ if namespace is None:
10505
+ namespace = self.whoami(token=token)["name"]
10506
+ response = get_session().get(
10507
+ f"{self.endpoint}/api/scheduled-jobs/{namespace}",
10508
+ headers=self._build_hf_headers(token=token),
10509
+ timeout=timeout,
10510
+ )
10511
+ hf_raise_for_status(response)
10512
+ return [ScheduledJobInfo(**scheduled_job_info) for scheduled_job_info in response.json()]
10513
+
10514
+ def inspect_scheduled_job(
10515
+ self,
10516
+ *,
10517
+ scheduled_job_id: str,
10518
+ namespace: Optional[str] = None,
10519
+ token: Union[bool, str, None] = None,
10520
+ ) -> ScheduledJobInfo:
10521
+ """
10522
+ Inspect a scheduled compute Job on Hugging Face infrastructure.
10523
+
10524
+ Args:
10525
+ scheduled_job_id (`str`):
10526
+ ID of the scheduled Job.
10527
+
10528
+ namespace (`str`, *optional*):
10529
+ The namespace where the scheduled Job is. Defaults to the current user's namespace.
10530
+
10531
+ token `(Union[bool, str, None]`, *optional*):
10532
+ A valid user access token. If not provided, the locally saved token will be used, which is the
10533
+ recommended authentication method. Set to `False` to disable authentication.
10534
+ Refer to: https://huggingface.co/docs/huggingface_hub/quick-start#authentication.
10535
+
10536
+ Example:
10537
+
10538
+ ```python
10539
+ >>> from huggingface_hub import inspect_job, create_scheduled_job
10540
+ >>> scheduled_job = create_scheduled_job(image="python:3.12", command=["python", "-c" ,"print('Hello from HF compute!')"], schedule="@hourly")
10541
+ >>> inspect_scheduled_job(scheduled_job.id)
10542
+ ```
10543
+ """
10544
+ if namespace is None:
10545
+ namespace = self.whoami(token=token)["name"]
10546
+ response = get_session().get(
10547
+ f"{self.endpoint}/api/scheduled-jobs/{namespace}/{scheduled_job_id}",
10548
+ headers=self._build_hf_headers(token=token),
10549
+ )
10550
+ hf_raise_for_status(response)
10551
+ return ScheduledJobInfo(**response.json())
10552
+
10553
+ def delete_scheduled_job(
10554
+ self,
10555
+ *,
10556
+ scheduled_job_id: str,
10557
+ namespace: Optional[str] = None,
10558
+ token: Union[bool, str, None] = None,
10559
+ ) -> None:
10560
+ """
10561
+ Delete a scheduled compute Job on Hugging Face infrastructure.
10562
+
10563
+ Args:
10564
+ scheduled_job_id (`str`):
10565
+ ID of the scheduled Job.
10566
+
10567
+ namespace (`str`, *optional*):
10568
+ The namespace where the scheduled Job is. Defaults to the current user's namespace.
10569
+
10570
+ token `(Union[bool, str, None]`, *optional*):
10571
+ A valid user access token. If not provided, the locally saved token will be used, which is the
10572
+ recommended authentication method. Set to `False` to disable authentication.
10573
+ Refer to: https://huggingface.co/docs/huggingface_hub/quick-start#authentication.
10574
+ """
10575
+ if namespace is None:
10576
+ namespace = self.whoami(token=token)["name"]
10577
+ response = get_session().delete(
10578
+ f"{self.endpoint}/api/scheduled-jobs/{namespace}/{scheduled_job_id}",
10579
+ headers=self._build_hf_headers(token=token),
10580
+ )
10581
+ hf_raise_for_status(response)
10582
+
10583
+ def suspend_scheduled_job(
10584
+ self,
10585
+ *,
10586
+ scheduled_job_id: str,
10587
+ namespace: Optional[str] = None,
10588
+ token: Union[bool, str, None] = None,
10589
+ ) -> None:
10590
+ """
10591
+ Suspend (pause) a scheduled compute Job on Hugging Face infrastructure.
10592
+
10593
+ Args:
10594
+ scheduled_job_id (`str`):
10595
+ ID of the scheduled Job.
10596
+
10597
+ namespace (`str`, *optional*):
10598
+ The namespace where the scheduled Job is. Defaults to the current user's namespace.
10599
+
10600
+ token `(Union[bool, str, None]`, *optional*):
10601
+ A valid user access token. If not provided, the locally saved token will be used, which is the
10602
+ recommended authentication method. Set to `False` to disable authentication.
10603
+ Refer to: https://huggingface.co/docs/huggingface_hub/quick-start#authentication.
10604
+ """
10605
+ if namespace is None:
10606
+ namespace = self.whoami(token=token)["name"]
10607
+ get_session().post(
10608
+ f"{self.endpoint}/api/scheduled-jobs/{namespace}/{scheduled_job_id}/suspend",
10609
+ headers=self._build_hf_headers(token=token),
10610
+ ).raise_for_status()
10611
+
10612
+ def resume_scheduled_job(
10613
+ self,
10614
+ *,
10615
+ scheduled_job_id: str,
10616
+ namespace: Optional[str] = None,
10617
+ token: Union[bool, str, None] = None,
10618
+ ) -> None:
10619
+ """
10620
+ Resume (unpause) a scheduled compute Job on Hugging Face infrastructure.
10621
+
10622
+ Args:
10623
+ scheduled_job_id (`str`):
10624
+ ID of the scheduled Job.
10625
+
10626
+ namespace (`str`, *optional*):
10627
+ The namespace where the scheduled Job is. Defaults to the current user's namespace.
10628
+
10629
+ token `(Union[bool, str, None]`, *optional*):
10630
+ A valid user access token. If not provided, the locally saved token will be used, which is the
10631
+ recommended authentication method. Set to `False` to disable authentication.
10632
+ Refer to: https://huggingface.co/docs/huggingface_hub/quick-start#authentication.
10633
+ """
10634
+ if namespace is None:
10635
+ namespace = self.whoami(token=token)["name"]
10636
+ get_session().post(
10637
+ f"{self.endpoint}/api/scheduled-jobs/{namespace}/{scheduled_job_id}/resume",
10638
+ headers=self._build_hf_headers(token=token),
10639
+ ).raise_for_status()
10640
+
10641
+ @experimental
10642
+ def create_scheduled_uv_job(
10643
+ self,
10644
+ script: str,
10645
+ *,
10646
+ script_args: Optional[List[str]] = None,
10647
+ schedule: str,
10648
+ suspend: Optional[bool] = None,
10649
+ concurrency: Optional[bool] = None,
10650
+ dependencies: Optional[List[str]] = None,
10651
+ python: Optional[str] = None,
10652
+ image: Optional[str] = None,
10653
+ env: Optional[Dict[str, Any]] = None,
10654
+ secrets: Optional[Dict[str, Any]] = None,
10655
+ flavor: Optional[SpaceHardware] = None,
10656
+ timeout: Optional[Union[int, float, str]] = None,
10657
+ namespace: Optional[str] = None,
10658
+ token: Union[bool, str, None] = None,
10659
+ _repo: Optional[str] = None,
10660
+ ) -> ScheduledJobInfo:
10661
+ """
10662
+ Run a UV script Job on Hugging Face infrastructure.
10663
+
10664
+ Args:
10665
+ script (`str`):
10666
+ Path or URL of the UV script, or a command.
10667
+
10668
+ script_args (`List[str]`, *optional*)
10669
+ Arguments to pass to the script, or a command.
10670
+
10671
+ schedule (`str`):
10672
+ One of "@annually", "@yearly", "@monthly", "@weekly", "@daily", "@hourly", or a
10673
+ CRON schedule expression (e.g., '0 9 * * 1' for 9 AM every Monday).
10674
+
10675
+ suspend (`bool`, *optional*):
10676
+ If True, the scheduled Job is suspended (paused). Defaults to False.
10677
+
10678
+ concurrency (`bool`, *optional*):
10679
+ If True, multiple instances of this Job can run concurrently. Defaults to False.
10680
+
10681
+ dependencies (`List[str]`, *optional*)
10682
+ Dependencies to use to run the UV script.
10683
+
10684
+ python (`str`, *optional*)
10685
+ Use a specific Python version. Default is 3.12.
10686
+
10687
+ image (`str`, *optional*, defaults to "ghcr.io/astral-sh/uv:python3.12-bookworm"):
10688
+ Use a custom Docker image with `uv` installed.
10689
+
10690
+ env (`Dict[str, Any]`, *optional*):
10691
+ Defines the environment variables for the Job.
10692
+
10693
+ secrets (`Dict[str, Any]`, *optional*):
10694
+ Defines the secret environment variables for the Job.
10695
+
10696
+ flavor (`str`, *optional*):
10697
+ Flavor for the hardware, as in Hugging Face Spaces. See [`SpaceHardware`] for possible values.
10698
+ Defaults to `"cpu-basic"`.
10699
+
10700
+ timeout (`Union[int, float, str]`, *optional*):
10701
+ Max duration for the Job: int/float with s (seconds, default), m (minutes), h (hours) or d (days).
10702
+ Example: `300` or `"5m"` for 5 minutes.
10703
+
10704
+ namespace (`str`, *optional*):
10705
+ The namespace where the Job will be created. Defaults to the current user's namespace.
10706
+
10707
+ token `(Union[bool, str, None]`, *optional*):
10708
+ A valid user access token. If not provided, the locally saved token will be used, which is the
10709
+ recommended authentication method. Set to `False` to disable authentication.
10710
+ Refer to: https://huggingface.co/docs/huggingface_hub/quick-start#authentication.
10711
+
10712
+ Example:
10713
+
10714
+ Schedule a script from a URL:
10715
+
10716
+ ```python
10717
+ >>> from huggingface_hub import create_scheduled_uv_job
10329
10718
  >>> script = "https://raw.githubusercontent.com/huggingface/trl/refs/heads/main/trl/scripts/sft.py"
10330
- >>> run_uv_job(script, dependencies=["trl"], flavor="a10g-small")
10719
+ >>> script_args = ["--model_name_or_path", "Qwen/Qwen2-0.5B", "--dataset_name", "trl-lib/Capybara", "--push_to_hub"]
10720
+ >>> create_scheduled_uv_job(script, script_args=script_args, dependencies=["trl"], flavor="a10g-small", schedule="@weekly")
10721
+ ```
10722
+
10723
+ Schedule a local script:
10724
+
10725
+ ```python
10726
+ >>> from huggingface_hub import create_scheduled_uv_job
10727
+ >>> script = "my_sft.py"
10728
+ >>> script_args = ["--model_name_or_path", "Qwen/Qwen2-0.5B", "--dataset_name", "trl-lib/Capybara", "--push_to_hub"]
10729
+ >>> create_scheduled_uv_job(script, script_args=script_args, dependencies=["trl"], flavor="a10g-small", schedule="@weekly")
10730
+ ```
10731
+
10732
+ Schedule a command:
10733
+
10734
+ ```python
10735
+ >>> from huggingface_hub import create_scheduled_uv_job
10736
+ >>> script = "lighteval"
10737
+ >>> script_args= ["endpoint", "inference-providers", "model_name=openai/gpt-oss-20b,provider=auto", "lighteval|gsm8k|0|0"]
10738
+ >>> create_scheduled_uv_job(script, script_args=script_args, dependencies=["lighteval"], flavor="a10g-small", schedule="@weekly")
10331
10739
  ```
10332
10740
  """
10333
10741
  image = image or "ghcr.io/astral-sh/uv:python3.12-bookworm"
10742
+ # Build command
10743
+ command, env, secrets = self._create_uv_command_env_and_secrets(
10744
+ script=script,
10745
+ script_args=script_args,
10746
+ dependencies=dependencies,
10747
+ python=python,
10748
+ env=env,
10749
+ secrets=secrets,
10750
+ namespace=namespace,
10751
+ token=token,
10752
+ _repo=_repo,
10753
+ )
10754
+ # Create RunCommand args
10755
+ return self.create_scheduled_job(
10756
+ image=image,
10757
+ command=command,
10758
+ schedule=schedule,
10759
+ suspend=suspend,
10760
+ concurrency=concurrency,
10761
+ env=env,
10762
+ secrets=secrets,
10763
+ flavor=flavor,
10764
+ timeout=timeout,
10765
+ namespace=namespace,
10766
+ token=token,
10767
+ )
10768
+
10769
+ def _create_uv_command_env_and_secrets(
10770
+ self,
10771
+ *,
10772
+ script: str,
10773
+ script_args: Optional[List[str]],
10774
+ dependencies: Optional[List[str]],
10775
+ python: Optional[str],
10776
+ env: Optional[Dict[str, Any]],
10777
+ secrets: Optional[Dict[str, Any]],
10778
+ namespace: Optional[str],
10779
+ token: Union[bool, str, None],
10780
+ _repo: Optional[str],
10781
+ ) -> Tuple[List[str], Dict[str, Any], Dict[str, Any]]:
10334
10782
  env = env or {}
10335
10783
  secrets = secrets or {}
10336
10784
 
@@ -10346,8 +10794,9 @@ class HfApi:
10346
10794
  if namespace is None:
10347
10795
  namespace = self.whoami(token=token)["name"]
10348
10796
 
10349
- if script.startswith("http://") or script.startswith("https://"):
10350
- # Direct URL execution - no upload needed
10797
+ is_url = script.startswith("http://") or script.startswith("https://")
10798
+ if is_url or not Path(script).is_file():
10799
+ # Direct URL execution or command - no upload needed
10351
10800
  command = ["uv", "run"] + uv_args + [script] + script_args
10352
10801
  else:
10353
10802
  # Local file - upload to HF
@@ -10358,7 +10807,6 @@ class HfApi:
10358
10807
  repo_id = _repo
10359
10808
  if "/" not in repo_id:
10360
10809
  repo_id = f"{namespace}/{repo_id}"
10361
- repo_id = _repo
10362
10810
  else:
10363
10811
  repo_id = f"{namespace}/hf-cli-jobs-uv-run-scripts"
10364
10812
 
@@ -10375,15 +10823,15 @@ class HfApi:
10375
10823
  with open(script_path, "r") as f:
10376
10824
  script_content = f.read()
10377
10825
 
10378
- self.upload_file(
10826
+ commit_hash = self.upload_file(
10379
10827
  path_or_fileobj=script_content.encode(),
10380
10828
  path_in_repo=filename,
10381
10829
  repo_id=repo_id,
10382
10830
  repo_type="dataset",
10383
- )
10831
+ ).oid
10384
10832
 
10385
- script_url = f"https://huggingface.co/datasets/{repo_id}/resolve/main/{filename}"
10386
- repo_url = f"https://huggingface.co/datasets/{repo_id}"
10833
+ script_url = f"{self.endpoint}/datasets/{repo_id}/resolve/{commit_hash}/{filename}"
10834
+ repo_url = f"{self.endpoint}/datasets/{repo_id}"
10387
10835
 
10388
10836
  logger.debug(f"✓ Script uploaded to: {repo_url}/blob/main/{filename}")
10389
10837
 
@@ -10440,18 +10888,7 @@ class HfApi:
10440
10888
  pre_command = ["python", "-c", '"' + "; ".join(pre_command) + '"']
10441
10889
  command = ["uv", "run"] + uv_args + ["/tmp/script.py"] + script_args
10442
10890
  command = ["bash", "-c", " ".join(pre_command) + " && " + " ".join(command)]
10443
-
10444
- # Create RunCommand args
10445
- return self.run_job(
10446
- image=image,
10447
- command=command,
10448
- env=env,
10449
- secrets=secrets,
10450
- flavor=flavor,
10451
- timeout=timeout,
10452
- namespace=namespace,
10453
- token=token,
10454
- )
10891
+ return command, env, secrets
10455
10892
 
10456
10893
 
10457
10894
  def _parse_revision_from_pr_url(pr_url: str) -> str:
@@ -10617,3 +11054,10 @@ list_jobs = api.list_jobs
10617
11054
  inspect_job = api.inspect_job
10618
11055
  cancel_job = api.cancel_job
10619
11056
  run_uv_job = api.run_uv_job
11057
+ create_scheduled_job = api.create_scheduled_job
11058
+ list_scheduled_jobs = api.list_scheduled_jobs
11059
+ inspect_scheduled_job = api.inspect_scheduled_job
11060
+ delete_scheduled_job = api.delete_scheduled_job
11061
+ suspend_scheduled_job = api.suspend_scheduled_job
11062
+ resume_scheduled_job = api.resume_scheduled_job
11063
+ create_scheduled_uv_job = api.create_scheduled_uv_job