Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 37 additions & 1 deletion docs/source/en/guides/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -862,7 +862,7 @@ Use `hf spaces` to list Spaces on the Hub and get detailed information about a s

## hf papers

Use `hf papers` to list daily papers on the Hub.
Use `hf papers` to list, search, get structured info, and read the markdown content of papers on the Hub.

### List papers

Expand All @@ -879,10 +879,46 @@ Use `hf papers` to list daily papers on the Hub.
# List today's papers
>>> hf papers ls --date=today

# List papers from a specific week
>>> hf papers ls --week=2025-W09

# List papers from a specific month
>>> hf papers ls --month=2025-02

# List papers submitted by a specific user
>>> hf papers ls --submitter=akhaliq

# Limit results
>>> hf papers ls --sort=trending --limit=5
```

### Search papers

```bash
# Search papers by keyword
>>> hf papers search "vision language"

# Limit search results
>>> hf papers search "diffusion models" --limit=10

# Output as JSON
>>> hf papers search "attention" --format=json
```

### Get paper info

```bash
# Get structured metadata for a paper (returns JSON)
>>> hf papers info 2601.15621
```

### Read paper as markdown

```bash
# Read the full paper content as markdown
>>> hf papers read 2601.15621
```

## hf discussions

Use `hf discussions` to manage discussions and pull requests on Hub repositories directly from your terminal. You can list, view, create, comment on, close, reopen, and merge both discussions and PRs. For a full guide on how the Hub's community features work, see the [Discussions and Pull Requests guide](./community).
Expand Down
94 changes: 94 additions & 0 deletions docs/source/en/package_reference/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -2665,7 +2665,37 @@ $ hf papers [OPTIONS] COMMAND [ARGS]...

**Commands**:

* `info`: Get info about a paper on the Hub.
* `list`: List daily papers on the Hub. [alias: ls]
* `read`: Read a paper as markdown.
* `search`: Search papers on the Hub.

### `hf papers info`

Get info about a paper on the Hub. Output is in JSON format.

**Usage**:

```console
$ hf papers info [OPTIONS] PAPER_ID
```

**Arguments**:

* `PAPER_ID`: The arXiv paper ID (e.g. '2502.08025'). [required]

**Options**:

* `--token TEXT`: A User Access Token generated from https://huggingface.co/settings/tokens.
* `--help`: Show this message and exit.

Examples
$ hf papers info 2601.15621

Learn more
Use `hf <command> --help` for more information about a command.
Read the documentation at https://huggingface.co/docs/huggingface_hub/en/guides/cli


### `hf papers list`

Expand All @@ -2680,6 +2710,9 @@ $ hf papers list [OPTIONS]
**Options**:

* `--date TEXT`: Date in ISO format (YYYY-MM-DD) or 'today'.
* `--week TEXT`: ISO week to filter by, e.g. '2025-W09'.
* `--month TEXT`: Month to filter by in ISO format (YYYY-MM), e.g. '2025-02'.
* `--submitter TEXT`: Filter by username of the submitter.
* `--sort [publishedAt|trending]`: Sort results.
* `--limit INTEGER`: Limit the number of results. [default: 50]
* `--format [table|json]`: Output format (table or json). [default: table]
Expand All @@ -2691,13 +2724,74 @@ Examples
$ hf papers ls
$ hf papers ls --sort trending
$ hf papers ls --date 2025-01-23
$ hf papers ls --week 2025-W09
$ hf papers ls --submitter akhaliq
$ hf papers ls --format json

Learn more
Use `hf <command> --help` for more information about a command.
Read the documentation at https://huggingface.co/docs/huggingface_hub/en/guides/cli


### `hf papers read`

Read a paper as markdown.

**Usage**:

```console
$ hf papers read [OPTIONS] PAPER_ID
```

**Arguments**:

* `PAPER_ID`: The arXiv paper ID (e.g. '2502.08025'). [required]

**Options**:

* `--token TEXT`: A User Access Token generated from https://huggingface.co/settings/tokens.
* `--help`: Show this message and exit.

Examples
$ hf papers read 2601.15621

Learn more
Use `hf <command> --help` for more information about a command.
Read the documentation at https://huggingface.co/docs/huggingface_hub/en/guides/cli


### `hf papers search`

Search papers on the Hub.

**Usage**:

```console
$ hf papers search [OPTIONS] QUERY
```

**Arguments**:

* `QUERY`: Search query string. [required]

**Options**:

* `--limit INTEGER`: Limit the number of results. [default: 20]
* `--format [table|json]`: Output format (table or json). [default: table]
* `-q, --quiet`: Print only IDs (one per line).
* `--token TEXT`: A User Access Token generated from https://huggingface.co/settings/tokens.
* `--help`: Show this message and exit.

Examples
$ hf papers search "vision language"
$ hf papers search "attention mechanism" --limit 10
$ hf papers search "diffusion" --format json

Learn more
Use `hf <command> --help` for more information about a command.
Read the documentation at https://huggingface.co/docs/huggingface_hub/en/guides/cli


## `hf repos`

Manage repos on the Hub. [alias: repo]
Expand Down
3 changes: 3 additions & 0 deletions src/huggingface_hub/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,7 @@
"pause_space",
"permanently_delete_lfs_files",
"preupload_lfs_files",
"read_paper",
"reject_access_request",
"rename_discussion",
"repo_exists",
Expand Down Expand Up @@ -1024,6 +1025,7 @@
"preupload_lfs_files",
"push_to_hub_fastai",
"read_dduf_file",
"read_paper",
"reject_access_request",
"rename_discussion",
"repo_exists",
Expand Down Expand Up @@ -1411,6 +1413,7 @@ def __dir__():
pause_space, # noqa: F401
permanently_delete_lfs_files, # noqa: F401
preupload_lfs_files, # noqa: F401
read_paper, # noqa: F401
reject_access_request, # noqa: F401
rename_discussion, # noqa: F401
repo_exists, # noqa: F401
Expand Down
119 changes: 117 additions & 2 deletions src/huggingface_hub/cli/papers.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,31 @@

# list today's papers, ordered by upvotes
hf papers ls --date=today

# list papers from a specific week
hf papers ls --week=2025-W09

# list papers by a specific submitter
hf papers ls --submitter=someuser

# search papers
hf papers search "vision language"

# get info about a paper
hf papers info 2502.08025

# read a paper as markdown
hf papers read 2502.08025
"""

import datetime
import enum
import json
from typing import Annotated, Optional, get_args

import typer

from huggingface_hub.errors import CLIError, HfHubHTTPError
from huggingface_hub.hf_api import DailyPapersSort_T

from ._cli_utils import (
Expand Down Expand Up @@ -71,6 +88,8 @@ def _parse_date(value: Optional[str]) -> Optional[str]:
"hf papers ls",
"hf papers ls --sort trending",
"hf papers ls --date 2025-01-23",
"hf papers ls --week 2025-W09",
"hf papers ls --submitter akhaliq",
"hf papers ls --format json",
],
)
Expand All @@ -82,6 +101,18 @@ def papers_ls(
callback=_parse_date,
),
] = None,
week: Annotated[
Optional[str],
typer.Option(help="ISO week to filter by, e.g. '2025-W09'."),
] = None,
month: Annotated[
Optional[str],
typer.Option(help="Month to filter by in ISO format (YYYY-MM), e.g. '2025-02'."),
] = None,
submitter: Annotated[
Optional[str],
typer.Option(help="Filter by username of the submitter."),
] = None,
sort: Annotated[
Optional[PaperSortEnum],
typer.Option(help="Sort results."),
Expand All @@ -98,6 +129,9 @@ def papers_ls(
api_object_to_dict(paper_info)
for paper_info in api.list_daily_papers(
date=date,
week=week,
month=month,
submitter=submitter,
sort=sort_key,
limit=limit,
)
Expand All @@ -106,14 +140,14 @@ def papers_ls(

def _paper_row(item: dict) -> list[str]:
submitted_by = item.get("submitted_by") or {}
submitter = submitted_by.get("fullname") or submitted_by.get("username") or ""
submitter_name = submitted_by.get("fullname") or submitted_by.get("username") or ""
return [
item.get("id", ""),
_format_cell(item.get("title", ""), max_len=60),
str(item.get("upvotes", "")),
str(item.get("comments", "")),
_format_cell(item.get("published_at", "")),
submitter,
submitter_name,
]

print_list_output(
Expand All @@ -125,3 +159,84 @@ def _paper_row(item: dict) -> list[str]:
row_fn=_paper_row,
alignments={"upvotes": "right", "comments": "right"},
)


@papers_cli.command(
"search",
examples=[
'hf papers search "vision language"',
'hf papers search "attention mechanism" --limit 10',
'hf papers search "diffusion" --format json',
],
)
def papers_search(
query: Annotated[str, typer.Argument(help="Search query string.")],
limit: LimitOpt = 20,
format: FormatOpt = OutputFormat.table,
quiet: QuietOpt = False,
token: TokenOpt = None,
) -> None:
"""Search papers on the Hub."""
api = get_hf_api(token=token)
results = [api_object_to_dict(paper_info) for paper_info in api.list_papers(query=query, limit=limit)]
_HEADERS = ["id", "title", "upvotes", "published_at"]

def _paper_row(item: dict) -> list[str]:
return [
item.get("id", ""),
_format_cell(item.get("title", ""), max_len=70),
str(item.get("upvotes", "")),
_format_cell(item.get("published_at", "")),
]

print_list_output(
results,
format=format,
quiet=quiet,
id_key="id",
headers=_HEADERS,
row_fn=_paper_row,
alignments={"upvotes": "right"},
)


@papers_cli.command(
"info",
examples=[
"hf papers info 2601.15621",
],
)
def papers_info(
paper_id: Annotated[str, typer.Argument(help="The arXiv paper ID (e.g. '2502.08025').")],
token: TokenOpt = None,
) -> None:
"""Get info about a paper on the Hub. Output is in JSON format."""
api = get_hf_api(token=token)
try:
info = api.paper_info(id=paper_id)
except HfHubHTTPError as e:
if e.response.status_code == 404:
raise CLIError(f"Paper '{paper_id}' not found on the Hub.") from e
raise
print(json.dumps(api_object_to_dict(info), indent=2))


@papers_cli.command(
"read",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

personal preference for hf papers view here instead of read. view gives us room if we ever want to add the possibility to open the paper in a browser with something like hf papers view 2601.15621 --web. also view might be more discoverable than read?

any preference @julien-c @Wauplin @gary149 ?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i kinda like read better here, but no strong opinion at all!

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for me view would actually be more like info

examples=[
"hf papers read 2601.15621",
],
)
def papers_read(
paper_id: Annotated[str, typer.Argument(help="The arXiv paper ID (e.g. '2502.08025').")],
token: TokenOpt = None,
) -> None:
"""Read a paper as markdown."""
api = get_hf_api(token=token)
try:
content = api.read_paper(id=paper_id)
except HfHubHTTPError as e:
if e.response.status_code == 404:
raise CLIError(f"Paper '{paper_id}' not found on the Hub.") from e
raise
print(content)
Loading
Loading