servatus 0.0.1__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.
- servatus-0.0.1/.github/workflows/ci.yml +31 -0
- servatus-0.0.1/.github/workflows/publish.yml +22 -0
- servatus-0.0.1/.gitignore +8 -0
- servatus-0.0.1/AGENTS.md +10 -0
- servatus-0.0.1/CONTRIBUTING.md +19 -0
- servatus-0.0.1/LICENSE +21 -0
- servatus-0.0.1/PKG-INFO +99 -0
- servatus-0.0.1/README.md +78 -0
- servatus-0.0.1/SECURITY.md +11 -0
- servatus-0.0.1/docs/CONTEXT.md +13 -0
- servatus-0.0.1/docs/adr/0001-opaque-application-seam.md +10 -0
- servatus-0.0.1/docs/adr/0002-posix-workspace-publication.md +15 -0
- servatus-0.0.1/docs/adr/README.md +4 -0
- servatus-0.0.1/docs/agents/issue-tracker.md +5 -0
- servatus-0.0.1/pyproject.toml +58 -0
- servatus-0.0.1/src/servatus/__init__.py +26 -0
- servatus-0.0.1/src/servatus/_errors.py +30 -0
- servatus-0.0.1/src/servatus/_posix.py +316 -0
- servatus-0.0.1/src/servatus/_workspace.py +306 -0
- servatus-0.0.1/src/servatus/py.typed +1 -0
- servatus-0.0.1/tests/test_workspace.py +498 -0
- servatus-0.0.1/uv.lock +152 -0
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
pull_request:
|
|
6
|
+
|
|
7
|
+
permissions:
|
|
8
|
+
contents: read
|
|
9
|
+
|
|
10
|
+
jobs:
|
|
11
|
+
verify:
|
|
12
|
+
strategy:
|
|
13
|
+
matrix:
|
|
14
|
+
os: [ubuntu-latest, macos-latest]
|
|
15
|
+
runs-on: ${{ matrix.os }}
|
|
16
|
+
steps:
|
|
17
|
+
- uses: actions/checkout@v4
|
|
18
|
+
- uses: astral-sh/setup-uv@v6
|
|
19
|
+
with:
|
|
20
|
+
enable-cache: true
|
|
21
|
+
- uses: actions/setup-python@v5
|
|
22
|
+
with:
|
|
23
|
+
python-version: "3.11"
|
|
24
|
+
- run: uv sync --locked
|
|
25
|
+
- run: uv run pytest
|
|
26
|
+
- run: uv run ruff check .
|
|
27
|
+
- run: uv run ruff format --check .
|
|
28
|
+
- run: uv run pyright
|
|
29
|
+
- run: uv run vulture
|
|
30
|
+
- run: uv build
|
|
31
|
+
- run: uv run --isolated --no-project --with dist/*.whl python -c "import servatus"
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
name: Publish
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
workflow_dispatch:
|
|
5
|
+
release:
|
|
6
|
+
types: [published]
|
|
7
|
+
|
|
8
|
+
permissions:
|
|
9
|
+
contents: read
|
|
10
|
+
|
|
11
|
+
jobs:
|
|
12
|
+
pypi:
|
|
13
|
+
runs-on: ubuntu-latest
|
|
14
|
+
environment: pypi
|
|
15
|
+
permissions:
|
|
16
|
+
contents: read
|
|
17
|
+
id-token: write
|
|
18
|
+
steps:
|
|
19
|
+
- uses: actions/checkout@v4
|
|
20
|
+
- uses: astral-sh/setup-uv@v6
|
|
21
|
+
- run: uv build
|
|
22
|
+
- uses: pypa/gh-action-pypi-publish@release/v1
|
servatus-0.0.1/AGENTS.md
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# Agent guidance
|
|
2
|
+
|
|
3
|
+
Servatus favors small, deep interfaces and ordinary typed Python. Keep application meaning outside
|
|
4
|
+
the package, reject unsafe filesystem behavior, and prefer clean breaks over compatibility layers.
|
|
5
|
+
|
|
6
|
+
Use synthetic temporary directories for tests. Never contact SSH, Slurm, Apptainer, external
|
|
7
|
+
storage, or an application's real outputs from the test suite.
|
|
8
|
+
|
|
9
|
+
Run pytest, Ruff, Pyright, Vulture, package builds, and an installed-artifact smoke before handing
|
|
10
|
+
off a change.
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# Contributing
|
|
2
|
+
|
|
3
|
+
Servatus keeps its public surface deliberately small. Changes should solve a demonstrated lifecycle
|
|
4
|
+
problem without importing application schemas, workflow topology, or backend plugin machinery.
|
|
5
|
+
|
|
6
|
+
Set up and verify the repository with:
|
|
7
|
+
|
|
8
|
+
```sh
|
|
9
|
+
uv sync --locked
|
|
10
|
+
uv run pytest
|
|
11
|
+
uv run ruff check .
|
|
12
|
+
uv run ruff format --check .
|
|
13
|
+
uv run pyright
|
|
14
|
+
uv run vulture
|
|
15
|
+
uv build
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Tests must use synthetic temporary directories. Pull requests must not depend on a live scheduler,
|
|
19
|
+
cluster, container runtime, or external data store.
|
servatus-0.0.1/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Edoardo Galli
|
|
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.
|
servatus-0.0.1/PKG-INFO
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: servatus
|
|
3
|
+
Version: 0.0.1
|
|
4
|
+
Summary: Run resumable work through Slurm and atomically publish validated outputs.
|
|
5
|
+
Project-URL: Repository, https://github.com/edoski/servatus
|
|
6
|
+
Project-URL: Issues, https://github.com/edoski/servatus/issues
|
|
7
|
+
Author: Edoardo Galli
|
|
8
|
+
License-Expression: MIT
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Classifier: Development Status :: 2 - Pre-Alpha
|
|
11
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
12
|
+
Classifier: Operating System :: MacOS
|
|
13
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
18
|
+
Classifier: Typing :: Typed
|
|
19
|
+
Requires-Python: >=3.11
|
|
20
|
+
Description-Content-Type: text/markdown
|
|
21
|
+
|
|
22
|
+
# Servatus
|
|
23
|
+
|
|
24
|
+
Run resumable work through Slurm and atomically publish validated outputs.
|
|
25
|
+
|
|
26
|
+
Servatus 0.0.1 is a publication-only alpha. It provides a small Python interface for keeping
|
|
27
|
+
private resumable work and exposing an application-built directory atomically. Slurm campaigns
|
|
28
|
+
arrive in a later release.
|
|
29
|
+
|
|
30
|
+
```sh
|
|
31
|
+
pip install servatus
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Publication
|
|
35
|
+
|
|
36
|
+
Use `publish` when failed work is disposable:
|
|
37
|
+
|
|
38
|
+
```python
|
|
39
|
+
from pathlib import Path
|
|
40
|
+
|
|
41
|
+
from servatus import Draft, publish
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def build(draft: Draft) -> None:
|
|
45
|
+
(draft.path / "result.json").write_text('{"status":"complete"}\n')
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
publication = publish(Path("outputs/run-1"), build)
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Use `Workspace` when a worker must retain private checkpoints across restarts:
|
|
52
|
+
|
|
53
|
+
```python
|
|
54
|
+
from servatus import Draft, Workspace
|
|
55
|
+
|
|
56
|
+
destination = Path("outputs/model-1")
|
|
57
|
+
with Workspace(destination, identity=b"model request bytes") as workspace:
|
|
58
|
+
checkpoint = workspace.path / "last.ckpt"
|
|
59
|
+
# The application creates or resumes its own checkpoint here.
|
|
60
|
+
|
|
61
|
+
def assemble(draft: Draft) -> None:
|
|
62
|
+
draft.link(checkpoint, "last.ckpt")
|
|
63
|
+
# Perform application validation before returning.
|
|
64
|
+
|
|
65
|
+
publication = workspace.publish(assemble)
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
`Workspace` binds its stable hidden state to the SHA-256 digest of the opaque identity and holds a
|
|
69
|
+
nonblocking writer lock. `Draft.link` only hard-links regular files into a safe relative path. The
|
|
70
|
+
application must not mutate a linked source inode after `Draft.link()` returns and before
|
|
71
|
+
publication completes. It owns file contents, validation, schemas, and completion meaning.
|
|
72
|
+
|
|
73
|
+
## Guarantees
|
|
74
|
+
|
|
75
|
+
- A destination is absent or one complete directory; it is never overwritten.
|
|
76
|
+
- Work, hard-link sources, stages, and destination must share a filesystem.
|
|
77
|
+
- Files and directories are synced before a kernel-exclusive commit; the destination parent is
|
|
78
|
+
synced afterward.
|
|
79
|
+
- Builder failures expose no destination. Resumable work remains available, while disposable
|
|
80
|
+
stages are removed.
|
|
81
|
+
- Successful workspace publication removes private state. A cleanup failure returns
|
|
82
|
+
`Publication(cleanup_pending=True)` without misreporting the committed destination as failed.
|
|
83
|
+
- Symlinks, special files, escaping link paths, path substitution, and unsupported exclusive-rename
|
|
84
|
+
primitives fail closed.
|
|
85
|
+
|
|
86
|
+
Servatus supports POSIX filesystems on Linux and macOS. Hardware durability still depends on the
|
|
87
|
+
filesystem and mount. It is not a security boundary against another process that can arbitrarily
|
|
88
|
+
modify the same parent directory.
|
|
89
|
+
|
|
90
|
+
## Non-goals in 0.0.1
|
|
91
|
+
|
|
92
|
+
Servatus does not interpret checkpoints or ML artifacts, decide when work is valid, model workflow
|
|
93
|
+
graphs, migrate old outputs, copy across filesystems, overwrite destinations, or provide scheduler
|
|
94
|
+
execution. It has no plugins, callbacks beyond the one build seam, runtime dependencies, daemon,
|
|
95
|
+
database, or global run store.
|
|
96
|
+
|
|
97
|
+
The public API is `Draft`, `Workspace`, `Publication`, `publish`, and the compact errors exported by
|
|
98
|
+
`servatus`. See [the context glossary](docs/CONTEXT.md) and [architecture decisions](docs/adr/README.md)
|
|
99
|
+
for the ownership boundary.
|
servatus-0.0.1/README.md
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# Servatus
|
|
2
|
+
|
|
3
|
+
Run resumable work through Slurm and atomically publish validated outputs.
|
|
4
|
+
|
|
5
|
+
Servatus 0.0.1 is a publication-only alpha. It provides a small Python interface for keeping
|
|
6
|
+
private resumable work and exposing an application-built directory atomically. Slurm campaigns
|
|
7
|
+
arrive in a later release.
|
|
8
|
+
|
|
9
|
+
```sh
|
|
10
|
+
pip install servatus
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Publication
|
|
14
|
+
|
|
15
|
+
Use `publish` when failed work is disposable:
|
|
16
|
+
|
|
17
|
+
```python
|
|
18
|
+
from pathlib import Path
|
|
19
|
+
|
|
20
|
+
from servatus import Draft, publish
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def build(draft: Draft) -> None:
|
|
24
|
+
(draft.path / "result.json").write_text('{"status":"complete"}\n')
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
publication = publish(Path("outputs/run-1"), build)
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Use `Workspace` when a worker must retain private checkpoints across restarts:
|
|
31
|
+
|
|
32
|
+
```python
|
|
33
|
+
from servatus import Draft, Workspace
|
|
34
|
+
|
|
35
|
+
destination = Path("outputs/model-1")
|
|
36
|
+
with Workspace(destination, identity=b"model request bytes") as workspace:
|
|
37
|
+
checkpoint = workspace.path / "last.ckpt"
|
|
38
|
+
# The application creates or resumes its own checkpoint here.
|
|
39
|
+
|
|
40
|
+
def assemble(draft: Draft) -> None:
|
|
41
|
+
draft.link(checkpoint, "last.ckpt")
|
|
42
|
+
# Perform application validation before returning.
|
|
43
|
+
|
|
44
|
+
publication = workspace.publish(assemble)
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
`Workspace` binds its stable hidden state to the SHA-256 digest of the opaque identity and holds a
|
|
48
|
+
nonblocking writer lock. `Draft.link` only hard-links regular files into a safe relative path. The
|
|
49
|
+
application must not mutate a linked source inode after `Draft.link()` returns and before
|
|
50
|
+
publication completes. It owns file contents, validation, schemas, and completion meaning.
|
|
51
|
+
|
|
52
|
+
## Guarantees
|
|
53
|
+
|
|
54
|
+
- A destination is absent or one complete directory; it is never overwritten.
|
|
55
|
+
- Work, hard-link sources, stages, and destination must share a filesystem.
|
|
56
|
+
- Files and directories are synced before a kernel-exclusive commit; the destination parent is
|
|
57
|
+
synced afterward.
|
|
58
|
+
- Builder failures expose no destination. Resumable work remains available, while disposable
|
|
59
|
+
stages are removed.
|
|
60
|
+
- Successful workspace publication removes private state. A cleanup failure returns
|
|
61
|
+
`Publication(cleanup_pending=True)` without misreporting the committed destination as failed.
|
|
62
|
+
- Symlinks, special files, escaping link paths, path substitution, and unsupported exclusive-rename
|
|
63
|
+
primitives fail closed.
|
|
64
|
+
|
|
65
|
+
Servatus supports POSIX filesystems on Linux and macOS. Hardware durability still depends on the
|
|
66
|
+
filesystem and mount. It is not a security boundary against another process that can arbitrarily
|
|
67
|
+
modify the same parent directory.
|
|
68
|
+
|
|
69
|
+
## Non-goals in 0.0.1
|
|
70
|
+
|
|
71
|
+
Servatus does not interpret checkpoints or ML artifacts, decide when work is valid, model workflow
|
|
72
|
+
graphs, migrate old outputs, copy across filesystems, overwrite destinations, or provide scheduler
|
|
73
|
+
execution. It has no plugins, callbacks beyond the one build seam, runtime dependencies, daemon,
|
|
74
|
+
database, or global run store.
|
|
75
|
+
|
|
76
|
+
The public API is `Draft`, `Workspace`, `Publication`, `publish`, and the compact errors exported by
|
|
77
|
+
`servatus`. See [the context glossary](docs/CONTEXT.md) and [architecture decisions](docs/adr/README.md)
|
|
78
|
+
for the ownership boundary.
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# Security policy
|
|
2
|
+
|
|
3
|
+
Please report vulnerabilities privately through GitHub's security-advisory form for this
|
|
4
|
+
repository. Do not include sensitive paths, credentials, or research data in a public issue.
|
|
5
|
+
|
|
6
|
+
Only the latest released version receives security fixes.
|
|
7
|
+
|
|
8
|
+
Servatus is an unprivileged user library, not an authorization, sandboxing, tenant-isolation, or
|
|
9
|
+
cluster-policy layer. Its publication transaction protects against accidental partial visibility,
|
|
10
|
+
overwrites, and ordinary lifecycle races. Callers remain responsible for directory permissions,
|
|
11
|
+
trusted builders, application validation, filesystem guarantees, and scheduler policy.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# Servatus context
|
|
2
|
+
|
|
3
|
+
Servatus uses a small generic vocabulary:
|
|
4
|
+
|
|
5
|
+
- **Destination:** the application-owned canonical path. It is immutable once published.
|
|
6
|
+
- **Workspace:** stable, identity-bound private state retained when resumable work fails.
|
|
7
|
+
- **Identity:** opaque application bytes whose digest binds a workspace to one logical request.
|
|
8
|
+
- **Draft:** one unique, disposable directory assembled before publication.
|
|
9
|
+
- **Publication:** the committed destination plus whether private cleanup remains pending.
|
|
10
|
+
- **Builder:** the application callback that writes and validates a draft before returning.
|
|
11
|
+
|
|
12
|
+
Servatus owns lifecycle mechanics, not application meaning. Checkpoints, manifests, schemas,
|
|
13
|
+
validation rules, task topology, and scientific completion remain with the calling project.
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# ADR 0001: Keep application meaning opaque
|
|
2
|
+
|
|
3
|
+
Status: accepted
|
|
4
|
+
|
|
5
|
+
Servatus accepts opaque identity bytes and one application-owned builder callback. The callback
|
|
6
|
+
writes the exact destination tree and performs domain validation before returning.
|
|
7
|
+
|
|
8
|
+
Servatus does not receive artifact schemas, validators, checkpoint formats, completion enums, or
|
|
9
|
+
workflow topology. This keeps the lifecycle reusable without becoming an ML framework or moving
|
|
10
|
+
scientific authority away from the calling project.
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# ADR 0002: Publish through a durable POSIX transaction
|
|
2
|
+
|
|
3
|
+
Status: accepted
|
|
4
|
+
|
|
5
|
+
Servatus builds in a unique destination-adjacent stage, rejects unsafe entries, recursively syncs
|
|
6
|
+
content, and atomically renames the directory into an absent destination with the platform's
|
|
7
|
+
no-replace primitive. It then syncs the destination parent.
|
|
8
|
+
|
|
9
|
+
Linux uses `renameat2(RENAME_NOREPLACE)` and macOS uses descriptor-relative
|
|
10
|
+
`renameatx_np(RENAME_EXCL)`. Unsupported systems and filesystems fail closed. Work, stages, link
|
|
11
|
+
sources, and destinations must share one filesystem; Servatus never weakens the contract with a
|
|
12
|
+
copy or check-then-rename fallback.
|
|
13
|
+
|
|
14
|
+
An identity-bound workspace is retained after build failure and removed only after a committed,
|
|
15
|
+
parent-synced publication. Cleanup failure is reported separately from publication success.
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling>=1.27"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "servatus"
|
|
7
|
+
version = "0.0.1"
|
|
8
|
+
description = "Run resumable work through Slurm and atomically publish validated outputs."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.11"
|
|
11
|
+
license = "MIT"
|
|
12
|
+
authors = [{ name = "Edoardo Galli" }]
|
|
13
|
+
classifiers = [
|
|
14
|
+
"Development Status :: 2 - Pre-Alpha",
|
|
15
|
+
"License :: OSI Approved :: MIT License",
|
|
16
|
+
"Operating System :: MacOS",
|
|
17
|
+
"Operating System :: POSIX :: Linux",
|
|
18
|
+
"Programming Language :: Python :: 3",
|
|
19
|
+
"Programming Language :: Python :: 3.11",
|
|
20
|
+
"Programming Language :: Python :: 3.12",
|
|
21
|
+
"Programming Language :: Python :: 3.13",
|
|
22
|
+
"Typing :: Typed",
|
|
23
|
+
]
|
|
24
|
+
dependencies = []
|
|
25
|
+
|
|
26
|
+
[project.urls]
|
|
27
|
+
Repository = "https://github.com/edoski/servatus"
|
|
28
|
+
Issues = "https://github.com/edoski/servatus/issues"
|
|
29
|
+
|
|
30
|
+
[dependency-groups]
|
|
31
|
+
dev = [
|
|
32
|
+
"pyright>=1.1.404",
|
|
33
|
+
"pytest>=8.4",
|
|
34
|
+
"ruff>=0.12",
|
|
35
|
+
"vulture>=2.14",
|
|
36
|
+
]
|
|
37
|
+
|
|
38
|
+
[tool.hatch.build.targets.wheel]
|
|
39
|
+
packages = ["src/servatus"]
|
|
40
|
+
|
|
41
|
+
[tool.pyright]
|
|
42
|
+
include = ["src"]
|
|
43
|
+
pythonVersion = "3.11"
|
|
44
|
+
typeCheckingMode = "strict"
|
|
45
|
+
|
|
46
|
+
[tool.pytest.ini_options]
|
|
47
|
+
testpaths = ["tests"]
|
|
48
|
+
|
|
49
|
+
[tool.ruff]
|
|
50
|
+
line-length = 100
|
|
51
|
+
target-version = "py311"
|
|
52
|
+
|
|
53
|
+
[tool.ruff.lint]
|
|
54
|
+
select = ["B", "E", "F", "I", "SIM", "UP"]
|
|
55
|
+
|
|
56
|
+
[tool.vulture]
|
|
57
|
+
min_confidence = 90
|
|
58
|
+
paths = ["src"]
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
from ._errors import (
|
|
2
|
+
CrossDevicePublication,
|
|
3
|
+
DestinationExists,
|
|
4
|
+
PublicationError,
|
|
5
|
+
ServatusError,
|
|
6
|
+
UnsafePublication,
|
|
7
|
+
UnsupportedPlatform,
|
|
8
|
+
WorkConflict,
|
|
9
|
+
WorkspaceBusy,
|
|
10
|
+
)
|
|
11
|
+
from ._workspace import Draft, Publication, Workspace, publish
|
|
12
|
+
|
|
13
|
+
__all__ = [
|
|
14
|
+
"CrossDevicePublication",
|
|
15
|
+
"DestinationExists",
|
|
16
|
+
"Draft",
|
|
17
|
+
"Publication",
|
|
18
|
+
"PublicationError",
|
|
19
|
+
"ServatusError",
|
|
20
|
+
"UnsafePublication",
|
|
21
|
+
"UnsupportedPlatform",
|
|
22
|
+
"WorkConflict",
|
|
23
|
+
"Workspace",
|
|
24
|
+
"WorkspaceBusy",
|
|
25
|
+
"publish",
|
|
26
|
+
]
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
class ServatusError(Exception):
|
|
2
|
+
"""Base class for Servatus contract failures."""
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class PublicationError(ServatusError):
|
|
6
|
+
"""A draft could not be safely published."""
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class DestinationExists(PublicationError):
|
|
10
|
+
"""The requested destination or draft entry already exists."""
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class CrossDevicePublication(PublicationError):
|
|
14
|
+
"""Publication would cross a filesystem boundary."""
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class UnsafePublication(PublicationError):
|
|
18
|
+
"""A path or filesystem entry violates the publication contract."""
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class UnsupportedPlatform(PublicationError):
|
|
22
|
+
"""The platform cannot provide an atomic no-replace commit."""
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class WorkConflict(ServatusError):
|
|
26
|
+
"""Existing private work is bound to another identity."""
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class WorkspaceBusy(ServatusError):
|
|
30
|
+
"""Another writer currently owns the workspace."""
|