outline-client 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.
Files changed (69) hide show
  1. outline_client-0.1.0/CHANGELOG.md +5 -0
  2. outline_client-0.1.0/LICENSE +21 -0
  3. outline_client-0.1.0/PKG-INFO +355 -0
  4. outline_client-0.1.0/README.md +325 -0
  5. outline_client-0.1.0/pyproject.toml +60 -0
  6. outline_client-0.1.0/src/outline_client/__init__.py +252 -0
  7. outline_client-0.1.0/src/outline_client/async_client.py +3845 -0
  8. outline_client-0.1.0/src/outline_client/cli/__init__.py +122 -0
  9. outline_client-0.1.0/src/outline_client/cli/__main__.py +4 -0
  10. outline_client-0.1.0/src/outline_client/cli/commands/__init__.py +0 -0
  11. outline_client-0.1.0/src/outline_client/cli/commands/access_requests.py +55 -0
  12. outline_client-0.1.0/src/outline_client/cli/commands/api_keys.py +76 -0
  13. outline_client-0.1.0/src/outline_client/cli/commands/attachments.py +112 -0
  14. outline_client-0.1.0/src/outline_client/cli/commands/auth.py +40 -0
  15. outline_client-0.1.0/src/outline_client/cli/commands/collections.py +378 -0
  16. outline_client-0.1.0/src/outline_client/cli/commands/comments.py +165 -0
  17. outline_client-0.1.0/src/outline_client/cli/commands/data_attributes.py +120 -0
  18. outline_client-0.1.0/src/outline_client/cli/commands/documents.py +837 -0
  19. outline_client-0.1.0/src/outline_client/cli/commands/events.py +58 -0
  20. outline_client-0.1.0/src/outline_client/cli/commands/file_operations.py +72 -0
  21. outline_client-0.1.0/src/outline_client/cli/commands/groups.py +166 -0
  22. outline_client-0.1.0/src/outline_client/cli/commands/notifications.py +76 -0
  23. outline_client-0.1.0/src/outline_client/cli/commands/oauth.py +162 -0
  24. outline_client-0.1.0/src/outline_client/cli/commands/pins.py +84 -0
  25. outline_client-0.1.0/src/outline_client/cli/commands/revisions.py +78 -0
  26. outline_client-0.1.0/src/outline_client/cli/commands/shares.py +101 -0
  27. outline_client-0.1.0/src/outline_client/cli/commands/stars.py +65 -0
  28. outline_client-0.1.0/src/outline_client/cli/commands/subscriptions.py +93 -0
  29. outline_client-0.1.0/src/outline_client/cli/commands/templates.py +167 -0
  30. outline_client-0.1.0/src/outline_client/cli/commands/users.py +233 -0
  31. outline_client-0.1.0/src/outline_client/cli/commands/webhooks.py +105 -0
  32. outline_client-0.1.0/src/outline_client/cli/context.py +50 -0
  33. outline_client-0.1.0/src/outline_client/cli/group.py +76 -0
  34. outline_client-0.1.0/src/outline_client/cli/options.py +112 -0
  35. outline_client-0.1.0/src/outline_client/cli/output.py +66 -0
  36. outline_client-0.1.0/src/outline_client/client.py +3827 -0
  37. outline_client-0.1.0/src/outline_client/errors.py +228 -0
  38. outline_client-0.1.0/src/outline_client/operations/__init__.py +0 -0
  39. outline_client-0.1.0/src/outline_client/operations/access_requests.py +85 -0
  40. outline_client-0.1.0/src/outline_client/operations/api_keys.py +80 -0
  41. outline_client-0.1.0/src/outline_client/operations/attachments.py +109 -0
  42. outline_client-0.1.0/src/outline_client/operations/auth.py +59 -0
  43. outline_client-0.1.0/src/outline_client/operations/collections.py +495 -0
  44. outline_client-0.1.0/src/outline_client/operations/comments.py +214 -0
  45. outline_client-0.1.0/src/outline_client/operations/data_attributes.py +133 -0
  46. outline_client-0.1.0/src/outline_client/operations/documents.py +933 -0
  47. outline_client-0.1.0/src/outline_client/operations/events.py +41 -0
  48. outline_client-0.1.0/src/outline_client/operations/file_operations.py +75 -0
  49. outline_client-0.1.0/src/outline_client/operations/generic.py +247 -0
  50. outline_client-0.1.0/src/outline_client/operations/groups.py +224 -0
  51. outline_client-0.1.0/src/outline_client/operations/notifications.py +80 -0
  52. outline_client-0.1.0/src/outline_client/operations/oauth.py +215 -0
  53. outline_client-0.1.0/src/outline_client/operations/pins.py +114 -0
  54. outline_client-0.1.0/src/outline_client/operations/reactions.py +25 -0
  55. outline_client-0.1.0/src/outline_client/operations/revisions.py +110 -0
  56. outline_client-0.1.0/src/outline_client/operations/shares.py +123 -0
  57. outline_client-0.1.0/src/outline_client/operations/stars.py +91 -0
  58. outline_client-0.1.0/src/outline_client/operations/subscriptions.py +108 -0
  59. outline_client-0.1.0/src/outline_client/operations/templates.py +192 -0
  60. outline_client-0.1.0/src/outline_client/operations/users.py +322 -0
  61. outline_client-0.1.0/src/outline_client/operations/views.py +24 -0
  62. outline_client-0.1.0/src/outline_client/operations/webhook_subscriptions.py +104 -0
  63. outline_client-0.1.0/src/outline_client/py.typed +0 -0
  64. outline_client-0.1.0/src/outline_client/schemas/__init__.py +228 -0
  65. outline_client-0.1.0/src/outline_client/schemas/base.py +25 -0
  66. outline_client-0.1.0/src/outline_client/schemas/envelopes.py +58 -0
  67. outline_client-0.1.0/src/outline_client/schemas/models.py +1946 -0
  68. outline_client-0.1.0/src/outline_client/schemas/results.py +441 -0
  69. outline_client-0.1.0/src/outline_client/transport.py +266 -0
@@ -0,0 +1,5 @@
1
+ # Changelog
2
+
3
+ ## [0.1.0] - 2026-09-22
4
+
5
+ - First release. `OutlineClient` and `AsyncOutlineClient` cover all 154 methods in Outline's OpenAPI specification, with Pydantic models generated from it, and an `outline` CLI over the same surface.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 SB&O Inc
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.
@@ -0,0 +1,355 @@
1
+ Metadata-Version: 2.4
2
+ Name: outline-client
3
+ Version: 0.1.0
4
+ Summary: Outline knowledge base Python API client
5
+ Keywords: outline,knowledge-base,api,client,cli
6
+ Author: SB&O Inc
7
+ Author-email: SB&O Inc <contact@sboinc.com>
8
+ License-Expression: MIT
9
+ License-File: LICENSE
10
+ Classifier: Development Status :: 3 - Alpha
11
+ Classifier: Environment :: Console
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: Operating System :: OS Independent
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.12
16
+ Classifier: Programming Language :: Python :: 3.13
17
+ Classifier: Programming Language :: Python :: 3.14
18
+ Classifier: Topic :: Office/Business :: Groupware
19
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
20
+ Classifier: Typing :: Typed
21
+ Requires-Dist: click>=8.0.0
22
+ Requires-Dist: httpx>=0.20.0
23
+ Requires-Dist: pydantic>=2.10.0
24
+ Requires-Python: >=3.12
25
+ Project-URL: Download, https://github.com/sbo-inc/outline-client/releases
26
+ Project-URL: Homepage, https://github.com/sbo-inc/outline-client
27
+ Project-URL: Issues, https://github.com/sbo-inc/outline-client/issues
28
+ Project-URL: Repository, https://github.com/sbo-inc/outline-client
29
+ Description-Content-Type: text/markdown
30
+
31
+ [![CI](https://github.com/sbo-inc/outline-client/actions/workflows/ci.yaml/badge.svg?branch=main)](https://github.com/sbo-inc/outline-client/actions/workflows/ci.yaml)
32
+ [![PyPI](https://img.shields.io/pypi/v/outline-client.svg)](https://pypi.org/project/outline-client/)
33
+ [![Python versions](https://img.shields.io/pypi/pyversions/outline-client.svg)](https://pypi.org/project/outline-client/)
34
+ [![License](https://img.shields.io/pypi/l/outline-client.svg)](https://github.com/sbo-inc/outline-client/blob/main/LICENSE)
35
+
36
+ # Outline Python client
37
+
38
+ An unofficial typed Python client and command-line interface for the [Outline](https://www.getoutline.com) knowledge base API - no affiliation with Outline is implied or intended.
39
+
40
+ Outline's API is RPC-style: every method is a `POST` to `https://your-outline/api/:method`. This package wraps all **154** of them in a fully type-hinted client built on [Pydantic](https://docs.pydantic.dev/) models generated from the [published OpenAPI specification](https://github.com/outline/openapi), plus an `outline` CLI for reaching them from the terminal.
41
+
42
+ ## Features
43
+
44
+ - **Complete** - every method in the specification, on both the sync and async clients and in the CLI.
45
+ - **Typed models** - schemas are generated from the OpenAPI specification with [datamodel-code-generator](https://github.com/koxudaxi/datamodel-code-generator), so `make schemas` is the whole upgrade path when the spec moves.
46
+ - **Sync and async** - `OutlineClient` and `AsyncOutlineClient` take the same arguments and return the same models.
47
+ - **Python client and CLI** - use it as a library, or straight from the shell via `outline`.
48
+ - **Typed errors** - a failed call raises `NotFoundError`, `RateLimitError`, `AuthorizationError` and friends rather than a bare exception.
49
+ - **Forward compatible** - fields Outline adds before the specification catches up are preserved rather than dropped.
50
+
51
+ ## Installation
52
+
53
+ The package is published on PyPI as [`outline-client`](https://pypi.org/project/outline-client/):
54
+
55
+ ```bash
56
+ pip install outline-client
57
+ # or, with uv:
58
+ uv add outline-client
59
+ ```
60
+
61
+ Requires Python 3.12+.
62
+
63
+ ## Configuration
64
+
65
+ An API token is the only credential this client uses. Create one under **Settings => API & Apps**; Outline's tokens begin with `ol_api_`. Treat it like a password - it carries the full access of the user who created it, and it is shown only once.
66
+
67
+ Settings are read from environment variables, or can be passed directly to the client:
68
+
69
+ | Variable | Description |
70
+ | --- | --- |
71
+ | `OUTLINE_API_URL` | The API endpoint. A workspace URL is accepted and has `/api` appended. Defaults to `https://app.getoutline.com/api`. |
72
+ | `OUTLINE_API_TOKEN` | The API token. |
73
+
74
+ ```bash
75
+ # Cloud-hosted; OUTLINE_API_URL can be omitted.
76
+ export OUTLINE_API_TOKEN="ol_api_..."
77
+
78
+ # Self-hosted; either spelling of the URL works.
79
+ export OUTLINE_API_URL="https://outline.example.com"
80
+ ```
81
+
82
+ OAuth 2.0 access tokens work anywhere an API token does - both are sent as a bearer credential - but this package does not implement the authorization-code exchange that obtains one.
83
+
84
+ ### Timeouts and retries
85
+
86
+ Every request carries a timeout (default `(5, 60)` seconds for connect and read) so a stalled connection cannot hang the caller forever. Pass `timeout=` to override it (a single float, a `(connect, read)` tuple, or `None` to disable), and `retries=` to retry connection-establishment failures:
87
+
88
+ ```python
89
+ # Wait longer, and retry a dropped or stale connection up to 3 times.
90
+ client = OutlineClient(timeout=120, retries=3)
91
+ ```
92
+
93
+ `retries` retries only the connection stage, before any bytes reach the server, which is safe for the non-idempotent writes this client performs: a create whose response is merely lost is never resubmitted. The CLI reads `OUTLINE_API_TIMEOUT` (seconds) and `OUTLINE_API_RETRIES` (count) for the same behaviour.
94
+
95
+ ## Quick start
96
+
97
+ ### Python
98
+
99
+ ```python
100
+ from outline_client import OutlineClient
101
+
102
+ # Reads OUTLINE_API_URL / OUTLINE_API_TOKEN from the environment, or pass
103
+ # url= and token= explicitly.
104
+ with OutlineClient() as outline:
105
+ collection = outline.create_collection("Handbook", permission="read_write")
106
+
107
+ document = outline.create_document(
108
+ title="Onboarding",
109
+ text="# Welcome\n\nStart here.",
110
+ collection_id=str(collection.id),
111
+ publish=True,
112
+ )
113
+
114
+ for hit in outline.search_documents("onboarding"):
115
+ print(hit.ranking, hit.document.title, hit.context)
116
+
117
+ print(outline.export_document(str(document.id)))
118
+ ```
119
+
120
+ ### Python (async)
121
+
122
+ `AsyncOutlineClient` mirrors `OutlineClient` method for method, so independent
123
+ reads can be gathered rather than awaited one at a time:
124
+
125
+ ```python
126
+ import asyncio
127
+
128
+ from outline_client import AsyncOutlineClient
129
+
130
+
131
+ async def main() -> None:
132
+ async with AsyncOutlineClient() as outline:
133
+ documents, collections, users = await asyncio.gather(
134
+ outline.list_documents(limit=100),
135
+ outline.list_collections(),
136
+ outline.list_users(),
137
+ )
138
+ print(len(documents), len(collections), len(users))
139
+
140
+
141
+ asyncio.run(main())
142
+ ```
143
+
144
+ ### CLI
145
+
146
+ ```bash
147
+ # Every command prints indented JSON, so it pipes into jq unchanged.
148
+ outline auth info
149
+ outline collections list | jq -r '.[].name'
150
+ outline documents list --collection-id "$COLLECTION_ID" --limit 10
151
+
152
+ # Create a document from a file, then export it back out.
153
+ outline documents create --title "Onboarding" --text-file ./onboarding.md \
154
+ --collection-id "$COLLECTION_ID" --publish
155
+ outline documents export "$DOCUMENT_ID" > onboarding.md
156
+ outline documents export "$DOCUMENT_ID" --accept text/html -o onboarding.html
157
+
158
+ outline --help # every resource
159
+ outline documents --help # every method on one resource
160
+ ```
161
+
162
+ `OUTLINE_CLI_DISABLE` takes a comma-separated list of dotted command paths
163
+ (`documents.empty-trash,users.delete`) and hides them from `--help` and from
164
+ dispatch, so an embedded runtime can suppress the destructive ones.
165
+
166
+ ## Usage
167
+
168
+ ### Pagination
169
+
170
+ Outline's list methods take `offset` and `limit`, and report back the window
171
+ they served rather than a total. `paginate` walks the pages for any of them:
172
+
173
+ ```python
174
+ for user in outline.paginate(outline.list_users, limit=100):
175
+ print(user.email)
176
+
177
+ # On the async client it is an async iterator.
178
+ async for document in outline.paginate(outline.list_documents, limit=100):
179
+ print(document.title)
180
+ ```
181
+
182
+ ### Filters
183
+
184
+ The newer list and search methods take a structured filter expression,
185
+ evaluated as an `AND` of the top-level entries. Conditions and nested
186
+ `AND`/`OR` groups are both models:
187
+
188
+ ```python
189
+ from outline_client import DocumentFilterCondition, DocumentFilterGroup
190
+
191
+ recent_drafts = outline.list_documents(
192
+ filters=[
193
+ DocumentFilterCondition(
194
+ field="collectionId", operator="eq", value=collection_id
195
+ ),
196
+ DocumentFilterGroup(
197
+ operator="OR",
198
+ filters=[
199
+ DocumentFilterCondition(
200
+ field="title", operator="contains", value="draft"
201
+ ),
202
+ DocumentFilterCondition(field="updatedAt", operator="gte", value="P7D"),
203
+ ],
204
+ ),
205
+ ]
206
+ )
207
+ ```
208
+
209
+ ### Errors
210
+
211
+ A failed call raises a subclass of `OutlineAPIError` chosen by the HTTP status,
212
+ carrying Outline's own message and its machine-readable `error` identifier:
213
+
214
+ ```python
215
+ from outline_client import NotFoundError, RateLimitError
216
+
217
+ try:
218
+ document = outline.get_document(document_id)
219
+ except NotFoundError:
220
+ document = None
221
+ except RateLimitError as exc:
222
+ time.sleep(exc.retry_after or 60)
223
+ ```
224
+
225
+ | Exception | Status | Raised when |
226
+ | --- | --- | --- |
227
+ | `ValidationError` | 400 | The request failed one of Outline's validations. |
228
+ | `AuthenticationError` | 401 | The token is missing, malformed, or revoked. |
229
+ | `PaymentRequiredError` | 402 | The feature is not available on this installation. |
230
+ | `AuthorizationError` | 403 | The token is valid but not permitted this action. |
231
+ | `NotFoundError` | 404 | The record does not exist, or is not visible. |
232
+ | `RateLimitError` | 429 | Too many requests in the rate-limit window. |
233
+ | `ServerError` | 5xx | The request failed inside Outline. |
234
+
235
+ `OutlineConfigurationError` is raised before any request is made, when the URL
236
+ or token is missing.
237
+
238
+ ### Exports and other background jobs
239
+
240
+ Exporting a collection queues a job rather than returning a file. Poll it, then
241
+ download what it produced:
242
+
243
+ ```python
244
+ queued = outline.export_collection(collection_id, format="outline-markdown")
245
+ operation_id = str(queued.file_operation.id)
246
+
247
+ while outline.get_file_operation(operation_id).state in {"creating", "uploading"}:
248
+ time.sleep(1)
249
+
250
+ Path("handbook.zip").write_bytes(outline.download_file_operation(operation_id))
251
+ ```
252
+
253
+ ### The escape hatch
254
+
255
+ Client methods return the `data` a response carries. The `policies` and
256
+ `pagination` beside it, an explicit JSON `null`, and any method a release does
257
+ not yet cover are all reachable through `request`:
258
+
259
+ ```python
260
+ body = outline.request("documents.info", {"id": document_id})
261
+ print(body["policies"])
262
+ ```
263
+
264
+ ## Design
265
+
266
+ ### Generated schemas, hand-written methods
267
+
268
+ `src/outline_client/schemas/models.py` is generated from Outline's published
269
+ OpenAPI specification and should not be edited; `make schemas` regenerates it.
270
+ Everything else - the operations, the client methods, the CLI - is written by
271
+ hand, so argument names, defaults, and docstrings say what the method does
272
+ rather than what a generator guessed.
273
+
274
+ The generator's output is corrected in three documented ways, each asserted so
275
+ that a specification change fails the regeneration rather than passing
276
+ silently. See `scripts/generate_schemas.py`:
277
+
278
+ - **Widened types.** `format: uri` and `format: email` become `AnyUrl` and
279
+ `EmailStr`, which reject data Outline actually sends - an attachment's `url`
280
+ is the relative path `/api/attachments.redirect?id=...`. Both widen to `str`.
281
+ - **Renamed classes.** Anonymous sub-schemas are named after the property they
282
+ were found under and disambiguated with a counter, which yields `Operator1`
283
+ and `Field3`. Each is renamed to what it is, e.g. `DocumentFilterOperator`.
284
+ - **Specification corrections.** Places where the specification and the server
285
+ disagree, verified against a running Outline 1.10: `Permission` is missing
286
+ `admin`, and a group membership's `permission` is a role within the group
287
+ (`member`/`admin`), not an access level.
288
+
289
+ A few methods are corrected in the operations layer for the same reason -
290
+ `notifications.list` and `pins.list` are documented as returning an array but
291
+ answer with an object wrapping one, and `revisions.list` is documented as
292
+ taking an optional `documentId` that the server requires.
293
+
294
+ ### Unknown fields are kept
295
+
296
+ Outline ships response fields before the specification catches up, so models
297
+ allow extras rather than dropping them. Anything the models do not name is
298
+ still reachable:
299
+
300
+ ```python
301
+ document = outline.get_document(document_id)
302
+ print(document.__pydantic_extra__)
303
+ ```
304
+
305
+ ## Development
306
+
307
+ ```bash
308
+ make install # sync the locked environment
309
+ make schemas # regenerate the models from the OpenAPI specification
310
+ make check # ruff and mypy
311
+ make test # unit tests, against a mocked transport
312
+ make coverage # the same, with a coverage floor
313
+ ```
314
+
315
+ ### Integration tests
316
+
317
+ `make outline-up` starts a throwaway Outline 1.10.1 on
318
+ [http://localhost:8099](http://localhost:8099) with its own Postgres and Redis,
319
+ seeds a workspace, an admin, a second non-admin member, a baseline collection,
320
+ and an API token, then prints the two variables the suite reads:
321
+
322
+ ```bash
323
+ make outline-up
324
+ export OUTLINE_API_URL=http://localhost:8099
325
+ export OUTLINE_API_TOKEN=ol_api_outlineClientIntegrationTests000000001
326
+ make test-integration
327
+ make outline-down # stop it and delete its data
328
+ ```
329
+
330
+ The suite exercises the real request and response shapes, which is the only way
331
+ to catch the places where the published specification is wrong. Three methods
332
+ cannot be reached from a community-edition container - `dataAttributes.*` and
333
+ `documents.answerQuestion` are not in the open-source server at all, and
334
+ `apiKeys.create` refuses an API token as the caller - so the suite asserts that
335
+ each fails for that reason rather than skipping it.
336
+
337
+ Three things about the live server are worth knowing if you write more of these
338
+ tests. Outline caches each user's accessible-collection ids in Redis for ten
339
+ seconds and filters the search and list methods by that cached set, so a
340
+ document in a brand-new collection is briefly invisible to them; the suite's
341
+ `eventually` helper polls through that window. `documents.delete` refuses
342
+ `permanent=True` on a live document, so `discard` trashes it first. And
343
+ `collections.delete` refuses to remove a workspace's only collection, which is
344
+ why the seed creates a baseline one for the suite's own collection to sit
345
+ beside.
346
+
347
+ ## Reference
348
+
349
+ - [Outline API documentation](https://www.getoutline.com/developers)
350
+ - [Outline OpenAPI specification](https://github.com/outline/openapi)
351
+ - [Outline source](https://github.com/outline/outline)
352
+
353
+ ## License
354
+
355
+ MIT