indico-cli 0.2.2__tar.gz → 0.4.2__tar.gz
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.
- {indico_cli-0.2.2 → indico_cli-0.4.2}/PKG-INFO +29 -2
- {indico_cli-0.2.2 → indico_cli-0.4.2}/README.md +28 -1
- indico_cli-0.4.2/indico_cli/_version.py +24 -0
- {indico_cli-0.2.2 → indico_cli-0.4.2}/indico_cli/cli.py +18 -4
- {indico_cli-0.2.2 → indico_cli-0.4.2}/indico_cli/indico_api.py +46 -1
- {indico_cli-0.2.2 → indico_cli-0.4.2}/skills/indico-skill/SKILL.md +19 -3
- indico_cli-0.4.2/tests/test_get_files.py +61 -0
- {indico_cli-0.2.2 → indico_cli-0.4.2}/uv.lock +74 -0
- indico_cli-0.2.2/indico_cli/_version.py +0 -34
- {indico_cli-0.2.2 → indico_cli-0.4.2}/.gitignore +0 -0
- {indico_cli-0.2.2 → indico_cli-0.4.2}/.gitlab-ci.yml +0 -0
- {indico_cli-0.2.2 → indico_cli-0.4.2}/CLAUDE.md +0 -0
- {indico_cli-0.2.2 → indico_cli-0.4.2}/LICENSE +0 -0
- {indico_cli-0.2.2 → indico_cli-0.4.2}/docs/superpowers/plans/2026-03-24-search-results-and-error-messages.md +0 -0
- {indico_cli-0.2.2 → indico_cli-0.4.2}/docs/superpowers/specs/2026-03-24-search-results-and-error-messages-design.md +0 -0
- {indico_cli-0.2.2 → indico_cli-0.4.2}/indico_cli/__init__.py +0 -0
- {indico_cli-0.2.2 → indico_cli-0.4.2}/indico_cli/utils.py +0 -0
- {indico_cli-0.2.2 → indico_cli-0.4.2}/pyproject.toml +0 -0
- {indico_cli-0.2.2 → indico_cli-0.4.2}/tests/__init__.py +0 -0
- {indico_cli-0.2.2 → indico_cli-0.4.2}/tests/test_error_messages.py +0 -0
- {indico_cli-0.2.2 → indico_cli-0.4.2}/tests/test_format_search_result.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: indico-cli
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.2
|
|
4
4
|
Summary: CLI tool for interacting with Indico event management systems
|
|
5
5
|
Project-URL: Repository, https://gitlab.cern.ch/cern-agent-skills/indico-cli
|
|
6
6
|
License: MIT
|
|
@@ -60,6 +60,9 @@ API tokens can be generated at `<your-indico-url>/user/preferences/api`. Require
|
|
|
60
60
|
# Full-text search across all content types
|
|
61
61
|
indico-cli search-by-term --term "machine learning"
|
|
62
62
|
|
|
63
|
+
# Full-text search with date range
|
|
64
|
+
indico-cli search-by-term --term "Smith" --type contribution --from-date 2025-01-01 --to-date 2025-03-31
|
|
65
|
+
|
|
63
66
|
# Search events in a category
|
|
64
67
|
indico-cli search-events --category-id 4648 --from-date 2025-01-01
|
|
65
68
|
|
|
@@ -90,6 +93,12 @@ indico-cli files --event-id 137346 --no-download
|
|
|
90
93
|
indico-cli download --url "https://indico.cern.ch/event/.../file.pdf"
|
|
91
94
|
```
|
|
92
95
|
|
|
96
|
+
The `files` command covers every file source attached to an event:
|
|
97
|
+
|
|
98
|
+
- **Event materials** — legacy `event.material[]` entries.
|
|
99
|
+
- **Event folder attachments** — generic files uploaded directly to the event page (not under any contribution). Typical for short meetings like the LHC morning meeting, where a single slide deck is attached to the event itself.
|
|
100
|
+
- **Contribution attachments** — files attached to individual contributions/talks.
|
|
101
|
+
|
|
93
102
|
### Create Events
|
|
94
103
|
|
|
95
104
|
```bash
|
|
@@ -105,7 +114,25 @@ indico-cli create-event-with-agenda --title "Workshop" --category-id 4648 \
|
|
|
105
114
|
|
|
106
115
|
### All Commands
|
|
107
116
|
|
|
108
|
-
|
|
117
|
+
| Command | Description |
|
|
118
|
+
|---------|-------------|
|
|
119
|
+
| `configure` | Save Indico base URL and API token, and verify the connection. |
|
|
120
|
+
| `user-info` | Show the current user's name, email, and admin status. |
|
|
121
|
+
| `search-events` | List events in a category, with optional date range and public-only filter. |
|
|
122
|
+
| `search-by-term` | Full-text search across categories, events, contributions, attachments, and notes. |
|
|
123
|
+
| `search-categories` | Browse sub-categories of a given category. |
|
|
124
|
+
| `event-details` | Show event metadata, optionally with contributions and sessions. |
|
|
125
|
+
| `contributions` | List contributions (and optionally subcontributions) of an event. |
|
|
126
|
+
| `files` | List and download all files attached to an event — event-level materials, event-page folder attachments, and contribution attachments. |
|
|
127
|
+
| `download` | Download a single attachment by its URL. |
|
|
128
|
+
| `create-event` | Create a new event (lecture, meeting, or conference). |
|
|
129
|
+
| `create-session` | Create a session inside an event. |
|
|
130
|
+
| `create-contribution` | Create a contribution inside an event, optionally in a given session. |
|
|
131
|
+
| `add-timetable-entry` | Add a session block or contribution entry to the event timetable. |
|
|
132
|
+
| `delete-timetable-entry` | Remove an entry from the event timetable. |
|
|
133
|
+
| `create-event-with-agenda` | Create an event and populate its timetable from a JSON agenda file. |
|
|
134
|
+
|
|
135
|
+
Run `indico-cli --help` for the same list, or `indico-cli <command> --help` for command-specific options.
|
|
109
136
|
|
|
110
137
|
## Claude Code Skill
|
|
111
138
|
|
|
@@ -37,6 +37,9 @@ API tokens can be generated at `<your-indico-url>/user/preferences/api`. Require
|
|
|
37
37
|
# Full-text search across all content types
|
|
38
38
|
indico-cli search-by-term --term "machine learning"
|
|
39
39
|
|
|
40
|
+
# Full-text search with date range
|
|
41
|
+
indico-cli search-by-term --term "Smith" --type contribution --from-date 2025-01-01 --to-date 2025-03-31
|
|
42
|
+
|
|
40
43
|
# Search events in a category
|
|
41
44
|
indico-cli search-events --category-id 4648 --from-date 2025-01-01
|
|
42
45
|
|
|
@@ -67,6 +70,12 @@ indico-cli files --event-id 137346 --no-download
|
|
|
67
70
|
indico-cli download --url "https://indico.cern.ch/event/.../file.pdf"
|
|
68
71
|
```
|
|
69
72
|
|
|
73
|
+
The `files` command covers every file source attached to an event:
|
|
74
|
+
|
|
75
|
+
- **Event materials** — legacy `event.material[]` entries.
|
|
76
|
+
- **Event folder attachments** — generic files uploaded directly to the event page (not under any contribution). Typical for short meetings like the LHC morning meeting, where a single slide deck is attached to the event itself.
|
|
77
|
+
- **Contribution attachments** — files attached to individual contributions/talks.
|
|
78
|
+
|
|
70
79
|
### Create Events
|
|
71
80
|
|
|
72
81
|
```bash
|
|
@@ -82,7 +91,25 @@ indico-cli create-event-with-agenda --title "Workshop" --category-id 4648 \
|
|
|
82
91
|
|
|
83
92
|
### All Commands
|
|
84
93
|
|
|
85
|
-
|
|
94
|
+
| Command | Description |
|
|
95
|
+
|---------|-------------|
|
|
96
|
+
| `configure` | Save Indico base URL and API token, and verify the connection. |
|
|
97
|
+
| `user-info` | Show the current user's name, email, and admin status. |
|
|
98
|
+
| `search-events` | List events in a category, with optional date range and public-only filter. |
|
|
99
|
+
| `search-by-term` | Full-text search across categories, events, contributions, attachments, and notes. |
|
|
100
|
+
| `search-categories` | Browse sub-categories of a given category. |
|
|
101
|
+
| `event-details` | Show event metadata, optionally with contributions and sessions. |
|
|
102
|
+
| `contributions` | List contributions (and optionally subcontributions) of an event. |
|
|
103
|
+
| `files` | List and download all files attached to an event — event-level materials, event-page folder attachments, and contribution attachments. |
|
|
104
|
+
| `download` | Download a single attachment by its URL. |
|
|
105
|
+
| `create-event` | Create a new event (lecture, meeting, or conference). |
|
|
106
|
+
| `create-session` | Create a session inside an event. |
|
|
107
|
+
| `create-contribution` | Create a contribution inside an event, optionally in a given session. |
|
|
108
|
+
| `add-timetable-entry` | Add a session block or contribution entry to the event timetable. |
|
|
109
|
+
| `delete-timetable-entry` | Remove an entry from the event timetable. |
|
|
110
|
+
| `create-event-with-agenda` | Create an event and populate its timetable from a JSON agenda file. |
|
|
111
|
+
|
|
112
|
+
Run `indico-cli --help` for the same list, or `indico-cli <command> --help` for command-specific options.
|
|
86
113
|
|
|
87
114
|
## Claude Code Skill
|
|
88
115
|
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# file generated by vcs-versioning
|
|
2
|
+
# don't change, don't track in version control
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
__all__ = [
|
|
6
|
+
"__version__",
|
|
7
|
+
"__version_tuple__",
|
|
8
|
+
"version",
|
|
9
|
+
"version_tuple",
|
|
10
|
+
"__commit_id__",
|
|
11
|
+
"commit_id",
|
|
12
|
+
]
|
|
13
|
+
|
|
14
|
+
version: str
|
|
15
|
+
__version__: str
|
|
16
|
+
__version_tuple__: tuple[int | str, ...]
|
|
17
|
+
version_tuple: tuple[int | str, ...]
|
|
18
|
+
commit_id: str | None
|
|
19
|
+
__commit_id__: str | None
|
|
20
|
+
|
|
21
|
+
__version__ = version = '0.4.2'
|
|
22
|
+
__version_tuple__ = version_tuple = (0, 4, 2)
|
|
23
|
+
|
|
24
|
+
__commit_id__ = commit_id = None
|
|
@@ -71,10 +71,21 @@ def cli(ctx, base_url, token):
|
|
|
71
71
|
|
|
72
72
|
@cli.command()
|
|
73
73
|
@click.option("--base-url", required=True, help="Indico instance URL")
|
|
74
|
-
@click.option("--token", default="", help="API bearer token")
|
|
74
|
+
@click.option("--token", envvar="INDICO_API_TOKEN", default="", help="API bearer token (or set INDICO_API_TOKEN)")
|
|
75
75
|
def configure(base_url, token):
|
|
76
76
|
"""Configure connection to an Indico instance and test it."""
|
|
77
|
-
|
|
77
|
+
if not token:
|
|
78
|
+
try:
|
|
79
|
+
token = click.prompt("API token", hide_input=True)
|
|
80
|
+
except (EOFError, click.Abort):
|
|
81
|
+
pass
|
|
82
|
+
if not token:
|
|
83
|
+
click.echo("Error: no token provided.", err=True)
|
|
84
|
+
click.echo("Either:", err=True)
|
|
85
|
+
click.echo(" 1. Run in a real terminal: indico-cli configure --base-url URL", err=True)
|
|
86
|
+
click.echo(" 2. Set env var first: export INDICO_API_TOKEN=indp_... && indico-cli configure --base-url URL", err=True)
|
|
87
|
+
sys.exit(1)
|
|
88
|
+
api = IndicoAPI(base_url, bearer_token=token)
|
|
78
89
|
client = IndicoClient(api)
|
|
79
90
|
try:
|
|
80
91
|
result = run_async(client.get_user_info())
|
|
@@ -84,6 +95,7 @@ def configure(base_url, token):
|
|
|
84
95
|
click.echo(f"Configuration saved to {CONFIG_FILE}")
|
|
85
96
|
except Exception as error:
|
|
86
97
|
click.echo(f"Connection test failed: {error}", err=True)
|
|
98
|
+
click.echo("Check that your token starts with 'indp_' and has the correct scopes.", err=True)
|
|
87
99
|
sys.exit(1)
|
|
88
100
|
|
|
89
101
|
|
|
@@ -116,11 +128,13 @@ def search_events(ctx, category_id, from_date, to_date, limit, only_public):
|
|
|
116
128
|
@click.option("--type", "type_filter", default=None,
|
|
117
129
|
type=click.Choice(["category", "event", "contribution", "subcontribution", "attachment", "event_note"]),
|
|
118
130
|
help="Filter to a specific content type")
|
|
131
|
+
@click.option("--from-date", default=None, help="Start date filter (YYYY-MM-DD)")
|
|
132
|
+
@click.option("--to-date", default=None, help="End date filter (YYYY-MM-DD)")
|
|
119
133
|
@click.pass_context
|
|
120
|
-
def search_by_term(ctx, term, limit, type_filter):
|
|
134
|
+
def search_by_term(ctx, term, limit, type_filter, from_date, to_date):
|
|
121
135
|
"""Search for events by keyword/term."""
|
|
122
136
|
client = get_client(ctx.obj["base_url"], ctx.obj["token"])
|
|
123
|
-
result = run_async(client.search_events_by_term(term, limit, type_filter))
|
|
137
|
+
result = run_async(client.search_events_by_term(term, limit, type_filter, from_date, to_date))
|
|
124
138
|
click.echo(result)
|
|
125
139
|
|
|
126
140
|
|
|
@@ -365,7 +365,8 @@ class IndicoClient:
|
|
|
365
365
|
return response
|
|
366
366
|
|
|
367
367
|
async def search_events_by_term(
|
|
368
|
-
self, search_term: str, limit: int = 50, type_filter: Optional[str] = None
|
|
368
|
+
self, search_term: str, limit: int = 50, type_filter: Optional[str] = None,
|
|
369
|
+
from_date: Optional[str] = None, to_date: Optional[str] = None
|
|
369
370
|
) -> str:
|
|
370
371
|
"""Search for content by keyword/term using comprehensive Indico search API"""
|
|
371
372
|
try:
|
|
@@ -387,6 +388,13 @@ class IndicoClient:
|
|
|
387
388
|
else:
|
|
388
389
|
search_types = all_search_types
|
|
389
390
|
|
|
391
|
+
# Build start_range filter if date params provided
|
|
392
|
+
start_range = None
|
|
393
|
+
if from_date or to_date:
|
|
394
|
+
range_start = from_date or "*"
|
|
395
|
+
range_end = to_date or "*"
|
|
396
|
+
start_range = f"[{range_start} TO {range_end}]"
|
|
397
|
+
|
|
390
398
|
all_results = {}
|
|
391
399
|
total_found = 0
|
|
392
400
|
|
|
@@ -396,6 +404,8 @@ class IndicoClient:
|
|
|
396
404
|
params = {"q": search_term, "type": search_type}
|
|
397
405
|
if limit:
|
|
398
406
|
params["limit"] = str(limit)
|
|
407
|
+
if start_range:
|
|
408
|
+
params["start_range"] = start_range
|
|
399
409
|
|
|
400
410
|
# Use the new search API endpoint
|
|
401
411
|
result = await self.api.get(f"/search/api/search", params)
|
|
@@ -991,6 +1001,41 @@ class IndicoClient:
|
|
|
991
1001
|
response += f" - {filename} ({file_size})\n"
|
|
992
1002
|
response += "\n"
|
|
993
1003
|
|
|
1004
|
+
# 1b. Check event-level folders/attachments (generic attachments uploaded to the event page)
|
|
1005
|
+
event_folders = event.get("folders", [])
|
|
1006
|
+
if event_folders:
|
|
1007
|
+
event_folder_files_count = 0
|
|
1008
|
+
for folder in event_folders:
|
|
1009
|
+
folder_title = folder.get("title", "Unknown Folder")
|
|
1010
|
+
folder_id = folder.get("id", "")
|
|
1011
|
+
attachments = folder.get("attachments", [])
|
|
1012
|
+
|
|
1013
|
+
for attachment in attachments:
|
|
1014
|
+
filename = attachment.get(
|
|
1015
|
+
"filename",
|
|
1016
|
+
attachment.get("title", "unknown_file"),
|
|
1017
|
+
)
|
|
1018
|
+
attachment_id = attachment.get("id", "")
|
|
1019
|
+
file_size = attachment.get("size", "unknown size")
|
|
1020
|
+
download_url = attachment.get("download_url") or attachment.get("url")
|
|
1021
|
+
|
|
1022
|
+
files_found.append(
|
|
1023
|
+
{
|
|
1024
|
+
"filename": filename,
|
|
1025
|
+
"attachment_id": attachment_id,
|
|
1026
|
+
"folder_id": folder_id,
|
|
1027
|
+
"size": file_size,
|
|
1028
|
+
"source": f"Event Folder: {folder_title}",
|
|
1029
|
+
"type": "event_attachment",
|
|
1030
|
+
"download_url": download_url,
|
|
1031
|
+
"api_path": f"/event/{event_id}/attachments/{attachment_id}/{filename}",
|
|
1032
|
+
}
|
|
1033
|
+
)
|
|
1034
|
+
event_folder_files_count += 1
|
|
1035
|
+
|
|
1036
|
+
if event_folder_files_count > 0:
|
|
1037
|
+
response += f"Event Attachments: {event_folder_files_count} files found\n\n"
|
|
1038
|
+
|
|
994
1039
|
# 2. Check contribution-level materials/attachments
|
|
995
1040
|
contributions = event.get("contributions", [])
|
|
996
1041
|
if contributions:
|
|
@@ -23,11 +23,13 @@ Set up or update Indico CLI credentials.
|
|
|
23
23
|
|
|
24
24
|
1. **Check if already configured**: run `uvx indico-cli user-info 2>&1`. If it returns user info, stop — already configured.
|
|
25
25
|
2. **Ask the user** which Indico instance to connect to (e.g., `https://indico.cern.ch`, `https://indico.fnal.gov`, or a custom URL).
|
|
26
|
-
3. **Guide token creation**: tell the user to open `<base_url>/user/
|
|
26
|
+
3. **Guide token creation**: tell the user to open `<base_url>/user/tokens/`, click "Create new token", name it (e.g., "indico-cli"), select all scopes (you can avoid write in case want to play on the safe side), click "Create", and copy the `indp_...` token immediately (shown only once).
|
|
27
27
|
4. **Save credentials**:
|
|
28
|
+
|
|
28
29
|
```bash
|
|
29
30
|
uvx indico-cli configure --base-url <BASE_URL> --token <TOKEN>
|
|
30
31
|
```
|
|
32
|
+
|
|
31
33
|
Saves to `~/.config/indico-cli/config.json` (never inside a repo).
|
|
32
34
|
5. **Verify**: the configure command tests the connection automatically. On failure: 403/401 = wrong scopes or expired token; connection error = wrong URL; SSL error = network issue.
|
|
33
35
|
|
|
@@ -44,6 +46,7 @@ If an event returns "not found" or "deleted", don't stop — use `search-by-term
|
|
|
44
46
|
### Chaining commands for deeper answers
|
|
45
47
|
|
|
46
48
|
Many tasks require chaining multiple commands. For example, to find out what someone concluded in a talk:
|
|
49
|
+
|
|
47
50
|
1. `search-by-term` or `contributions` to find the relevant contribution
|
|
48
51
|
2. `files` or `download` to get the slides/PDF
|
|
49
52
|
3. **Read the downloaded file** and extract the answer
|
|
@@ -53,6 +56,7 @@ The goal is to answer the user's question, not just list metadata. If slides wer
|
|
|
53
56
|
### Using event IDs from search results
|
|
54
57
|
|
|
55
58
|
`search-by-term` returns `Event ID` for every contribution, attachment, and note result. Use this ID to drill into the event:
|
|
59
|
+
|
|
56
60
|
1. `search-by-term --term "my topic"` — find the contribution and note its Event ID
|
|
57
61
|
2. `event-details --event-id <ID>` — get full event info
|
|
58
62
|
3. `contributions --event-id <ID>` — list all contributions
|
|
@@ -71,7 +75,7 @@ The goal is to answer the user's question, not just list metadata. If slides wer
|
|
|
71
75
|
### search-by-term — Full-text search across all Indico content
|
|
72
76
|
|
|
73
77
|
```bash
|
|
74
|
-
uvx indico-cli search-by-term --term "<query>" [--limit N] [--type TYPE]
|
|
78
|
+
uvx indico-cli search-by-term --term "<query>" [--limit N] [--type TYPE] [--from-date YYYY-MM-DD] [--to-date YYYY-MM-DD]
|
|
75
79
|
```
|
|
76
80
|
|
|
77
81
|
| Parameter | Required | Description |
|
|
@@ -79,8 +83,10 @@ uvx indico-cli search-by-term --term "<query>" [--limit N] [--type TYPE]
|
|
|
79
83
|
| `--term` | Yes | Search keyword or phrase |
|
|
80
84
|
| `--limit` | No | Max results per content type (default: 50) |
|
|
81
85
|
| `--type` | No | Filter to one content type: `event`, `contribution`, `subcontribution`, `attachment`, `event_note`, `category` |
|
|
86
|
+
| `--from-date` | No | Start date filter (YYYY-MM-DD) |
|
|
87
|
+
| `--to-date` | No | End date filter (YYYY-MM-DD) |
|
|
82
88
|
|
|
83
|
-
Searches categories, events, contributions, subcontributions, attachments, and notes.
|
|
89
|
+
Searches categories, events, contributions, subcontributions, attachments, and notes. Use `--from-date`/`--to-date` to narrow results to a specific time range.
|
|
84
90
|
|
|
85
91
|
### search-events — Search events in a category by date
|
|
86
92
|
|
|
@@ -155,7 +161,13 @@ uvx indico-cli files --event-id <ID> [--download | --no-download] [--download-di
|
|
|
155
161
|
| `--download/--no-download` | No | Download files (default: download) |
|
|
156
162
|
| `--download-dir` | No | Directory for downloads |
|
|
157
163
|
|
|
164
|
+
Covers three sources of files:
|
|
165
|
+
- Event-level legacy **materials** (`event.material[]`)
|
|
166
|
+
- Event-level **folder attachments** — generic files uploaded to the event page itself, not tied to any contribution (e.g. the single slide deck of an LHC morning meeting)
|
|
167
|
+
- **Contribution attachments** — files attached to individual talks/contributions
|
|
168
|
+
|
|
158
169
|
If the built-in download fails (403), list with `--no-download` to get URLs, then use curl:
|
|
170
|
+
|
|
159
171
|
```bash
|
|
160
172
|
curl -L -H "Authorization: Bearer $INDICO_API_TOKEN" -o filename.pdf "DOWNLOAD_URL"
|
|
161
173
|
```
|
|
@@ -310,11 +322,13 @@ Used by `create-event-with-agenda`. A JSON array where items with a `contributio
|
|
|
310
322
|
## Examples
|
|
311
323
|
|
|
312
324
|
Search for beam dynamics content:
|
|
325
|
+
|
|
313
326
|
```bash
|
|
314
327
|
uvx indico-cli search-by-term --term "beam dynamics" --limit 5
|
|
315
328
|
```
|
|
316
329
|
|
|
317
330
|
Create a meeting with agenda:
|
|
331
|
+
|
|
318
332
|
```bash
|
|
319
333
|
uvx indico-cli create-event-with-agenda \
|
|
320
334
|
--title "Workshop on ML" \
|
|
@@ -328,11 +342,13 @@ uvx indico-cli create-event-with-agenda \
|
|
|
328
342
|
```
|
|
329
343
|
|
|
330
344
|
Download all files from an event:
|
|
345
|
+
|
|
331
346
|
```bash
|
|
332
347
|
uvx indico-cli files --event-id 137346
|
|
333
348
|
```
|
|
334
349
|
|
|
335
350
|
Schedule a contribution:
|
|
351
|
+
|
|
336
352
|
```bash
|
|
337
353
|
uvx indico-cli add-timetable-entry --event-id 137346 --type contribution --object-id 12 --start 2025-06-15T14:00:00 --duration 30
|
|
338
354
|
```
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"""Tests for get_files discovery of the different Indico attachment sources."""
|
|
2
|
+
|
|
3
|
+
import pytest
|
|
4
|
+
from unittest.mock import AsyncMock
|
|
5
|
+
|
|
6
|
+
from indico_cli.indico_api import IndicoAPI, IndicoClient
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def make_client():
|
|
10
|
+
return IndicoClient(IndicoAPI("https://indico.cern.ch"))
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
EVENT_FOLDER_ATTACHMENT = {
|
|
14
|
+
"count": 1,
|
|
15
|
+
"results": [{
|
|
16
|
+
"title": "LHC morning meeting",
|
|
17
|
+
"folders": [{
|
|
18
|
+
"title": "Slides",
|
|
19
|
+
"id": 3254260,
|
|
20
|
+
"attachments": [{
|
|
21
|
+
"filename": "2026.04.13.morning-meeting.pdf",
|
|
22
|
+
"id": 5808485,
|
|
23
|
+
"size": 1073612,
|
|
24
|
+
"download_url": "https://indico.cern.ch/event/1649151/attachments/3254260/5808485/2026.04.13.morning-meeting.pdf",
|
|
25
|
+
}],
|
|
26
|
+
}],
|
|
27
|
+
"contributions": [],
|
|
28
|
+
}],
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class TestEventFolderAttachments:
|
|
33
|
+
@pytest.mark.asyncio
|
|
34
|
+
async def test_lists_event_level_folder_attachment(self):
|
|
35
|
+
"""Generic attachments uploaded to the event page (not a contribution) must be discovered."""
|
|
36
|
+
client = make_client()
|
|
37
|
+
client.api.get = AsyncMock(return_value=EVENT_FOLDER_ATTACHMENT)
|
|
38
|
+
result = await client.get_files("1649151", download_files=False, include_content=False)
|
|
39
|
+
assert "2026.04.13.morning-meeting.pdf" in result
|
|
40
|
+
assert "Event Attachments: 1 files found" in result
|
|
41
|
+
assert "Event Folder: Slides" in result
|
|
42
|
+
assert "Total files found: 1" in result
|
|
43
|
+
|
|
44
|
+
@pytest.mark.asyncio
|
|
45
|
+
async def test_event_folder_download_url_exposed(self):
|
|
46
|
+
"""The attachment's download_url must be surfaced so downloads hit the correct path."""
|
|
47
|
+
client = make_client()
|
|
48
|
+
client.api.get = AsyncMock(return_value=EVENT_FOLDER_ATTACHMENT)
|
|
49
|
+
result = await client.get_files("1649151", download_files=False, include_content=False)
|
|
50
|
+
assert "/event/1649151/attachments/3254260/5808485/" in result
|
|
51
|
+
|
|
52
|
+
@pytest.mark.asyncio
|
|
53
|
+
async def test_no_folders_no_false_positive(self):
|
|
54
|
+
"""Events without folder attachments must not report event attachments."""
|
|
55
|
+
client = make_client()
|
|
56
|
+
client.api.get = AsyncMock(return_value={
|
|
57
|
+
"count": 1,
|
|
58
|
+
"results": [{"title": "Empty", "folders": [], "contributions": []}],
|
|
59
|
+
})
|
|
60
|
+
result = await client.get_files("1", download_files=False, include_content=False)
|
|
61
|
+
assert "Event Attachments:" not in result
|
|
@@ -99,10 +99,84 @@ dependencies = [
|
|
|
99
99
|
{ name = "httpx" },
|
|
100
100
|
]
|
|
101
101
|
|
|
102
|
+
[package.optional-dependencies]
|
|
103
|
+
dev = [
|
|
104
|
+
{ name = "pytest" },
|
|
105
|
+
{ name = "pytest-asyncio" },
|
|
106
|
+
]
|
|
107
|
+
|
|
102
108
|
[package.metadata]
|
|
103
109
|
requires-dist = [
|
|
104
110
|
{ name = "click", specifier = ">=8.0" },
|
|
105
111
|
{ name = "httpx", specifier = ">=0.25" },
|
|
112
|
+
{ name = "pytest", marker = "extra == 'dev'", specifier = ">=7.0" },
|
|
113
|
+
{ name = "pytest-asyncio", marker = "extra == 'dev'", specifier = ">=0.21" },
|
|
114
|
+
]
|
|
115
|
+
provides-extras = ["dev"]
|
|
116
|
+
|
|
117
|
+
[[package]]
|
|
118
|
+
name = "iniconfig"
|
|
119
|
+
version = "2.3.0"
|
|
120
|
+
source = { registry = "https://acc-py-repo.cern.ch/repository/vr-py-releases/simple" }
|
|
121
|
+
sdist = { url = "https://acc-py-repo.cern.ch/repository/vr-py-releases/resources/iniconfig/iniconfig-2.3.0.tar.gz", hash = "sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730", size = 20503, upload-time = "2025-10-18T21:55:43Z" }
|
|
122
|
+
wheels = [
|
|
123
|
+
{ url = "https://acc-py-repo.cern.ch/repository/vr-py-releases/resources/iniconfig/iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12", size = 7484, upload-time = "2025-10-18T21:55:41Z" },
|
|
124
|
+
]
|
|
125
|
+
|
|
126
|
+
[[package]]
|
|
127
|
+
name = "packaging"
|
|
128
|
+
version = "26.0"
|
|
129
|
+
source = { registry = "https://acc-py-repo.cern.ch/repository/vr-py-releases/simple" }
|
|
130
|
+
sdist = { url = "https://acc-py-repo.cern.ch/repository/vr-py-releases/resources/packaging/packaging-26.0.tar.gz", hash = "sha256:00243ae351a257117b6a241061796684b084ed1c516a08c48a3f7e147a9d80b4", size = 143416, upload-time = "2026-01-21T20:50:39Z" }
|
|
131
|
+
wheels = [
|
|
132
|
+
{ url = "https://acc-py-repo.cern.ch/repository/vr-py-releases/resources/packaging/packaging-26.0-py3-none-any.whl", hash = "sha256:b36f1fef9334a5588b4166f8bcd26a14e521f2b55e6b9de3aaa80d3ff7a37529", size = 74366, upload-time = "2026-01-21T20:50:37Z" },
|
|
133
|
+
]
|
|
134
|
+
|
|
135
|
+
[[package]]
|
|
136
|
+
name = "pluggy"
|
|
137
|
+
version = "1.6.0"
|
|
138
|
+
source = { registry = "https://acc-py-repo.cern.ch/repository/vr-py-releases/simple" }
|
|
139
|
+
sdist = { url = "https://acc-py-repo.cern.ch/repository/vr-py-releases/resources/pluggy/pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3", size = 69412, upload-time = "2025-05-15T12:30:07Z" }
|
|
140
|
+
wheels = [
|
|
141
|
+
{ url = "https://acc-py-repo.cern.ch/repository/vr-py-releases/resources/pluggy/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538, upload-time = "2025-05-15T12:30:06Z" },
|
|
142
|
+
]
|
|
143
|
+
|
|
144
|
+
[[package]]
|
|
145
|
+
name = "pygments"
|
|
146
|
+
version = "2.20.0"
|
|
147
|
+
source = { registry = "https://acc-py-repo.cern.ch/repository/vr-py-releases/simple" }
|
|
148
|
+
sdist = { url = "https://acc-py-repo.cern.ch/repository/vr-py-releases/resources/pygments/pygments-2.20.0.tar.gz", hash = "sha256:6757cd03768053ff99f3039c1a36d6c0aa0b263438fcab17520b30a303a82b5f", size = 4955991, upload-time = "2026-03-29T13:29:33Z" }
|
|
149
|
+
wheels = [
|
|
150
|
+
{ url = "https://acc-py-repo.cern.ch/repository/vr-py-releases/resources/pygments/pygments-2.20.0-py3-none-any.whl", hash = "sha256:81a9e26dd42fd28a23a2d169d86d7ac03b46e2f8b59ed4698fb4785f946d0176", size = 1231151, upload-time = "2026-03-29T13:29:30Z" },
|
|
151
|
+
]
|
|
152
|
+
|
|
153
|
+
[[package]]
|
|
154
|
+
name = "pytest"
|
|
155
|
+
version = "9.0.3"
|
|
156
|
+
source = { registry = "https://acc-py-repo.cern.ch/repository/vr-py-releases/simple" }
|
|
157
|
+
dependencies = [
|
|
158
|
+
{ name = "colorama", marker = "sys_platform == 'win32'" },
|
|
159
|
+
{ name = "iniconfig" },
|
|
160
|
+
{ name = "packaging" },
|
|
161
|
+
{ name = "pluggy" },
|
|
162
|
+
{ name = "pygments" },
|
|
163
|
+
]
|
|
164
|
+
sdist = { url = "https://acc-py-repo.cern.ch/repository/vr-py-releases/resources/pytest/pytest-9.0.3.tar.gz", hash = "sha256:b86ada508af81d19edeb213c681b1d48246c1a91d304c6c81a427674c17eb91c", size = 1572165, upload-time = "2026-04-07T17:16:18Z" }
|
|
165
|
+
wheels = [
|
|
166
|
+
{ url = "https://acc-py-repo.cern.ch/repository/vr-py-releases/resources/pytest/pytest-9.0.3-py3-none-any.whl", hash = "sha256:2c5efc453d45394fdd706ade797c0a81091eccd1d6e4bccfcd476e2b8e0ab5d9", size = 375249, upload-time = "2026-04-07T17:16:16Z" },
|
|
167
|
+
]
|
|
168
|
+
|
|
169
|
+
[[package]]
|
|
170
|
+
name = "pytest-asyncio"
|
|
171
|
+
version = "1.3.0"
|
|
172
|
+
source = { registry = "https://acc-py-repo.cern.ch/repository/vr-py-releases/simple" }
|
|
173
|
+
dependencies = [
|
|
174
|
+
{ name = "pytest" },
|
|
175
|
+
{ name = "typing-extensions", marker = "python_full_version < '3.13'" },
|
|
176
|
+
]
|
|
177
|
+
sdist = { url = "https://acc-py-repo.cern.ch/repository/vr-py-releases/resources/pytest-asyncio/pytest_asyncio-1.3.0.tar.gz", hash = "sha256:d7f52f36d231b80ee124cd216ffb19369aa168fc10095013c6b014a34d3ee9e5", size = 50087, upload-time = "2025-11-10T16:07:47Z" }
|
|
178
|
+
wheels = [
|
|
179
|
+
{ url = "https://acc-py-repo.cern.ch/repository/vr-py-releases/resources/pytest-asyncio/pytest_asyncio-1.3.0-py3-none-any.whl", hash = "sha256:611e26147c7f77640e6d0a92a38ed17c3e9848063698d5c93d5aa7aa11cebff5", size = 15075, upload-time = "2025-11-10T16:07:45Z" },
|
|
106
180
|
]
|
|
107
181
|
|
|
108
182
|
[[package]]
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
# file generated by setuptools-scm
|
|
2
|
-
# don't change, don't track in version control
|
|
3
|
-
|
|
4
|
-
__all__ = [
|
|
5
|
-
"__version__",
|
|
6
|
-
"__version_tuple__",
|
|
7
|
-
"version",
|
|
8
|
-
"version_tuple",
|
|
9
|
-
"__commit_id__",
|
|
10
|
-
"commit_id",
|
|
11
|
-
]
|
|
12
|
-
|
|
13
|
-
TYPE_CHECKING = False
|
|
14
|
-
if TYPE_CHECKING:
|
|
15
|
-
from typing import Tuple
|
|
16
|
-
from typing import Union
|
|
17
|
-
|
|
18
|
-
VERSION_TUPLE = Tuple[Union[int, str], ...]
|
|
19
|
-
COMMIT_ID = Union[str, None]
|
|
20
|
-
else:
|
|
21
|
-
VERSION_TUPLE = object
|
|
22
|
-
COMMIT_ID = object
|
|
23
|
-
|
|
24
|
-
version: str
|
|
25
|
-
__version__: str
|
|
26
|
-
__version_tuple__: VERSION_TUPLE
|
|
27
|
-
version_tuple: VERSION_TUPLE
|
|
28
|
-
commit_id: COMMIT_ID
|
|
29
|
-
__commit_id__: COMMIT_ID
|
|
30
|
-
|
|
31
|
-
__version__ = version = '0.2.2'
|
|
32
|
-
__version_tuple__ = version_tuple = (0, 2, 2)
|
|
33
|
-
|
|
34
|
-
__commit_id__ = commit_id = None
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|