Skip to content

Commit 981e5a4

Browse files
update readme to favor new mkdocs and publish scripts to supply the empty auth credentials by default
1 parent 0d6ef64 commit 981e5a4

4 files changed

Lines changed: 190 additions & 9 deletions

File tree

README.md

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,24 +11,48 @@ Links:
1111

1212
## Generating the Docs
1313

14-
The documentation is built with [Sphinx](https://www.sphinx-doc.org/). Dev dependencies (including Sphinx) are installed automatically with:
14+
The documentation is built with [MkDocs](https://www.mkdocs.org/) using the
15+
Material theme, [mkdocstrings](https://mkdocstrings.github.io/) for
16+
auto-generated API reference from the source, and
17+
[mermaid](https://mermaid.js.org/) for architecture diagrams. Markdown sources
18+
live under `docs/markdown/`.
19+
20+
Install dev dependencies (including MkDocs and plugins):
1521

1622
```bash
1723
uv sync
1824
```
1925

20-
Then build the HTML docs:
26+
Build the HTML docs:
2127

2228
```bash
23-
uv run sphinx-build -b html docs/source docs/build/html
29+
uv run mkdocs build
2430
```
2531

26-
The output will be in `docs/build/html/`. Open `docs/build/html/index.html` in a browser to view locally.
32+
The output will be in `docs/build/html/`. Open `docs/build/html/index.html` in
33+
a browser to view locally.
2734

28-
To do a clean rebuild:
35+
For a live-reloading preview while editing:
2936

3037
```bash
31-
uv run sphinx-build -E -b html docs/source docs/build/html
38+
uv run mkdocs serve
3239
```
3340

34-
The `-E` flag forces Sphinx to re-read all source files rather than using cached data.
41+
Then visit http://127.0.0.1:8000.
42+
43+
To match what CI publishes (warnings become errors — useful when you've
44+
touched docstrings):
45+
46+
```bash
47+
uv run mkdocs build --strict
48+
```
49+
50+
CI builds the site on every push and deploys `main` to GitHub Pages via
51+
`.github/workflows/docs_pages.yaml`.
52+
53+
The legacy Sphinx setup under `docs/source/` is kept temporarily for
54+
reference and builds to a separate output directory:
55+
56+
```bash
57+
uv run sphinx-build -b html docs/source docs/build/sphinx
58+
```

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "oshconnect"
3-
version = "0.4.0a1"
3+
version = "0.5.0a0"
44
description = "Library for interfacing with OSH, helping guide visualization efforts, and providing a place to store configurations. Implements OGC CS API Part 3 (Pub/Sub) MQTT topic conventions including :data topics and resource event topics."
55
readme = "README.md"
66
authors = [

scripts/publish-local.py

Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
#!/usr/bin/env python3
2+
# =============================================================================
3+
# publish-local.py — Build oshconnect and publish to the local PyPI server.
4+
#
5+
# One-command dev loop: edit code -> run this -> downstream picks up the new
6+
# version via `pip install --index-url http://localhost:8090/simple/ oshconnect`.
7+
#
8+
# The local pypiserver container must be running (started automatically below
9+
# via `docker compose up -d pypi` if it isn't). pypiserver is configured with
10+
# `-o` so re-uploading the same version overwrites — no version bump needed.
11+
#
12+
# Usage:
13+
# ./scripts/publish-local.py # build + upload
14+
# ./scripts/publish-local.py --no-build # upload existing wheel(s) in dist/
15+
# LOCAL_PYPI_URL=http://host:port ./scripts/publish-local.py # override URL
16+
# =============================================================================
17+
from __future__ import annotations
18+
19+
import argparse
20+
import os
21+
import shutil
22+
import subprocess
23+
import sys
24+
import time
25+
import urllib.error
26+
import urllib.request
27+
from pathlib import Path
28+
29+
PROJECT_ROOT = Path(__file__).resolve().parent.parent
30+
PYPI_URL = os.environ.get("LOCAL_PYPI_URL", "http://localhost:8090")
31+
32+
CYAN = "\033[0;36m"
33+
GREEN = "\033[0;32m"
34+
RED = "\033[0;31m"
35+
NC = "\033[0m"
36+
37+
38+
def info(msg: str) -> None:
39+
print(f"{CYAN}[INFO]{NC} {msg}")
40+
41+
42+
def ok(msg: str) -> None:
43+
print(f"{GREEN}[OK]{NC} {msg}")
44+
45+
46+
def fail(msg: str, code: int = 1) -> None:
47+
print(f"{RED}[FAIL]{NC} {msg}", file=sys.stderr)
48+
sys.exit(code)
49+
50+
51+
def pypi_ready(url: str) -> bool:
52+
"""Return True iff the URL responds with a 2xx or 3xx status."""
53+
try:
54+
with urllib.request.urlopen(url, timeout=3) as resp:
55+
return 200 <= resp.status < 400
56+
except (urllib.error.URLError, urllib.error.HTTPError, TimeoutError, OSError):
57+
return False
58+
59+
60+
def ensure_pypi(url: str) -> None:
61+
info(f"Checking local PyPI at {url}")
62+
if pypi_ready(url):
63+
ok("Local PyPI is already running")
64+
return
65+
66+
info("Local PyPI not running — starting container...")
67+
res = subprocess.run(
68+
["docker", "compose", "up", "-d", "pypi"], cwd=PROJECT_ROOT
69+
)
70+
if res.returncode != 0:
71+
fail("docker compose up failed")
72+
73+
for i in range(1, 11):
74+
time.sleep(1)
75+
if pypi_ready(url):
76+
ok("Local PyPI started")
77+
return
78+
info(f" waiting... ({i}/10)")
79+
80+
fail("Could not start local PyPI")
81+
82+
83+
def build_wheel() -> None:
84+
info("Building wheel...")
85+
for sub in ("dist", "build"):
86+
shutil.rmtree(PROJECT_ROOT / sub, ignore_errors=True)
87+
for egg in (PROJECT_ROOT / "src").glob("*.egg-info"):
88+
shutil.rmtree(egg, ignore_errors=True)
89+
90+
res = subprocess.run(["uv", "build"], cwd=PROJECT_ROOT)
91+
if res.returncode != 0:
92+
fail("uv build failed")
93+
94+
95+
def find_wheels() -> list[Path]:
96+
return sorted((PROJECT_ROOT / "dist").glob("*.whl"))
97+
98+
99+
def publish(url: str, wheels: list[Path]) -> None:
100+
# pypiserver runs with `-a . -P .` (auth disabled), but `uv publish`/
101+
# pypiserver still issue a Basic-Auth challenge that triggers an
102+
# interactive prompt. Pass empty credentials to satisfy it.
103+
info(f"Uploading to {url}")
104+
cmd = [
105+
"uv", "publish",
106+
"--publish-url", url,
107+
"--username", "",
108+
"--password", "",
109+
*[str(w) for w in wheels],
110+
]
111+
res = subprocess.run(cmd, cwd=PROJECT_ROOT)
112+
if res.returncode != 0:
113+
fail("uv publish failed")
114+
115+
116+
def main() -> int:
117+
parser = argparse.ArgumentParser(
118+
description="Build oshconnect and publish it to the local PyPI server.",
119+
)
120+
parser.add_argument(
121+
"--no-build",
122+
action="store_true",
123+
help="Skip wheel build; upload whatever is in dist/.",
124+
)
125+
args = parser.parse_args()
126+
127+
info(f"Project root: {PROJECT_ROOT}")
128+
ensure_pypi(PYPI_URL)
129+
130+
if not args.no_build:
131+
build_wheel()
132+
133+
wheels = find_wheels()
134+
if not wheels:
135+
fail(
136+
f"No wheel found in {PROJECT_ROOT}/dist/. "
137+
"Build first or remove --no-build."
138+
)
139+
140+
ok(f"Wheel(s): {' '.join(str(w.relative_to(PROJECT_ROOT)) for w in wheels)}")
141+
publish(PYPI_URL, wheels)
142+
143+
ok("Published to local PyPI")
144+
print()
145+
print(f" Browse: {PYPI_URL}/simple/")
146+
print(f" Install: pip install --index-url {PYPI_URL}/simple/ oshconnect")
147+
print(f" uv: uv pip install --index-url {PYPI_URL}/simple/ oshconnect")
148+
print(f" uv sync: uv sync (if pyproject.toml has [[tool.uv.index]] configured)")
149+
return 0
150+
151+
152+
if __name__ == "__main__":
153+
sys.exit(main())

scripts/publish-local.sh

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,8 +96,12 @@ fi
9696
ok "Wheel(s): ${WHEELS[*]}"
9797

9898
# ── Upload ──────────────────────────────────────────────────────────────────
99+
# pypiserver runs with `-a . -P .` (auth disabled), but `uv publish` still
100+
# prompts for credentials when none are configured. Pass empty values via
101+
# flags to skip the prompt and run non-interactively.
99102
info "Uploading to ${PYPI_URL}"
100-
uv publish --publish-url "${PYPI_URL}" dist/*.whl || fail "uv publish failed"
103+
uv publish --publish-url "${PYPI_URL}" --username "" --password "" dist/*.whl \
104+
|| fail "uv publish failed"
101105

102106
ok "Published to local PyPI"
103107
echo ""

0 commit comments

Comments
 (0)