tourclaim 0.1.0__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.
- tourclaim-0.1.0/.gitignore +8 -0
- tourclaim-0.1.0/CHANGELOG.md +17 -0
- tourclaim-0.1.0/LICENSE +21 -0
- tourclaim-0.1.0/PKG-INFO +251 -0
- tourclaim-0.1.0/README.md +217 -0
- tourclaim-0.1.0/RELEASING.md +42 -0
- tourclaim-0.1.0/pyproject.toml +81 -0
- tourclaim-0.1.0/src/tourclaim/__init__.py +121 -0
- tourclaim-0.1.0/src/tourclaim/__main__.py +6 -0
- tourclaim-0.1.0/src/tourclaim/cli.py +1914 -0
- tourclaim-0.1.0/src/tourclaim/client.py +925 -0
- tourclaim-0.1.0/src/tourclaim/config.py +101 -0
- tourclaim-0.1.0/src/tourclaim/credentials.py +151 -0
- tourclaim-0.1.0/src/tourclaim/eml.py +167 -0
- tourclaim-0.1.0/src/tourclaim/errors.py +251 -0
- tourclaim-0.1.0/src/tourclaim/fields.py +214 -0
- tourclaim-0.1.0/src/tourclaim/filetype.py +32 -0
- tourclaim-0.1.0/src/tourclaim/format.py +229 -0
- tourclaim-0.1.0/src/tourclaim/models.py +198 -0
- tourclaim-0.1.0/src/tourclaim/output.py +92 -0
- tourclaim-0.1.0/src/tourclaim/py.typed +0 -0
- tourclaim-0.1.0/tests/conftest.py +189 -0
- tourclaim-0.1.0/tests/mock_server.py +1050 -0
- tourclaim-0.1.0/tests/test_auth.py +679 -0
- tourclaim-0.1.0/tests/test_client.py +385 -0
- tourclaim-0.1.0/tests/test_e2e.py +166 -0
- tourclaim-0.1.0/tests/test_intake.py +882 -0
- tourclaim-0.1.0/tests/test_meta.py +156 -0
- tourclaim-0.1.0/tests/test_units.py +286 -0
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to the Python edition of tourclaim are recorded here. The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and versions follow [Semantic Versioning](https://semver.org/).
|
|
4
|
+
|
|
5
|
+
## [0.1.0] - 2026-10-04
|
|
6
|
+
|
|
7
|
+
First version of the Python edition. Its commands, flags, JSON output, exit codes and credentials file match the Node edition.
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- `tourclaim.Client`, a typed library with one method per connector API operation (14 in all, including `list_drafts`, `get_connection`, `disconnect` and `request_data_deletion`), plus `device_login()` and `wait_for_signature()`. Errors are typed exceptions carrying `status`, `code` and `message`.
|
|
12
|
+
- The `tourclaim` command (also `python -m tourclaim`): `login` with device authorization (the traveler types the code shown in the terminal on the sign-in page; a replaced key is retired by the server; brief server errors while waiting are retried) or `--with-token`, `logout`, `status` (alias `whoami`), `cards search`, `intake start|list|show|set|attach|add-email|sign|submit|delete`, `claims list|show` and `schema`.
|
|
13
|
+
- The cause of every 409 (the API's `X-TourClaim-Error` header) as the JSON error `code`, with a fallback for servers that do not send the header.
|
|
14
|
+
- Credentials stored per API URL in the same file and format as the Node edition, with mode 0600 in a 0700 directory (`%APPDATA%\tourclaim` on Windows); `TOURCLAIM_API_KEY` and `TOURCLAIM_API_URL` overrides; a warning when the key expires within 3 days.
|
|
15
|
+
- Consent prompts (or `--yes`) before any evidence is shared, attachment types detected from file contents, and `.eml` parsing with the standard library.
|
|
16
|
+
- One automatic retry after a rate limit, honoring `Retry-After` up to 60 seconds. No runtime dependencies; Python 3.9 or newer.
|
|
17
|
+
- `Client.request_data_deletion()`: asks TourClaim to delete the traveler's data; nothing is deleted until they confirm from the email TourClaim sends.
|
tourclaim-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Copernican
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
tourclaim-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: tourclaim
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Client and command line for TourClaim: start, fill in and submit a trip cancellation claim against the travel insurance that comes with your credit card, from Python, a terminal or an AI agent.
|
|
5
|
+
Project-URL: Homepage, https://github.com/tourclaim/tourclaim-cli
|
|
6
|
+
Project-URL: Documentation, https://github.com/tourclaim/tourclaim-cli/tree/main/python#readme
|
|
7
|
+
Project-URL: Issues, https://github.com/tourclaim/tourclaim-cli/issues
|
|
8
|
+
Project-URL: Changelog, https://github.com/tourclaim/tourclaim-cli/blob/main/python/CHANGELOG.md
|
|
9
|
+
Author-email: Copernican <info@getcopernican.com>
|
|
10
|
+
License-Expression: MIT
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
Keywords: agent tools,ai agents,claims,cli,copernican,credit card benefits,insurance claims,sdk,tourclaim,travel insurance,trip cancellation,trip interruption
|
|
13
|
+
Classifier: Development Status :: 4 - Beta
|
|
14
|
+
Classifier: Environment :: Console
|
|
15
|
+
Classifier: Intended Audience :: Developers
|
|
16
|
+
Classifier: Intended Audience :: End Users/Desktop
|
|
17
|
+
Classifier: Operating System :: OS Independent
|
|
18
|
+
Classifier: Programming Language :: Python
|
|
19
|
+
Classifier: Programming Language :: Python :: 3
|
|
20
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
24
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
25
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
26
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
27
|
+
Classifier: Topic :: Office/Business :: Financial
|
|
28
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
29
|
+
Classifier: Typing :: Typed
|
|
30
|
+
Requires-Python: >=3.9
|
|
31
|
+
Provides-Extra: dev
|
|
32
|
+
Requires-Dist: pytest>=7; extra == 'dev'
|
|
33
|
+
Description-Content-Type: text/markdown
|
|
34
|
+
|
|
35
|
+
# tourclaim (Python)
|
|
36
|
+
|
|
37
|
+
Python client and command line for [TourClaim](https://app.getcopernican.com/muse) by Copernican: start, fill in and submit a trip cancellation claim against the travel insurance that comes with the credit card the trip was booked with. It works for a person at a terminal, for a Python program, and for an AI agent acting for one traveler.
|
|
38
|
+
|
|
39
|
+
> **Review mode.** The TourClaim connector API currently runs in review mode: it creates synthetic claims and files nothing with an insurer. Use fictional booking and medical data only. `tourclaim status` (or `Client().connector_info()["mode"]`) shows the current mode, and every draft and claim the API returns says which mode it came from.
|
|
40
|
+
|
|
41
|
+
This is the Python edition of [tourclaim](https://github.com/tourclaim/tourclaim-cli). It has the same commands, flags, output, exit codes and credentials file as the Node edition (`npx tourclaim`), so a key saved by one works in the other. It adds a typed library, `tourclaim.Client`.
|
|
42
|
+
|
|
43
|
+
## What it does
|
|
44
|
+
|
|
45
|
+
1. **Sign in.** The traveler opens the sign-in page in their own browser, types the code shown in the terminal, and approves. The tool saves a key that belongs to that traveler.
|
|
46
|
+
2. **Start a draft** with whatever the traveler has said, then answer the questions the API says are still open.
|
|
47
|
+
3. **Add evidence** the traveler chooses to share: receipts, itineraries, a doctor's note they already have, and booking or cancellation emails.
|
|
48
|
+
4. **The traveler signs.** They review the draft and sign an authorization in their own browser. This package cannot sign for them.
|
|
49
|
+
5. **Submit** the signed draft, then check the claim's status.
|
|
50
|
+
|
|
51
|
+
Nothing here decides whether a loss is covered, or promises reimbursement or a medical note. Copernican charges a 10% fee only when a claim is reimbursed; no payment is taken through this package. Only bookings charged in US dollars are supported.
|
|
52
|
+
|
|
53
|
+
AI agents: read [AGENTS.md](https://github.com/tourclaim/tourclaim-cli/blob/main/AGENTS.md) before driving the command line. The rules there apply to the library too.
|
|
54
|
+
|
|
55
|
+
## Install
|
|
56
|
+
|
|
57
|
+
Requires Python 3.9 or newer. There are no runtime dependencies.
|
|
58
|
+
|
|
59
|
+
```sh
|
|
60
|
+
pip install tourclaim
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
or run it without installing, or install it as an isolated command:
|
|
64
|
+
|
|
65
|
+
```sh
|
|
66
|
+
uvx tourclaim --help
|
|
67
|
+
pipx install tourclaim
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
`python -m tourclaim` works too.
|
|
71
|
+
|
|
72
|
+
## Command line quickstart
|
|
73
|
+
|
|
74
|
+
```sh
|
|
75
|
+
# 1. Connect to the traveler's account. Opens a page; the traveler enters the code shown.
|
|
76
|
+
tourclaim login
|
|
77
|
+
|
|
78
|
+
# 2. Find the card the booking was paid with (by product name, never a card number).
|
|
79
|
+
tourclaim cards search sapphire
|
|
80
|
+
|
|
81
|
+
# 3. Start a draft with what the traveler has said so far (check `tourclaim intake list` first).
|
|
82
|
+
tourclaim intake start --set merchant_name="Example Air" --set booking_ref=EXA-482913 \
|
|
83
|
+
--set reason_category=airline_cancellation
|
|
84
|
+
|
|
85
|
+
# 4. Answer what is missing. The draft id comes from step 3.
|
|
86
|
+
tourclaim intake set <id> trip_date=2026-03-04 booking_amount=250.00 refunded_amount=50.00 \
|
|
87
|
+
currency=USD card_product_id=412 other_insurance=no \
|
|
88
|
+
narrative="Example Air cancelled flight EX 204 the night before departure."
|
|
89
|
+
|
|
90
|
+
# 5. Add the evidence the traveler agreed to share.
|
|
91
|
+
tourclaim intake attach <id> receipt.pdf --type receipt
|
|
92
|
+
tourclaim intake add-email <id> --eml cancellation.eml
|
|
93
|
+
|
|
94
|
+
# 6. The traveler reviews and signs in their browser. --wait returns once they have.
|
|
95
|
+
tourclaim intake sign <id> --wait
|
|
96
|
+
|
|
97
|
+
# 7. Submit, then follow the claim.
|
|
98
|
+
tourclaim intake submit <id>
|
|
99
|
+
tourclaim claims list
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
Every command takes `--json` (one JSON value per line on stdout, errors as one JSON line on stderr), `--api-url <url>`, `-h`/`--help` and `--version`. The full command reference, the field table and the JSON output contract are in the [main README](https://github.com/tourclaim/tourclaim-cli#commands); they apply unchanged.
|
|
103
|
+
|
|
104
|
+
| Command | What it does |
|
|
105
|
+
| --- | --- |
|
|
106
|
+
| `tourclaim login` | Sign in: the traveler opens the sign-in page and types the code shown in the terminal (`--no-browser`, `--scope`, `--force`). Or `--with-token` to save an existing key read from stdin or a hidden prompt; such a key does not say whose account it is. |
|
|
107
|
+
| `tourclaim logout` | Revoke the key on the server and remove the stored copy. |
|
|
108
|
+
| `tourclaim status` (`whoami`) | The API mode, whether the connector is enabled, the signed-in account and key expiry. |
|
|
109
|
+
| `tourclaim cards search <name>` | Find a card product id. |
|
|
110
|
+
| `tourclaim intake start\|list\|show\|set\|attach\|add-email\|sign\|submit\|delete` | The whole draft lifecycle. |
|
|
111
|
+
| `tourclaim claims list\|show` | Submitted claims and their status. |
|
|
112
|
+
| `tourclaim schema` | The live OpenAPI document with every operation the CLI uses (`openapi-cli.json`; `openapi.json` on older servers). |
|
|
113
|
+
|
|
114
|
+
### Exit codes
|
|
115
|
+
|
|
116
|
+
| Code | Meaning |
|
|
117
|
+
| --- | --- |
|
|
118
|
+
| 0 | Success. |
|
|
119
|
+
| 1 | Error: invalid values (422), unreadable or unsupported file, network failure, timeout, declined prompt. |
|
|
120
|
+
| 2 | Usage: bad flags or arguments, or a confirmation was needed and there was no terminal. |
|
|
121
|
+
| 3 | Not signed in, or the key was rejected (401) or lacks permission (403). Also a declined or expired sign-in. |
|
|
122
|
+
| 4 | Conflict (409). The JSON error `code` names the cause: `stale_revision`, `approval_required`, `approval_outdated`, `intake_incomplete`, `intake_submitted`, `duplicate_booking`, `evidence_conflict`, `idempotency_key_reused`, `idempotency_key_other_connection` or `concurrent_request`. |
|
|
123
|
+
| 5 | Rate limited (429) after one automatic retry. |
|
|
124
|
+
| 6 | Not found (404). |
|
|
125
|
+
| 7 | The connector is disabled or unavailable (503). |
|
|
126
|
+
|
|
127
|
+
## Library quickstart
|
|
128
|
+
|
|
129
|
+
```python
|
|
130
|
+
from tourclaim import Client
|
|
131
|
+
|
|
132
|
+
# Uses TOURCLAIM_API_KEY, else the key `tourclaim login` saved. Or pass api_key=...
|
|
133
|
+
client = Client()
|
|
134
|
+
|
|
135
|
+
if not client.has_api_key:
|
|
136
|
+
# The traveler opens the page and types the code in their own browser; never put
|
|
137
|
+
# the code in a link. save=True stores the key where `tourclaim login` keeps it.
|
|
138
|
+
client.device_login(
|
|
139
|
+
on_code=lambda code: print(f"Open {code['verification_uri']}\nEnter this code on that page: {code['user_code']}"),
|
|
140
|
+
save=True,
|
|
141
|
+
)
|
|
142
|
+
|
|
143
|
+
# account_email is present only for keys from `tourclaim login` (device_login).
|
|
144
|
+
print(client.get_connection().get("account_email"), client.connector_info()["mode"])
|
|
145
|
+
|
|
146
|
+
drafts = client.list_drafts() # offer to continue one before starting another
|
|
147
|
+
draft = client.start_intake({"merchant_name": "Example Air", "reason_category": "AIRLINE_CANCELLATION"})
|
|
148
|
+
print(draft["missing_fields"], draft["next_questions"])
|
|
149
|
+
|
|
150
|
+
draft = client.update_intake(
|
|
151
|
+
draft["id"],
|
|
152
|
+
{
|
|
153
|
+
"booking_ref": "EXA-482913",
|
|
154
|
+
"trip_date": "2026-03-04",
|
|
155
|
+
"booking_amount": "250.00",
|
|
156
|
+
"refunded_amount": "50.00",
|
|
157
|
+
"currency": "USD",
|
|
158
|
+
"card_product_id": client.search_cards("sapphire preferred")[0]["id"],
|
|
159
|
+
"narrative": "Example Air cancelled flight EX 204 the night before departure.",
|
|
160
|
+
"other_insurance": "NO",
|
|
161
|
+
},
|
|
162
|
+
expected_revision=draft["revision"],
|
|
163
|
+
)
|
|
164
|
+
|
|
165
|
+
# Only after the traveler agreed to share this exact file:
|
|
166
|
+
with open("receipt.pdf", "rb") as f:
|
|
167
|
+
draft = client.add_attachment(
|
|
168
|
+
draft["id"], expected_revision=draft["revision"], filename="receipt.pdf",
|
|
169
|
+
content=f.read(), doc_type="receipt", user_authorized_sharing=True,
|
|
170
|
+
)
|
|
171
|
+
|
|
172
|
+
# The traveler signs at draft["review_url"] in their own browser.
|
|
173
|
+
print("Review and sign:", draft["review_url"])
|
|
174
|
+
signed = client.wait_for_signature(draft["id"], timeout=900)
|
|
175
|
+
|
|
176
|
+
claim = client.submit(draft["id"], expected_revision=signed["revision"])
|
|
177
|
+
print(claim["status"], claim["next_action"])
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
`Client(api_key=None, api_url=None)` has one method per API operation:
|
|
181
|
+
|
|
182
|
+
| Method | Operation |
|
|
183
|
+
| --- | --- |
|
|
184
|
+
| `connector_info()`, `schema()` | Discovery and the OpenAPI document (no key needed). |
|
|
185
|
+
| `get_connection()`, `disconnect()` | `get_connection`, `disconnect`: the key's account, expiry and scopes; revoke it. |
|
|
186
|
+
| `search_cards(query)` | `search_credit_cards` |
|
|
187
|
+
| `start_intake(fields=None, *, idempotency_key=None)` | `start_travel_claim` |
|
|
188
|
+
| `list_drafts(offset=0)` | `list_claim_drafts` |
|
|
189
|
+
| `get_intake(id)`, `update_intake(id, fields, *, expected_revision)`, `delete_draft(id)` | Read, change and delete a draft. |
|
|
190
|
+
| `add_email(id, *, expected_revision, subject, sender, text, user_authorized_sharing, ...)` | `import_selected_email` |
|
|
191
|
+
| `add_attachment(id, *, expected_revision, filename, content, doc_type, user_authorized_sharing)` | `import_claim_attachment` |
|
|
192
|
+
| `submit(id, *, expected_revision)` | `submit_authorized_travel_claim` (safe to retry) |
|
|
193
|
+
| `list_claims(offset=0)`, `get_claim(id)` | `list_my_claims`, `get_my_claim_status` |
|
|
194
|
+
| `device_login(scopes=None, *, on_code=None, save=False)` | Sign in with a device code (also `request_device_code`, `poll_device_token`, `wait_for_device_token`). |
|
|
195
|
+
| `wait_for_signature(id, *, timeout=900)` | Poll until the traveler has signed. |
|
|
196
|
+
|
|
197
|
+
Responses are plain `dict` objects described by typed dictionaries (`IntakeResponse`, `ClaimResponse`, `CardResponse`, `KeyInfo`, ...). After each call, `client.mode` holds the API's mode (`review` or `live`).
|
|
198
|
+
|
|
199
|
+
### Errors
|
|
200
|
+
|
|
201
|
+
Every exception derives from `tourclaim.TourClaimError` and carries `message`, `code` (stable, machine-readable), `status` (the HTTP status, or `None`), `exit_code` (what the command line would exit with) and `extra`. API errors (`APIError`) also carry `detail` and `headers`.
|
|
202
|
+
|
|
203
|
+
| Exception | When |
|
|
204
|
+
| --- | --- |
|
|
205
|
+
| `AuthenticationError` (401), `PermissionDeniedError` (403), `NotSignedInError` | The key is missing, expired, revoked or lacks the permission. |
|
|
206
|
+
| `NotFoundError` (404) | No such draft or claim for this key. |
|
|
207
|
+
| `ConflictError` (409) | `code` is the API's cause from `X-TourClaim-Error`, such as `stale_revision` or `approval_required`. |
|
|
208
|
+
| `ValidationError` (422) | `detail` lists each invalid field as `{loc, type, msg}`, or explains in a sentence. |
|
|
209
|
+
| `RateLimitError` (429) | `retry_after` seconds. The client retries once by itself when that is at most 60. |
|
|
210
|
+
| `UnavailableError` (503) | The connector is disabled or temporarily unavailable. |
|
|
211
|
+
| `NetworkError`, `RequestTimeoutError` | The API could not be reached, or did not answer in 90 seconds. |
|
|
212
|
+
| `AccessDeniedError`, `ExpiredTokenError` | The traveler declined the sign-in, or its code expired. |
|
|
213
|
+
| `ConsentRequiredError`, `UnsupportedFileError`, `FileTooLargeError`, `UsageError` | Checked before anything is sent. |
|
|
214
|
+
|
|
215
|
+
## Configuration
|
|
216
|
+
|
|
217
|
+
| Variable | Meaning |
|
|
218
|
+
| --- | --- |
|
|
219
|
+
| `TOURCLAIM_API_URL` | API base URL (default `https://app.getcopernican.com`). `--api-url` overrides it. Plain `http://` is accepted only for localhost. |
|
|
220
|
+
| `TOURCLAIM_API_KEY` | A key to use instead of the stored one. It takes precedence over the stored key. |
|
|
221
|
+
| `XDG_CONFIG_HOME` | Credentials are stored in `$XDG_CONFIG_HOME/tourclaim/credentials.json` (default `~/.config/tourclaim/credentials.json`; `%APPDATA%\tourclaim\credentials.json` on Windows). |
|
|
222
|
+
|
|
223
|
+
The credentials file maps each API base URL to `{"api_key","expires_at","grant_id","scopes"}` and is shared with the Node edition.
|
|
224
|
+
|
|
225
|
+
## Security
|
|
226
|
+
|
|
227
|
+
- **Keys belong to one traveler.** A key lasts 30 days and cannot be refreshed; a traveler can have at most 5 connections, and a new `tourclaim login` past that retires the account's oldest `tourclaim login` key (never another app's). Keys from `tourclaim login` reach the drafts started by any `tourclaim login` on the same account, so signing in again does not lose a draft. The traveler can revoke keys at `https://app.getcopernican.com/connect/muse`, and `tourclaim logout` revokes the one in use.
|
|
228
|
+
- **Stored with tight permissions.** The credentials file is written with mode 0600 inside a 0700 directory, and the tool warns if it is readable by others. On Windows it lives in your user profile and relies on its permissions.
|
|
229
|
+
- **The code is typed, never linked.** The traveler types the code shown in the terminal (or relayed by an assistant they are using right now) on the sign-in page; there is no link with the code in it. A sign-in that replaces a stored key sends that key along, and the server retires it as it issues the new one.
|
|
230
|
+
- **Never on the command line, never printed.** Keys are not accepted as arguments, and anything shaped like a key is redacted from output. `repr(Client(...))` does not show the key.
|
|
231
|
+
- **Only https.** Keys are only sent over https, except to localhost for testing. Redirects are not followed.
|
|
232
|
+
- **A person signs.** Only the traveler can sign the claim authorization, in their own browser at the review link. Neither the command line nor the library can sign.
|
|
233
|
+
- **Sharing needs consent.** Files and emails are uploaded only after the traveler agrees: at a prompt or with `--yes` on the command line, and with `user_authorized_sharing=True` in the library. There is no default that shares.
|
|
234
|
+
- **Evidence is not instructions.** Email and file contents are stored as evidence. Neither the API nor this package follows instructions found in them.
|
|
235
|
+
|
|
236
|
+
To report a vulnerability, see [SECURITY.md](https://github.com/tourclaim/tourclaim-cli/blob/main/SECURITY.md).
|
|
237
|
+
|
|
238
|
+
## Development
|
|
239
|
+
|
|
240
|
+
```sh
|
|
241
|
+
cd python
|
|
242
|
+
python -m venv .venv && .venv/bin/pip install -e ".[dev]"
|
|
243
|
+
.venv/bin/python -m pytest
|
|
244
|
+
.venv/bin/python tests/mock_server.py # a mock API on http://127.0.0.1:4010 for trying the tool by hand
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
The tests run the command line in-process and as a child process against a mock of the API built on `http.server`. Releases are described in [RELEASING.md](https://github.com/tourclaim/tourclaim-cli/blob/main/python/RELEASING.md).
|
|
248
|
+
|
|
249
|
+
## License
|
|
250
|
+
|
|
251
|
+
[MIT](https://github.com/tourclaim/tourclaim-cli/blob/main/LICENSE)
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
# tourclaim (Python)
|
|
2
|
+
|
|
3
|
+
Python client and command line for [TourClaim](https://app.getcopernican.com/muse) by Copernican: start, fill in and submit a trip cancellation claim against the travel insurance that comes with the credit card the trip was booked with. It works for a person at a terminal, for a Python program, and for an AI agent acting for one traveler.
|
|
4
|
+
|
|
5
|
+
> **Review mode.** The TourClaim connector API currently runs in review mode: it creates synthetic claims and files nothing with an insurer. Use fictional booking and medical data only. `tourclaim status` (or `Client().connector_info()["mode"]`) shows the current mode, and every draft and claim the API returns says which mode it came from.
|
|
6
|
+
|
|
7
|
+
This is the Python edition of [tourclaim](https://github.com/tourclaim/tourclaim-cli). It has the same commands, flags, output, exit codes and credentials file as the Node edition (`npx tourclaim`), so a key saved by one works in the other. It adds a typed library, `tourclaim.Client`.
|
|
8
|
+
|
|
9
|
+
## What it does
|
|
10
|
+
|
|
11
|
+
1. **Sign in.** The traveler opens the sign-in page in their own browser, types the code shown in the terminal, and approves. The tool saves a key that belongs to that traveler.
|
|
12
|
+
2. **Start a draft** with whatever the traveler has said, then answer the questions the API says are still open.
|
|
13
|
+
3. **Add evidence** the traveler chooses to share: receipts, itineraries, a doctor's note they already have, and booking or cancellation emails.
|
|
14
|
+
4. **The traveler signs.** They review the draft and sign an authorization in their own browser. This package cannot sign for them.
|
|
15
|
+
5. **Submit** the signed draft, then check the claim's status.
|
|
16
|
+
|
|
17
|
+
Nothing here decides whether a loss is covered, or promises reimbursement or a medical note. Copernican charges a 10% fee only when a claim is reimbursed; no payment is taken through this package. Only bookings charged in US dollars are supported.
|
|
18
|
+
|
|
19
|
+
AI agents: read [AGENTS.md](https://github.com/tourclaim/tourclaim-cli/blob/main/AGENTS.md) before driving the command line. The rules there apply to the library too.
|
|
20
|
+
|
|
21
|
+
## Install
|
|
22
|
+
|
|
23
|
+
Requires Python 3.9 or newer. There are no runtime dependencies.
|
|
24
|
+
|
|
25
|
+
```sh
|
|
26
|
+
pip install tourclaim
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
or run it without installing, or install it as an isolated command:
|
|
30
|
+
|
|
31
|
+
```sh
|
|
32
|
+
uvx tourclaim --help
|
|
33
|
+
pipx install tourclaim
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
`python -m tourclaim` works too.
|
|
37
|
+
|
|
38
|
+
## Command line quickstart
|
|
39
|
+
|
|
40
|
+
```sh
|
|
41
|
+
# 1. Connect to the traveler's account. Opens a page; the traveler enters the code shown.
|
|
42
|
+
tourclaim login
|
|
43
|
+
|
|
44
|
+
# 2. Find the card the booking was paid with (by product name, never a card number).
|
|
45
|
+
tourclaim cards search sapphire
|
|
46
|
+
|
|
47
|
+
# 3. Start a draft with what the traveler has said so far (check `tourclaim intake list` first).
|
|
48
|
+
tourclaim intake start --set merchant_name="Example Air" --set booking_ref=EXA-482913 \
|
|
49
|
+
--set reason_category=airline_cancellation
|
|
50
|
+
|
|
51
|
+
# 4. Answer what is missing. The draft id comes from step 3.
|
|
52
|
+
tourclaim intake set <id> trip_date=2026-03-04 booking_amount=250.00 refunded_amount=50.00 \
|
|
53
|
+
currency=USD card_product_id=412 other_insurance=no \
|
|
54
|
+
narrative="Example Air cancelled flight EX 204 the night before departure."
|
|
55
|
+
|
|
56
|
+
# 5. Add the evidence the traveler agreed to share.
|
|
57
|
+
tourclaim intake attach <id> receipt.pdf --type receipt
|
|
58
|
+
tourclaim intake add-email <id> --eml cancellation.eml
|
|
59
|
+
|
|
60
|
+
# 6. The traveler reviews and signs in their browser. --wait returns once they have.
|
|
61
|
+
tourclaim intake sign <id> --wait
|
|
62
|
+
|
|
63
|
+
# 7. Submit, then follow the claim.
|
|
64
|
+
tourclaim intake submit <id>
|
|
65
|
+
tourclaim claims list
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Every command takes `--json` (one JSON value per line on stdout, errors as one JSON line on stderr), `--api-url <url>`, `-h`/`--help` and `--version`. The full command reference, the field table and the JSON output contract are in the [main README](https://github.com/tourclaim/tourclaim-cli#commands); they apply unchanged.
|
|
69
|
+
|
|
70
|
+
| Command | What it does |
|
|
71
|
+
| --- | --- |
|
|
72
|
+
| `tourclaim login` | Sign in: the traveler opens the sign-in page and types the code shown in the terminal (`--no-browser`, `--scope`, `--force`). Or `--with-token` to save an existing key read from stdin or a hidden prompt; such a key does not say whose account it is. |
|
|
73
|
+
| `tourclaim logout` | Revoke the key on the server and remove the stored copy. |
|
|
74
|
+
| `tourclaim status` (`whoami`) | The API mode, whether the connector is enabled, the signed-in account and key expiry. |
|
|
75
|
+
| `tourclaim cards search <name>` | Find a card product id. |
|
|
76
|
+
| `tourclaim intake start\|list\|show\|set\|attach\|add-email\|sign\|submit\|delete` | The whole draft lifecycle. |
|
|
77
|
+
| `tourclaim claims list\|show` | Submitted claims and their status. |
|
|
78
|
+
| `tourclaim schema` | The live OpenAPI document with every operation the CLI uses (`openapi-cli.json`; `openapi.json` on older servers). |
|
|
79
|
+
|
|
80
|
+
### Exit codes
|
|
81
|
+
|
|
82
|
+
| Code | Meaning |
|
|
83
|
+
| --- | --- |
|
|
84
|
+
| 0 | Success. |
|
|
85
|
+
| 1 | Error: invalid values (422), unreadable or unsupported file, network failure, timeout, declined prompt. |
|
|
86
|
+
| 2 | Usage: bad flags or arguments, or a confirmation was needed and there was no terminal. |
|
|
87
|
+
| 3 | Not signed in, or the key was rejected (401) or lacks permission (403). Also a declined or expired sign-in. |
|
|
88
|
+
| 4 | Conflict (409). The JSON error `code` names the cause: `stale_revision`, `approval_required`, `approval_outdated`, `intake_incomplete`, `intake_submitted`, `duplicate_booking`, `evidence_conflict`, `idempotency_key_reused`, `idempotency_key_other_connection` or `concurrent_request`. |
|
|
89
|
+
| 5 | Rate limited (429) after one automatic retry. |
|
|
90
|
+
| 6 | Not found (404). |
|
|
91
|
+
| 7 | The connector is disabled or unavailable (503). |
|
|
92
|
+
|
|
93
|
+
## Library quickstart
|
|
94
|
+
|
|
95
|
+
```python
|
|
96
|
+
from tourclaim import Client
|
|
97
|
+
|
|
98
|
+
# Uses TOURCLAIM_API_KEY, else the key `tourclaim login` saved. Or pass api_key=...
|
|
99
|
+
client = Client()
|
|
100
|
+
|
|
101
|
+
if not client.has_api_key:
|
|
102
|
+
# The traveler opens the page and types the code in their own browser; never put
|
|
103
|
+
# the code in a link. save=True stores the key where `tourclaim login` keeps it.
|
|
104
|
+
client.device_login(
|
|
105
|
+
on_code=lambda code: print(f"Open {code['verification_uri']}\nEnter this code on that page: {code['user_code']}"),
|
|
106
|
+
save=True,
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
# account_email is present only for keys from `tourclaim login` (device_login).
|
|
110
|
+
print(client.get_connection().get("account_email"), client.connector_info()["mode"])
|
|
111
|
+
|
|
112
|
+
drafts = client.list_drafts() # offer to continue one before starting another
|
|
113
|
+
draft = client.start_intake({"merchant_name": "Example Air", "reason_category": "AIRLINE_CANCELLATION"})
|
|
114
|
+
print(draft["missing_fields"], draft["next_questions"])
|
|
115
|
+
|
|
116
|
+
draft = client.update_intake(
|
|
117
|
+
draft["id"],
|
|
118
|
+
{
|
|
119
|
+
"booking_ref": "EXA-482913",
|
|
120
|
+
"trip_date": "2026-03-04",
|
|
121
|
+
"booking_amount": "250.00",
|
|
122
|
+
"refunded_amount": "50.00",
|
|
123
|
+
"currency": "USD",
|
|
124
|
+
"card_product_id": client.search_cards("sapphire preferred")[0]["id"],
|
|
125
|
+
"narrative": "Example Air cancelled flight EX 204 the night before departure.",
|
|
126
|
+
"other_insurance": "NO",
|
|
127
|
+
},
|
|
128
|
+
expected_revision=draft["revision"],
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
# Only after the traveler agreed to share this exact file:
|
|
132
|
+
with open("receipt.pdf", "rb") as f:
|
|
133
|
+
draft = client.add_attachment(
|
|
134
|
+
draft["id"], expected_revision=draft["revision"], filename="receipt.pdf",
|
|
135
|
+
content=f.read(), doc_type="receipt", user_authorized_sharing=True,
|
|
136
|
+
)
|
|
137
|
+
|
|
138
|
+
# The traveler signs at draft["review_url"] in their own browser.
|
|
139
|
+
print("Review and sign:", draft["review_url"])
|
|
140
|
+
signed = client.wait_for_signature(draft["id"], timeout=900)
|
|
141
|
+
|
|
142
|
+
claim = client.submit(draft["id"], expected_revision=signed["revision"])
|
|
143
|
+
print(claim["status"], claim["next_action"])
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
`Client(api_key=None, api_url=None)` has one method per API operation:
|
|
147
|
+
|
|
148
|
+
| Method | Operation |
|
|
149
|
+
| --- | --- |
|
|
150
|
+
| `connector_info()`, `schema()` | Discovery and the OpenAPI document (no key needed). |
|
|
151
|
+
| `get_connection()`, `disconnect()` | `get_connection`, `disconnect`: the key's account, expiry and scopes; revoke it. |
|
|
152
|
+
| `search_cards(query)` | `search_credit_cards` |
|
|
153
|
+
| `start_intake(fields=None, *, idempotency_key=None)` | `start_travel_claim` |
|
|
154
|
+
| `list_drafts(offset=0)` | `list_claim_drafts` |
|
|
155
|
+
| `get_intake(id)`, `update_intake(id, fields, *, expected_revision)`, `delete_draft(id)` | Read, change and delete a draft. |
|
|
156
|
+
| `add_email(id, *, expected_revision, subject, sender, text, user_authorized_sharing, ...)` | `import_selected_email` |
|
|
157
|
+
| `add_attachment(id, *, expected_revision, filename, content, doc_type, user_authorized_sharing)` | `import_claim_attachment` |
|
|
158
|
+
| `submit(id, *, expected_revision)` | `submit_authorized_travel_claim` (safe to retry) |
|
|
159
|
+
| `list_claims(offset=0)`, `get_claim(id)` | `list_my_claims`, `get_my_claim_status` |
|
|
160
|
+
| `device_login(scopes=None, *, on_code=None, save=False)` | Sign in with a device code (also `request_device_code`, `poll_device_token`, `wait_for_device_token`). |
|
|
161
|
+
| `wait_for_signature(id, *, timeout=900)` | Poll until the traveler has signed. |
|
|
162
|
+
|
|
163
|
+
Responses are plain `dict` objects described by typed dictionaries (`IntakeResponse`, `ClaimResponse`, `CardResponse`, `KeyInfo`, ...). After each call, `client.mode` holds the API's mode (`review` or `live`).
|
|
164
|
+
|
|
165
|
+
### Errors
|
|
166
|
+
|
|
167
|
+
Every exception derives from `tourclaim.TourClaimError` and carries `message`, `code` (stable, machine-readable), `status` (the HTTP status, or `None`), `exit_code` (what the command line would exit with) and `extra`. API errors (`APIError`) also carry `detail` and `headers`.
|
|
168
|
+
|
|
169
|
+
| Exception | When |
|
|
170
|
+
| --- | --- |
|
|
171
|
+
| `AuthenticationError` (401), `PermissionDeniedError` (403), `NotSignedInError` | The key is missing, expired, revoked or lacks the permission. |
|
|
172
|
+
| `NotFoundError` (404) | No such draft or claim for this key. |
|
|
173
|
+
| `ConflictError` (409) | `code` is the API's cause from `X-TourClaim-Error`, such as `stale_revision` or `approval_required`. |
|
|
174
|
+
| `ValidationError` (422) | `detail` lists each invalid field as `{loc, type, msg}`, or explains in a sentence. |
|
|
175
|
+
| `RateLimitError` (429) | `retry_after` seconds. The client retries once by itself when that is at most 60. |
|
|
176
|
+
| `UnavailableError` (503) | The connector is disabled or temporarily unavailable. |
|
|
177
|
+
| `NetworkError`, `RequestTimeoutError` | The API could not be reached, or did not answer in 90 seconds. |
|
|
178
|
+
| `AccessDeniedError`, `ExpiredTokenError` | The traveler declined the sign-in, or its code expired. |
|
|
179
|
+
| `ConsentRequiredError`, `UnsupportedFileError`, `FileTooLargeError`, `UsageError` | Checked before anything is sent. |
|
|
180
|
+
|
|
181
|
+
## Configuration
|
|
182
|
+
|
|
183
|
+
| Variable | Meaning |
|
|
184
|
+
| --- | --- |
|
|
185
|
+
| `TOURCLAIM_API_URL` | API base URL (default `https://app.getcopernican.com`). `--api-url` overrides it. Plain `http://` is accepted only for localhost. |
|
|
186
|
+
| `TOURCLAIM_API_KEY` | A key to use instead of the stored one. It takes precedence over the stored key. |
|
|
187
|
+
| `XDG_CONFIG_HOME` | Credentials are stored in `$XDG_CONFIG_HOME/tourclaim/credentials.json` (default `~/.config/tourclaim/credentials.json`; `%APPDATA%\tourclaim\credentials.json` on Windows). |
|
|
188
|
+
|
|
189
|
+
The credentials file maps each API base URL to `{"api_key","expires_at","grant_id","scopes"}` and is shared with the Node edition.
|
|
190
|
+
|
|
191
|
+
## Security
|
|
192
|
+
|
|
193
|
+
- **Keys belong to one traveler.** A key lasts 30 days and cannot be refreshed; a traveler can have at most 5 connections, and a new `tourclaim login` past that retires the account's oldest `tourclaim login` key (never another app's). Keys from `tourclaim login` reach the drafts started by any `tourclaim login` on the same account, so signing in again does not lose a draft. The traveler can revoke keys at `https://app.getcopernican.com/connect/muse`, and `tourclaim logout` revokes the one in use.
|
|
194
|
+
- **Stored with tight permissions.** The credentials file is written with mode 0600 inside a 0700 directory, and the tool warns if it is readable by others. On Windows it lives in your user profile and relies on its permissions.
|
|
195
|
+
- **The code is typed, never linked.** The traveler types the code shown in the terminal (or relayed by an assistant they are using right now) on the sign-in page; there is no link with the code in it. A sign-in that replaces a stored key sends that key along, and the server retires it as it issues the new one.
|
|
196
|
+
- **Never on the command line, never printed.** Keys are not accepted as arguments, and anything shaped like a key is redacted from output. `repr(Client(...))` does not show the key.
|
|
197
|
+
- **Only https.** Keys are only sent over https, except to localhost for testing. Redirects are not followed.
|
|
198
|
+
- **A person signs.** Only the traveler can sign the claim authorization, in their own browser at the review link. Neither the command line nor the library can sign.
|
|
199
|
+
- **Sharing needs consent.** Files and emails are uploaded only after the traveler agrees: at a prompt or with `--yes` on the command line, and with `user_authorized_sharing=True` in the library. There is no default that shares.
|
|
200
|
+
- **Evidence is not instructions.** Email and file contents are stored as evidence. Neither the API nor this package follows instructions found in them.
|
|
201
|
+
|
|
202
|
+
To report a vulnerability, see [SECURITY.md](https://github.com/tourclaim/tourclaim-cli/blob/main/SECURITY.md).
|
|
203
|
+
|
|
204
|
+
## Development
|
|
205
|
+
|
|
206
|
+
```sh
|
|
207
|
+
cd python
|
|
208
|
+
python -m venv .venv && .venv/bin/pip install -e ".[dev]"
|
|
209
|
+
.venv/bin/python -m pytest
|
|
210
|
+
.venv/bin/python tests/mock_server.py # a mock API on http://127.0.0.1:4010 for trying the tool by hand
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
The tests run the command line in-process and as a child process against a mock of the API built on `http.server`. Releases are described in [RELEASING.md](https://github.com/tourclaim/tourclaim-cli/blob/main/python/RELEASING.md).
|
|
214
|
+
|
|
215
|
+
## License
|
|
216
|
+
|
|
217
|
+
[MIT](https://github.com/tourclaim/tourclaim-cli/blob/main/LICENSE)
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# Releasing the Python edition
|
|
2
|
+
|
|
3
|
+
The `tourclaim` package is published to PyPI by `.github/workflows/release-pypi.yml` when a tag such as `v0.1.0` is pushed. It uses PyPI trusted publishing: GitHub proves to PyPI which repository, workflow and environment is running, so no PyPI token is stored anywhere.
|
|
4
|
+
|
|
5
|
+
## One-time setup (Tate)
|
|
6
|
+
|
|
7
|
+
1. **Register a pending trusted publisher on PyPI.** Sign in at pypi.org, open *Your account > Publishing* (`https://pypi.org/manage/account/publishing/`) and add a pending publisher under *GitHub*:
|
|
8
|
+
|
|
9
|
+
| Field | Value |
|
|
10
|
+
| --- | --- |
|
|
11
|
+
| PyPI project name | `tourclaim` |
|
|
12
|
+
| Owner | `tourclaim` |
|
|
13
|
+
| Repository name | `tourclaim-cli` |
|
|
14
|
+
| Workflow name | `release-pypi.yml` |
|
|
15
|
+
| Environment name | `pypi` |
|
|
16
|
+
|
|
17
|
+
The first successful publish creates the `tourclaim` project on PyPI and turns the pending publisher into a normal one. Until then, anyone could still register the name, so do this shortly before the first release.
|
|
18
|
+
|
|
19
|
+
2. **Create the `pypi` environment on GitHub.** In the repository settings, under *Environments*, add an environment named `pypi`. Adding yourself as a required reviewer means every publish waits for your approval. Restrict its deployment branches and tags to `v*` tags.
|
|
20
|
+
|
|
21
|
+
## Each release
|
|
22
|
+
|
|
23
|
+
1. Set the version in `python/src/tourclaim/__init__.py` (`__version__ = "X.Y.Z"`) and add a `## [X.Y.Z] - YYYY-MM-DD` section to `python/CHANGELOG.md`. The Node edition's `package.json` uses the same version, because one tag releases both.
|
|
24
|
+
2. Commit, and check that CI passes on all platforms.
|
|
25
|
+
3. Tag and push the tag:
|
|
26
|
+
|
|
27
|
+
```sh
|
|
28
|
+
git tag v0.1.0
|
|
29
|
+
git push origin v0.1.0
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
The workflow then runs the Python tests, checks that the tag (without its `v`) equals `tourclaim.__version__`, builds the sdist and wheel with `python -m build`, checks them with `twine check`, and publishes them from the `pypi` environment. A tag that does not match the version fails before anything is published. PyPI never accepts the same version twice, so a broken release is fixed with a new version, not a re-upload.
|
|
33
|
+
|
|
34
|
+
## Checking a build locally
|
|
35
|
+
|
|
36
|
+
```sh
|
|
37
|
+
cd python
|
|
38
|
+
python -m venv .venv && .venv/bin/pip install -e ".[dev]" build twine
|
|
39
|
+
.venv/bin/python -m pytest
|
|
40
|
+
.venv/bin/python -m build
|
|
41
|
+
.venv/bin/python -m twine check --strict dist/*
|
|
42
|
+
```
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling>=1.27"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "tourclaim"
|
|
7
|
+
dynamic = ["version"]
|
|
8
|
+
description = "Client and command line for TourClaim: start, fill in and submit a trip cancellation claim against the travel insurance that comes with your credit card, from Python, a terminal or an AI agent."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = "MIT"
|
|
11
|
+
license-files = ["LICENSE"]
|
|
12
|
+
requires-python = ">=3.9"
|
|
13
|
+
authors = [{ name = "Copernican", email = "info@getcopernican.com" }]
|
|
14
|
+
keywords = [
|
|
15
|
+
"tourclaim",
|
|
16
|
+
"copernican",
|
|
17
|
+
"travel insurance",
|
|
18
|
+
"trip cancellation",
|
|
19
|
+
"trip interruption",
|
|
20
|
+
"claims",
|
|
21
|
+
"insurance claims",
|
|
22
|
+
"credit card benefits",
|
|
23
|
+
"ai agents",
|
|
24
|
+
"agent tools",
|
|
25
|
+
"cli",
|
|
26
|
+
"sdk",
|
|
27
|
+
]
|
|
28
|
+
classifiers = [
|
|
29
|
+
"Development Status :: 4 - Beta",
|
|
30
|
+
"Environment :: Console",
|
|
31
|
+
"Intended Audience :: Developers",
|
|
32
|
+
"Intended Audience :: End Users/Desktop",
|
|
33
|
+
"Operating System :: OS Independent",
|
|
34
|
+
"Programming Language :: Python",
|
|
35
|
+
"Programming Language :: Python :: 3",
|
|
36
|
+
"Programming Language :: Python :: 3 :: Only",
|
|
37
|
+
"Programming Language :: Python :: 3.9",
|
|
38
|
+
"Programming Language :: Python :: 3.10",
|
|
39
|
+
"Programming Language :: Python :: 3.11",
|
|
40
|
+
"Programming Language :: Python :: 3.12",
|
|
41
|
+
"Programming Language :: Python :: 3.13",
|
|
42
|
+
"Programming Language :: Python :: 3.14",
|
|
43
|
+
"Topic :: Office/Business :: Financial",
|
|
44
|
+
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
45
|
+
"Typing :: Typed",
|
|
46
|
+
]
|
|
47
|
+
dependencies = []
|
|
48
|
+
|
|
49
|
+
[project.optional-dependencies]
|
|
50
|
+
dev = ["pytest>=7"]
|
|
51
|
+
|
|
52
|
+
[project.urls]
|
|
53
|
+
Homepage = "https://github.com/tourclaim/tourclaim-cli"
|
|
54
|
+
Documentation = "https://github.com/tourclaim/tourclaim-cli/tree/main/python#readme"
|
|
55
|
+
Issues = "https://github.com/tourclaim/tourclaim-cli/issues"
|
|
56
|
+
Changelog = "https://github.com/tourclaim/tourclaim-cli/blob/main/python/CHANGELOG.md"
|
|
57
|
+
|
|
58
|
+
[project.scripts]
|
|
59
|
+
tourclaim = "tourclaim.cli:main"
|
|
60
|
+
|
|
61
|
+
[tool.hatch.version]
|
|
62
|
+
path = "src/tourclaim/__init__.py"
|
|
63
|
+
|
|
64
|
+
[tool.hatch.build.targets.wheel]
|
|
65
|
+
packages = ["src/tourclaim"]
|
|
66
|
+
|
|
67
|
+
[tool.hatch.build.targets.sdist]
|
|
68
|
+
include = [
|
|
69
|
+
"src/tourclaim",
|
|
70
|
+
"tests",
|
|
71
|
+
"README.md",
|
|
72
|
+
"CHANGELOG.md",
|
|
73
|
+
"RELEASING.md",
|
|
74
|
+
"LICENSE",
|
|
75
|
+
"pyproject.toml",
|
|
76
|
+
]
|
|
77
|
+
exclude = ["__pycache__", "*.pyc"]
|
|
78
|
+
|
|
79
|
+
[tool.pytest.ini_options]
|
|
80
|
+
testpaths = ["tests"]
|
|
81
|
+
addopts = "-p no:cacheprovider"
|