plotwork 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.
- plotwork-0.1.0/.gitignore +164 -0
- plotwork-0.1.0/LICENSE +21 -0
- plotwork-0.1.0/PKG-INFO +141 -0
- plotwork-0.1.0/README.md +112 -0
- plotwork-0.1.0/pyproject.toml +55 -0
- plotwork-0.1.0/src/plotwork/README.md +21 -0
- plotwork-0.1.0/src/plotwork/__init__.py +90 -0
- plotwork-0.1.0/src/plotwork/_generated.py +2201 -0
- plotwork-0.1.0/src/plotwork/_request.py +187 -0
- plotwork-0.1.0/src/plotwork/_version.py +3 -0
- plotwork-0.1.0/src/plotwork/py.typed +0 -0
- plotwork-0.1.0/tests/__init__.py +0 -0
- plotwork-0.1.0/tests/conftest.py +90 -0
- plotwork-0.1.0/tests/test_generated.py +114 -0
- plotwork-0.1.0/tests/test_request.py +195 -0
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
# Logs
|
|
2
|
+
logs
|
|
3
|
+
*.log
|
|
4
|
+
npm-debug.log*
|
|
5
|
+
yarn-debug.log*
|
|
6
|
+
yarn-error.log*
|
|
7
|
+
lerna-debug.log*
|
|
8
|
+
|
|
9
|
+
# Diagnostic reports (https://nodejs.org/api/report.html)
|
|
10
|
+
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
|
|
11
|
+
|
|
12
|
+
# Runtime data
|
|
13
|
+
pids
|
|
14
|
+
*.pid
|
|
15
|
+
*.seed
|
|
16
|
+
*.pid.lock
|
|
17
|
+
|
|
18
|
+
# Directory for instrumented libs generated by jscoverage/JSCover
|
|
19
|
+
lib-cov
|
|
20
|
+
|
|
21
|
+
# Coverage directory used by tools like istanbul
|
|
22
|
+
coverage
|
|
23
|
+
*.lcov
|
|
24
|
+
|
|
25
|
+
# nyc test coverage
|
|
26
|
+
.nyc_output
|
|
27
|
+
|
|
28
|
+
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
|
|
29
|
+
.grunt
|
|
30
|
+
|
|
31
|
+
# Bower dependency directory (https://bower.io/)
|
|
32
|
+
bower_components
|
|
33
|
+
|
|
34
|
+
# node-waf configuration
|
|
35
|
+
.lock-wscript
|
|
36
|
+
|
|
37
|
+
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
|
38
|
+
build/Release
|
|
39
|
+
|
|
40
|
+
# Dependency directories
|
|
41
|
+
node_modules/
|
|
42
|
+
jspm_packages/
|
|
43
|
+
|
|
44
|
+
# Snowpack dependency directory (https://snowpack.dev/)
|
|
45
|
+
web_modules/
|
|
46
|
+
|
|
47
|
+
# TypeScript cache
|
|
48
|
+
*.tsbuildinfo
|
|
49
|
+
|
|
50
|
+
# Optional npm cache directory
|
|
51
|
+
.npm
|
|
52
|
+
|
|
53
|
+
# Optional eslint cache
|
|
54
|
+
.eslintcache
|
|
55
|
+
|
|
56
|
+
# Optional stylelint cache
|
|
57
|
+
.stylelintcache
|
|
58
|
+
|
|
59
|
+
# Optional REPL history
|
|
60
|
+
.node_repl_history
|
|
61
|
+
|
|
62
|
+
# Output of 'npm pack'
|
|
63
|
+
*.tgz
|
|
64
|
+
|
|
65
|
+
# Yarn Integrity file
|
|
66
|
+
.yarn-integrity
|
|
67
|
+
|
|
68
|
+
# dotenv environment variable files
|
|
69
|
+
.env
|
|
70
|
+
.env.*
|
|
71
|
+
!.env.example
|
|
72
|
+
|
|
73
|
+
# parcel-bundler cache (https://parceljs.org/)
|
|
74
|
+
.cache
|
|
75
|
+
.parcel-cache
|
|
76
|
+
|
|
77
|
+
# Next.js build output
|
|
78
|
+
.next
|
|
79
|
+
out
|
|
80
|
+
|
|
81
|
+
# Nuxt.js build / generate output
|
|
82
|
+
.nuxt
|
|
83
|
+
dist
|
|
84
|
+
.output
|
|
85
|
+
|
|
86
|
+
# Gatsby files
|
|
87
|
+
.cache/
|
|
88
|
+
# Comment in the public line in if your project uses Gatsby and not Next.js
|
|
89
|
+
# https://nextjs.org/blog/next-9-1#public-directory-support
|
|
90
|
+
# public
|
|
91
|
+
|
|
92
|
+
# vuepress build output
|
|
93
|
+
.vuepress/dist
|
|
94
|
+
|
|
95
|
+
# vuepress v2.x temp directory
|
|
96
|
+
.temp
|
|
97
|
+
|
|
98
|
+
# Sveltekit cache directory
|
|
99
|
+
.svelte-kit/
|
|
100
|
+
|
|
101
|
+
# vitepress build output
|
|
102
|
+
**/.vitepress/dist
|
|
103
|
+
|
|
104
|
+
# vitepress cache directory
|
|
105
|
+
**/.vitepress/cache
|
|
106
|
+
|
|
107
|
+
# Docusaurus cache and generated files
|
|
108
|
+
.docusaurus
|
|
109
|
+
|
|
110
|
+
# Serverless directories
|
|
111
|
+
.serverless/
|
|
112
|
+
|
|
113
|
+
# FuseBox cache
|
|
114
|
+
.fusebox/
|
|
115
|
+
|
|
116
|
+
# DynamoDB Local files
|
|
117
|
+
.dynamodb/
|
|
118
|
+
|
|
119
|
+
# Firebase cache directory
|
|
120
|
+
.firebase/
|
|
121
|
+
|
|
122
|
+
# TernJS port file
|
|
123
|
+
.tern-port
|
|
124
|
+
|
|
125
|
+
# Stores Visual Studio Code versions used for testing Visual Studio Code extensions
|
|
126
|
+
.vscode-test
|
|
127
|
+
|
|
128
|
+
# pnpm
|
|
129
|
+
.pnpm-store
|
|
130
|
+
|
|
131
|
+
# yarn v3
|
|
132
|
+
.pnp.*
|
|
133
|
+
.yarn/*
|
|
134
|
+
!.yarn/patches
|
|
135
|
+
!.yarn/plugins
|
|
136
|
+
!.yarn/releases
|
|
137
|
+
!.yarn/sdks
|
|
138
|
+
!.yarn/versions
|
|
139
|
+
|
|
140
|
+
# Vite files
|
|
141
|
+
vite.config.js.timestamp-*
|
|
142
|
+
vite.config.ts.timestamp-*
|
|
143
|
+
.vite/
|
|
144
|
+
|
|
145
|
+
# Astro generated types
|
|
146
|
+
.astro/
|
|
147
|
+
|
|
148
|
+
# Turbo Repo
|
|
149
|
+
.turbo
|
|
150
|
+
|
|
151
|
+
# SDK build output
|
|
152
|
+
dist/
|
|
153
|
+
dist-packs/
|
|
154
|
+
.claude/state/
|
|
155
|
+
.claude/settings.local.json
|
|
156
|
+
docs/film/out/
|
|
157
|
+
|
|
158
|
+
# Python
|
|
159
|
+
__pycache__/
|
|
160
|
+
*.py[cod]
|
|
161
|
+
.pytest_cache/
|
|
162
|
+
.mypy_cache/
|
|
163
|
+
.venv/
|
|
164
|
+
*.egg-info/
|
plotwork-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Plotwork
|
|
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.
|
plotwork-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: plotwork
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: The Plotwork API from Python: validate, draw, render, import and publish diagrams, on the standard library alone.
|
|
5
|
+
Project-URL: Homepage, https://plotwork.dev
|
|
6
|
+
Project-URL: Documentation, https://docs.plotwork.dev/sdks
|
|
7
|
+
Project-URL: Source, https://github.com/plotwork-official/plotwork-sdk
|
|
8
|
+
Project-URL: Issues, https://github.com/plotwork-official/plotwork-sdk/issues
|
|
9
|
+
Author: Plotwork
|
|
10
|
+
License-Expression: MIT
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
Keywords: api-client,architecture,diagrams,diagrams-as-code,plotwork,svg
|
|
13
|
+
Classifier: Development Status :: 4 - Beta
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: Operating System :: OS Independent
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
23
|
+
Classifier: Topic :: Documentation
|
|
24
|
+
Classifier: Topic :: Multimedia :: Graphics
|
|
25
|
+
Classifier: Topic :: Software Development :: Documentation
|
|
26
|
+
Classifier: Typing :: Typed
|
|
27
|
+
Requires-Python: >=3.10
|
|
28
|
+
Description-Content-Type: text/markdown
|
|
29
|
+
|
|
30
|
+
<p align="center">
|
|
31
|
+
<a href="https://plotwork.dev">
|
|
32
|
+
<picture>
|
|
33
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://plotwork.dev/brand/logo/plotwork-lockup-on-dark.svg">
|
|
34
|
+
<img alt="Plotwork" src="https://plotwork.dev/brand/logo/plotwork-lockup-on-light.svg" width="240">
|
|
35
|
+
</picture>
|
|
36
|
+
</a>
|
|
37
|
+
</p>
|
|
38
|
+
|
|
39
|
+
# plotwork
|
|
40
|
+
|
|
41
|
+
<p>
|
|
42
|
+
<a href="https://pypi.org/project/plotwork/"><img alt="PyPI" src="https://img.shields.io/pypi/v/plotwork?logo=pypi&logoColor=white&color=0f766e"></a>
|
|
43
|
+
<img alt="Python" src="https://img.shields.io/pypi/pyversions/plotwork?logo=python&logoColor=white&color=0f766e">
|
|
44
|
+
<a href="https://pypi.org/project/plotwork/#provenance"><img alt="Provenance" src="https://img.shields.io/badge/provenance-attested-0f766e?logo=sigstore&logoColor=white"></a>
|
|
45
|
+
<img alt="Runtime dependencies" src="https://img.shields.io/badge/runtime%20dependencies-0-0f766e?logo=dependabot&logoColor=white">
|
|
46
|
+
<img alt="Typed" src="https://img.shields.io/badge/types-generated%20from%20OpenAPI-3776ab?logo=python&logoColor=white">
|
|
47
|
+
</p>
|
|
48
|
+
|
|
49
|
+
The hosted Plotwork API from Python. Every `/v1` operation (validate, draw, render, import a file, publish, patterns, icons) is a typed method generated from the API's OpenAPI document, sent with `urllib` from the standard library alone. It runs on Python 3.10 and later.
|
|
50
|
+
|
|
51
|
+
## TL;DR
|
|
52
|
+
|
|
53
|
+
| Question | Answer |
|
|
54
|
+
|---|---|
|
|
55
|
+
| What does it install? | Nothing else. |
|
|
56
|
+
| Where do the types come from? | The API's OpenAPI document, kept in the SDK repository as [`spec/openapi.json`](https://github.com/plotwork-official/plotwork-sdk/blob/main/spec/openapi.json). Every request and answer is a `TypedDict`. |
|
|
57
|
+
| How do I sign in? | An API key from the Plotwork portal (`api_key`), or an OAuth access token (`access_token`). |
|
|
58
|
+
| Does a mistake in a diagram raise? | No. It is part of the answer, with a line, a column and a hint. Only a failed request raises, as `PlotworkApiError` with a stable `error_code`. |
|
|
59
|
+
| Does it retry? | A safe call is retried twice on 429 and 503, after the API's `Retry-After`. Publishing is never retried. |
|
|
60
|
+
| Is there a TypeScript client? | Yes, [`@plotwork.official/sdk`](https://www.npmjs.com/package/@plotwork.official/sdk), with the same calls in camelCase. |
|
|
61
|
+
|
|
62
|
+
## Install
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
pip install plotwork
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Use
|
|
69
|
+
|
|
70
|
+
```python
|
|
71
|
+
import os
|
|
72
|
+
|
|
73
|
+
from plotwork import Plotwork
|
|
74
|
+
|
|
75
|
+
plotwork = Plotwork(api_key=os.environ["PLOTWORK_API_KEY"])
|
|
76
|
+
|
|
77
|
+
source = 'flow "Checkout"\nnode web service "Web tier"\nnode api service "Orders API"\nweb -> api : "places order"\n'
|
|
78
|
+
|
|
79
|
+
checked = plotwork.diagrams.validate(source=source)
|
|
80
|
+
if not checked["valid"]:
|
|
81
|
+
for error in checked["errors"]:
|
|
82
|
+
print(error["line"], error["column"], error["message"], error.get("hint"))
|
|
83
|
+
|
|
84
|
+
published = plotwork.diagrams.publish(source=source, embedSource=True)
|
|
85
|
+
# A diagram an organisation's policy keeps private has no public link.
|
|
86
|
+
if "url" in published:
|
|
87
|
+
print(published["url"])
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
A method takes the request's fields as keyword arguments, named as the API names them (`embedSource`, `documentPath`), and returns the answer as a plain `dict` typed by a `TypedDict`. A body you already have as a `dict` is passed with `**body`. Keep the key in an environment variable or your CI's secret store, never in a file you commit.
|
|
91
|
+
|
|
92
|
+
| Group | Calls |
|
|
93
|
+
|---|---|
|
|
94
|
+
| `diagrams` | `validate`, `draw`, `render`, `outline`, `read`, `edit`, `compare`, `suggest`, `convert_mermaid`, `publish` |
|
|
95
|
+
| `import_source` | A diagram from Terraform, OpenAPI, SQL, Kubernetes, Compose and the other formats the API reads |
|
|
96
|
+
| `markdown` | `sync`, `plan` |
|
|
97
|
+
| `patterns` | `find`, `get`, `draw`, `check` |
|
|
98
|
+
| `icons` | `search`, `map` |
|
|
99
|
+
| `vocabulary` | The language's statements and limits, for a kind or a topic |
|
|
100
|
+
|
|
101
|
+
## Errors
|
|
102
|
+
|
|
103
|
+
```python
|
|
104
|
+
from plotwork import PlotworkApiError
|
|
105
|
+
|
|
106
|
+
try:
|
|
107
|
+
plotwork.diagrams.render(source=source)
|
|
108
|
+
except PlotworkApiError as error:
|
|
109
|
+
print(error.status, error.error_code, error.request_id)
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
| `error_code` | Means |
|
|
113
|
+
|---|---|
|
|
114
|
+
| `auth.missing`, `auth.invalid_key` | No key, or one the API does not accept |
|
|
115
|
+
| `rate_limit.exceeded` | Too many calls; already retried for a safe call |
|
|
116
|
+
| `http.<status>` | An answer that was not the API's error envelope, such as a proxy's page |
|
|
117
|
+
| `request.timeout`, `request.failed` | No answer came; `status` is 0 |
|
|
118
|
+
|
|
119
|
+
## Options
|
|
120
|
+
|
|
121
|
+
| Option | Default |
|
|
122
|
+
|---|---|
|
|
123
|
+
| `api_key` | none |
|
|
124
|
+
| `access_token` | none |
|
|
125
|
+
| `base_url` | `https://api.plotwork.dev` (`https://api-preview.plotwork.dev` for preview, or a self-hosted engine) |
|
|
126
|
+
| `timeout` | `60` seconds |
|
|
127
|
+
| `max_retries` | `2` |
|
|
128
|
+
| `opener` | `urllib.request.build_opener().open`; pass your own for a proxy or a test |
|
|
129
|
+
| `sleep` | `time.sleep`, the wait before a retry |
|
|
130
|
+
|
|
131
|
+
`plotwork.with_options(timeout=120)` gives a copy with another timeout or number of retries, for a slow call such as a large import.
|
|
132
|
+
|
|
133
|
+
## See also
|
|
134
|
+
|
|
135
|
+
| Page | Why |
|
|
136
|
+
|---|---|
|
|
137
|
+
| [SDKs guide](https://docs.plotwork.dev/sdks) | Every Plotwork SDK, and which to choose |
|
|
138
|
+
| [API reference](https://docs.plotwork.dev) | What each operation does |
|
|
139
|
+
| [TypeScript client](https://www.npmjs.com/package/@plotwork.official/sdk) | The same API from TypeScript |
|
|
140
|
+
| [Viewer](https://www.npmjs.com/package/@plotwork.official/viewer) | Show what you publish, interactively, in a web page |
|
|
141
|
+
| [Source](https://github.com/plotwork-official/plotwork-sdk/tree/main/python) | This package, its tests and its generator |
|
plotwork-0.1.0/README.md
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<a href="https://plotwork.dev">
|
|
3
|
+
<picture>
|
|
4
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://plotwork.dev/brand/logo/plotwork-lockup-on-dark.svg">
|
|
5
|
+
<img alt="Plotwork" src="https://plotwork.dev/brand/logo/plotwork-lockup-on-light.svg" width="240">
|
|
6
|
+
</picture>
|
|
7
|
+
</a>
|
|
8
|
+
</p>
|
|
9
|
+
|
|
10
|
+
# plotwork
|
|
11
|
+
|
|
12
|
+
<p>
|
|
13
|
+
<a href="https://pypi.org/project/plotwork/"><img alt="PyPI" src="https://img.shields.io/pypi/v/plotwork?logo=pypi&logoColor=white&color=0f766e"></a>
|
|
14
|
+
<img alt="Python" src="https://img.shields.io/pypi/pyversions/plotwork?logo=python&logoColor=white&color=0f766e">
|
|
15
|
+
<a href="https://pypi.org/project/plotwork/#provenance"><img alt="Provenance" src="https://img.shields.io/badge/provenance-attested-0f766e?logo=sigstore&logoColor=white"></a>
|
|
16
|
+
<img alt="Runtime dependencies" src="https://img.shields.io/badge/runtime%20dependencies-0-0f766e?logo=dependabot&logoColor=white">
|
|
17
|
+
<img alt="Typed" src="https://img.shields.io/badge/types-generated%20from%20OpenAPI-3776ab?logo=python&logoColor=white">
|
|
18
|
+
</p>
|
|
19
|
+
|
|
20
|
+
The hosted Plotwork API from Python. Every `/v1` operation (validate, draw, render, import a file, publish, patterns, icons) is a typed method generated from the API's OpenAPI document, sent with `urllib` from the standard library alone. It runs on Python 3.10 and later.
|
|
21
|
+
|
|
22
|
+
## TL;DR
|
|
23
|
+
|
|
24
|
+
| Question | Answer |
|
|
25
|
+
|---|---|
|
|
26
|
+
| What does it install? | Nothing else. |
|
|
27
|
+
| Where do the types come from? | The API's OpenAPI document, kept in the SDK repository as [`spec/openapi.json`](https://github.com/plotwork-official/plotwork-sdk/blob/main/spec/openapi.json). Every request and answer is a `TypedDict`. |
|
|
28
|
+
| How do I sign in? | An API key from the Plotwork portal (`api_key`), or an OAuth access token (`access_token`). |
|
|
29
|
+
| Does a mistake in a diagram raise? | No. It is part of the answer, with a line, a column and a hint. Only a failed request raises, as `PlotworkApiError` with a stable `error_code`. |
|
|
30
|
+
| Does it retry? | A safe call is retried twice on 429 and 503, after the API's `Retry-After`. Publishing is never retried. |
|
|
31
|
+
| Is there a TypeScript client? | Yes, [`@plotwork.official/sdk`](https://www.npmjs.com/package/@plotwork.official/sdk), with the same calls in camelCase. |
|
|
32
|
+
|
|
33
|
+
## Install
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
pip install plotwork
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Use
|
|
40
|
+
|
|
41
|
+
```python
|
|
42
|
+
import os
|
|
43
|
+
|
|
44
|
+
from plotwork import Plotwork
|
|
45
|
+
|
|
46
|
+
plotwork = Plotwork(api_key=os.environ["PLOTWORK_API_KEY"])
|
|
47
|
+
|
|
48
|
+
source = 'flow "Checkout"\nnode web service "Web tier"\nnode api service "Orders API"\nweb -> api : "places order"\n'
|
|
49
|
+
|
|
50
|
+
checked = plotwork.diagrams.validate(source=source)
|
|
51
|
+
if not checked["valid"]:
|
|
52
|
+
for error in checked["errors"]:
|
|
53
|
+
print(error["line"], error["column"], error["message"], error.get("hint"))
|
|
54
|
+
|
|
55
|
+
published = plotwork.diagrams.publish(source=source, embedSource=True)
|
|
56
|
+
# A diagram an organisation's policy keeps private has no public link.
|
|
57
|
+
if "url" in published:
|
|
58
|
+
print(published["url"])
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
A method takes the request's fields as keyword arguments, named as the API names them (`embedSource`, `documentPath`), and returns the answer as a plain `dict` typed by a `TypedDict`. A body you already have as a `dict` is passed with `**body`. Keep the key in an environment variable or your CI's secret store, never in a file you commit.
|
|
62
|
+
|
|
63
|
+
| Group | Calls |
|
|
64
|
+
|---|---|
|
|
65
|
+
| `diagrams` | `validate`, `draw`, `render`, `outline`, `read`, `edit`, `compare`, `suggest`, `convert_mermaid`, `publish` |
|
|
66
|
+
| `import_source` | A diagram from Terraform, OpenAPI, SQL, Kubernetes, Compose and the other formats the API reads |
|
|
67
|
+
| `markdown` | `sync`, `plan` |
|
|
68
|
+
| `patterns` | `find`, `get`, `draw`, `check` |
|
|
69
|
+
| `icons` | `search`, `map` |
|
|
70
|
+
| `vocabulary` | The language's statements and limits, for a kind or a topic |
|
|
71
|
+
|
|
72
|
+
## Errors
|
|
73
|
+
|
|
74
|
+
```python
|
|
75
|
+
from plotwork import PlotworkApiError
|
|
76
|
+
|
|
77
|
+
try:
|
|
78
|
+
plotwork.diagrams.render(source=source)
|
|
79
|
+
except PlotworkApiError as error:
|
|
80
|
+
print(error.status, error.error_code, error.request_id)
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
| `error_code` | Means |
|
|
84
|
+
|---|---|
|
|
85
|
+
| `auth.missing`, `auth.invalid_key` | No key, or one the API does not accept |
|
|
86
|
+
| `rate_limit.exceeded` | Too many calls; already retried for a safe call |
|
|
87
|
+
| `http.<status>` | An answer that was not the API's error envelope, such as a proxy's page |
|
|
88
|
+
| `request.timeout`, `request.failed` | No answer came; `status` is 0 |
|
|
89
|
+
|
|
90
|
+
## Options
|
|
91
|
+
|
|
92
|
+
| Option | Default |
|
|
93
|
+
|---|---|
|
|
94
|
+
| `api_key` | none |
|
|
95
|
+
| `access_token` | none |
|
|
96
|
+
| `base_url` | `https://api.plotwork.dev` (`https://api-preview.plotwork.dev` for preview, or a self-hosted engine) |
|
|
97
|
+
| `timeout` | `60` seconds |
|
|
98
|
+
| `max_retries` | `2` |
|
|
99
|
+
| `opener` | `urllib.request.build_opener().open`; pass your own for a proxy or a test |
|
|
100
|
+
| `sleep` | `time.sleep`, the wait before a retry |
|
|
101
|
+
|
|
102
|
+
`plotwork.with_options(timeout=120)` gives a copy with another timeout or number of retries, for a slow call such as a large import.
|
|
103
|
+
|
|
104
|
+
## See also
|
|
105
|
+
|
|
106
|
+
| Page | Why |
|
|
107
|
+
|---|---|
|
|
108
|
+
| [SDKs guide](https://docs.plotwork.dev/sdks) | Every Plotwork SDK, and which to choose |
|
|
109
|
+
| [API reference](https://docs.plotwork.dev) | What each operation does |
|
|
110
|
+
| [TypeScript client](https://www.npmjs.com/package/@plotwork.official/sdk) | The same API from TypeScript |
|
|
111
|
+
| [Viewer](https://www.npmjs.com/package/@plotwork.official/viewer) | Show what you publish, interactively, in a web page |
|
|
112
|
+
| [Source](https://github.com/plotwork-official/plotwork-sdk/tree/main/python) | This package, its tests and its generator |
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling==1.33.0"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "plotwork"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "The Plotwork API from Python: validate, draw, render, import and publish diagrams, on the standard library alone."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.10"
|
|
11
|
+
license = "MIT"
|
|
12
|
+
license-files = ["LICENSE"]
|
|
13
|
+
authors = [{ name = "Plotwork" }]
|
|
14
|
+
keywords = ["plotwork", "diagrams", "diagrams-as-code", "architecture", "svg", "api-client"]
|
|
15
|
+
classifiers = [
|
|
16
|
+
"Development Status :: 4 - Beta",
|
|
17
|
+
"Intended Audience :: Developers",
|
|
18
|
+
"Operating System :: OS Independent",
|
|
19
|
+
"Programming Language :: Python :: 3",
|
|
20
|
+
"Programming Language :: Python :: 3 :: Only",
|
|
21
|
+
"Programming Language :: Python :: 3.10",
|
|
22
|
+
"Programming Language :: Python :: 3.11",
|
|
23
|
+
"Programming Language :: Python :: 3.12",
|
|
24
|
+
"Programming Language :: Python :: 3.13",
|
|
25
|
+
"Programming Language :: Python :: 3.14",
|
|
26
|
+
"Topic :: Documentation",
|
|
27
|
+
"Topic :: Multimedia :: Graphics",
|
|
28
|
+
"Topic :: Software Development :: Documentation",
|
|
29
|
+
"Typing :: Typed",
|
|
30
|
+
]
|
|
31
|
+
# No runtime dependencies: scripts/check-no-runtime-dependencies.mjs fails if this list gains a name.
|
|
32
|
+
dependencies = []
|
|
33
|
+
|
|
34
|
+
[project.urls]
|
|
35
|
+
Homepage = "https://plotwork.dev"
|
|
36
|
+
Documentation = "https://docs.plotwork.dev/sdks"
|
|
37
|
+
Source = "https://github.com/plotwork-official/plotwork-sdk"
|
|
38
|
+
Issues = "https://github.com/plotwork-official/plotwork-sdk/issues"
|
|
39
|
+
|
|
40
|
+
[dependency-groups]
|
|
41
|
+
# What CI installs: the tests, the build, and a strict type check of the generated types.
|
|
42
|
+
dev = ["pytest==9.2.0", "build==1.6.1", "mypy==2.4.1"]
|
|
43
|
+
|
|
44
|
+
[tool.hatch.build.targets.wheel]
|
|
45
|
+
packages = ["src/plotwork"]
|
|
46
|
+
exclude = ["src/plotwork/README.md"]
|
|
47
|
+
|
|
48
|
+
[tool.hatch.build.targets.sdist]
|
|
49
|
+
include = ["src/plotwork", "tests", "README.md", "LICENSE", "pyproject.toml"]
|
|
50
|
+
|
|
51
|
+
[tool.pytest.ini_options]
|
|
52
|
+
testpaths = ["tests"]
|
|
53
|
+
pythonpath = ["src"]
|
|
54
|
+
addopts = "-ra"
|
|
55
|
+
filterwarnings = ["error"]
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# Python client source
|
|
2
|
+
|
|
3
|
+
The typed client for the Plotwork API: one transport on `urllib.request`, and the operations generated from `spec/openapi.json`.
|
|
4
|
+
|
|
5
|
+
## Standards
|
|
6
|
+
|
|
7
|
+
Code here follows:
|
|
8
|
+
|
|
9
|
+
- [API clients](../../../.standards/docs/standards/core/api-clients.md) - one transport, typed errors, a timeout, retries only for calls that are safe to send twice
|
|
10
|
+
- [Dependencies](../../../.standards/docs/standards/core/dependencies.md) - nothing is imported but the standard library
|
|
11
|
+
- [Error handling](../../../.standards/docs/standards/core/error-handling.md) - a diagram's mistakes are data in the answer; only a failed request raises
|
|
12
|
+
|
|
13
|
+
## Contents
|
|
14
|
+
|
|
15
|
+
| Path | Purpose |
|
|
16
|
+
|---|---|
|
|
17
|
+
| `__init__.py` | `Plotwork`, the client: the key or token, the base address, `with_options`, and the generated operations on it. |
|
|
18
|
+
| `_request.py` | `Transport`: sends one request, reads the answer, retries 429 and 503 for safe calls, and turns the API's error envelope into `PlotworkApiError`. |
|
|
19
|
+
| `_generated.py` | Every schema as a `TypedDict` and every operation as a typed method, written by `pnpm gen:python`. Never edited by hand; `pnpm check` fails when it is stale. |
|
|
20
|
+
| `_version.py` | `__version__`; a test holds it equal to `pyproject.toml`. |
|
|
21
|
+
| `py.typed` | Tells type checkers the package carries its own types. |
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
"""``plotwork``: the hosted Plotwork API from Python, on the standard library alone.
|
|
2
|
+
|
|
3
|
+
Every ``/v1`` operation is a typed method generated from ``spec/openapi.json``::
|
|
4
|
+
|
|
5
|
+
import os
|
|
6
|
+
from plotwork import Plotwork
|
|
7
|
+
|
|
8
|
+
plotwork = Plotwork(api_key=os.environ["PLOTWORK_API_KEY"])
|
|
9
|
+
checked = plotwork.diagrams.validate(source=source)
|
|
10
|
+
published = plotwork.diagrams.publish(source=source, alias="checkout-flow")
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from __future__ import annotations
|
|
14
|
+
|
|
15
|
+
from typing import Any, Callable, Dict, Optional
|
|
16
|
+
|
|
17
|
+
from ._generated import OPERATION_PATHS, Operations
|
|
18
|
+
from ._request import Opener, PlotworkApiError, Transport, retry_delay
|
|
19
|
+
from ._version import __version__
|
|
20
|
+
|
|
21
|
+
__all__ = ["DEFAULT_BASE_URL", "OPERATION_PATHS", "Plotwork", "PlotworkApiError", "Transport", "__version__", "retry_delay"]
|
|
22
|
+
|
|
23
|
+
#: The production API.
|
|
24
|
+
DEFAULT_BASE_URL = "https://api.plotwork.dev"
|
|
25
|
+
|
|
26
|
+
_UNSET: Any = object()
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class Plotwork(Operations):
|
|
30
|
+
"""The Plotwork API client.
|
|
31
|
+
|
|
32
|
+
:param api_key: An account or organisation API key, sent as ``X-API-Key``. Keep it in an environment variable or a secret store.
|
|
33
|
+
:param access_token: An OAuth access token, sent as ``Authorization: Bearer``, in place of a key.
|
|
34
|
+
:param base_url: The API's address: production by default, ``https://api-preview.plotwork.dev`` for preview, or a self-hosted engine.
|
|
35
|
+
:param timeout: Seconds before a call counts as failed: 60 by default.
|
|
36
|
+
:param max_retries: How many times a safe call is tried again on 429 or 503: 2 by default, 0 to never retry.
|
|
37
|
+
:param opener: Opens each request, called like ``urllib.request.urlopen``; a proxy or a test passes its own.
|
|
38
|
+
:param sleep: Waits the given seconds before a retry; ``time.sleep`` by default.
|
|
39
|
+
"""
|
|
40
|
+
|
|
41
|
+
def __init__(
|
|
42
|
+
self,
|
|
43
|
+
*,
|
|
44
|
+
api_key: Optional[str] = None,
|
|
45
|
+
access_token: Optional[str] = None,
|
|
46
|
+
base_url: Optional[str] = None,
|
|
47
|
+
timeout: float = 60.0,
|
|
48
|
+
max_retries: int = 2,
|
|
49
|
+
opener: Optional[Opener] = None,
|
|
50
|
+
sleep: Optional[Callable[[float], Any]] = None,
|
|
51
|
+
) -> None:
|
|
52
|
+
headers: Dict[str, str] = {}
|
|
53
|
+
if api_key:
|
|
54
|
+
headers["X-API-Key"] = api_key
|
|
55
|
+
if access_token:
|
|
56
|
+
headers["Authorization"] = f"Bearer {access_token}"
|
|
57
|
+
self._options: Dict[str, Any] = {
|
|
58
|
+
"api_key": api_key,
|
|
59
|
+
"access_token": access_token,
|
|
60
|
+
"base_url": base_url,
|
|
61
|
+
"timeout": timeout,
|
|
62
|
+
"max_retries": max_retries,
|
|
63
|
+
"opener": opener,
|
|
64
|
+
"sleep": sleep,
|
|
65
|
+
}
|
|
66
|
+
super().__init__(
|
|
67
|
+
Transport(
|
|
68
|
+
base_url=base_url or DEFAULT_BASE_URL,
|
|
69
|
+
headers=headers,
|
|
70
|
+
timeout=timeout,
|
|
71
|
+
max_retries=max_retries,
|
|
72
|
+
opener=opener,
|
|
73
|
+
sleep=sleep,
|
|
74
|
+
)
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
def with_options(self, *, timeout: float = _UNSET, max_retries: int = _UNSET) -> "Plotwork":
|
|
78
|
+
"""A copy of this client with another timeout or number of retries, for one call or a few:
|
|
79
|
+
|
|
80
|
+
``plotwork.with_options(timeout=120).import_source(format="terraform", text=text)``
|
|
81
|
+
"""
|
|
82
|
+
options = dict(self._options)
|
|
83
|
+
if timeout is not _UNSET:
|
|
84
|
+
options["timeout"] = timeout
|
|
85
|
+
if max_retries is not _UNSET:
|
|
86
|
+
options["max_retries"] = max_retries
|
|
87
|
+
return Plotwork(**options)
|
|
88
|
+
|
|
89
|
+
def __repr__(self) -> str:
|
|
90
|
+
return f"Plotwork(base_url={self._transport.base_url!r})"
|