things-api 0.1.0__tar.gz → 0.2.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.
Files changed (48) hide show
  1. things_api-0.2.1/.github/workflows/publish.yml +56 -0
  2. {things_api-0.1.0 → things_api-0.2.1}/CHANGELOG.md +11 -0
  3. {things_api-0.1.0 → things_api-0.2.1}/PKG-INFO +20 -11
  4. {things_api-0.1.0 → things_api-0.2.1}/README.md +19 -10
  5. {things_api-0.1.0 → things_api-0.2.1}/com.things-api.server.plist +11 -12
  6. {things_api-0.1.0 → things_api-0.2.1}/docs/deployment.md +17 -5
  7. {things_api-0.1.0 → things_api-0.2.1}/pyproject.toml +1 -1
  8. {things_api-0.1.0 → things_api-0.2.1}/src/things_api/app.py +13 -1
  9. {things_api-0.1.0 → things_api-0.2.1}/uv.lock +1 -1
  10. {things_api-0.1.0 → things_api-0.2.1}/.gitignore +0 -0
  11. {things_api-0.1.0 → things_api-0.2.1}/LICENSE +0 -0
  12. {things_api-0.1.0 → things_api-0.2.1}/docs/api-reference.md +0 -0
  13. {things_api-0.1.0 → things_api-0.2.1}/docs/configuration.md +0 -0
  14. {things_api-0.1.0 → things_api-0.2.1}/docs/development.md +0 -0
  15. {things_api-0.1.0 → things_api-0.2.1}/docs/plans/2026-04-03-things-api-design.md +0 -0
  16. {things_api-0.1.0 → things_api-0.2.1}/docs/plans/2026-04-03-things-api-plan.md +0 -0
  17. {things_api-0.1.0 → things_api-0.2.1}/docs/plans/2026-04-03-things-api-plan.md.tasks.json +0 -0
  18. {things_api-0.1.0 → things_api-0.2.1}/env.example +0 -0
  19. {things_api-0.1.0 → things_api-0.2.1}/src/things_api/__init__.py +0 -0
  20. {things_api-0.1.0 → things_api-0.2.1}/src/things_api/auth.py +0 -0
  21. {things_api-0.1.0 → things_api-0.2.1}/src/things_api/config.py +0 -0
  22. {things_api-0.1.0 → things_api-0.2.1}/src/things_api/models.py +0 -0
  23. {things_api-0.1.0 → things_api-0.2.1}/src/things_api/ratelimit.py +0 -0
  24. {things_api-0.1.0 → things_api-0.2.1}/src/things_api/routers/__init__.py +0 -0
  25. {things_api-0.1.0 → things_api-0.2.1}/src/things_api/routers/areas.py +0 -0
  26. {things_api-0.1.0 → things_api-0.2.1}/src/things_api/routers/lists.py +0 -0
  27. {things_api-0.1.0 → things_api-0.2.1}/src/things_api/routers/projects.py +0 -0
  28. {things_api-0.1.0 → things_api-0.2.1}/src/things_api/routers/search.py +0 -0
  29. {things_api-0.1.0 → things_api-0.2.1}/src/things_api/routers/tags.py +0 -0
  30. {things_api-0.1.0 → things_api-0.2.1}/src/things_api/routers/todos.py +0 -0
  31. {things_api-0.1.0 → things_api-0.2.1}/src/things_api/services/__init__.py +0 -0
  32. {things_api-0.1.0 → things_api-0.2.1}/src/things_api/services/reader.py +0 -0
  33. {things_api-0.1.0 → things_api-0.2.1}/src/things_api/services/writer.py +0 -0
  34. {things_api-0.1.0 → things_api-0.2.1}/tests/__init__.py +0 -0
  35. {things_api-0.1.0 → things_api-0.2.1}/tests/conftest.py +0 -0
  36. {things_api-0.1.0 → things_api-0.2.1}/tests/test_app.py +0 -0
  37. {things_api-0.1.0 → things_api-0.2.1}/tests/test_auth.py +0 -0
  38. {things_api-0.1.0 → things_api-0.2.1}/tests/test_config.py +0 -0
  39. {things_api-0.1.0 → things_api-0.2.1}/tests/test_models.py +0 -0
  40. {things_api-0.1.0 → things_api-0.2.1}/tests/test_ratelimit.py +0 -0
  41. {things_api-0.1.0 → things_api-0.2.1}/tests/test_reader.py +0 -0
  42. {things_api-0.1.0 → things_api-0.2.1}/tests/test_router_areas.py +0 -0
  43. {things_api-0.1.0 → things_api-0.2.1}/tests/test_router_lists.py +0 -0
  44. {things_api-0.1.0 → things_api-0.2.1}/tests/test_router_projects.py +0 -0
  45. {things_api-0.1.0 → things_api-0.2.1}/tests/test_router_search.py +0 -0
  46. {things_api-0.1.0 → things_api-0.2.1}/tests/test_router_tags.py +0 -0
  47. {things_api-0.1.0 → things_api-0.2.1}/tests/test_router_todos.py +0 -0
  48. {things_api-0.1.0 → things_api-0.2.1}/tests/test_writer.py +0 -0
@@ -0,0 +1,56 @@
1
+ name: Publish to PyPI
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - "v*"
7
+
8
+ jobs:
9
+ test:
10
+ runs-on: ubuntu-latest
11
+ steps:
12
+ - uses: actions/checkout@v4
13
+
14
+ - name: Install uv
15
+ uses: astral-sh/setup-uv@v6
16
+
17
+ - name: Set up Python
18
+ run: uv python install 3.12
19
+
20
+ - name: Install dependencies
21
+ run: uv sync --extra test
22
+
23
+ - name: Run tests
24
+ run: uv run pytest -v
25
+
26
+ publish:
27
+ needs: test
28
+ runs-on: ubuntu-latest
29
+ environment: pypi
30
+ permissions:
31
+ id-token: write
32
+ contents: read
33
+ steps:
34
+ - uses: actions/checkout@v4
35
+
36
+ - name: Install uv
37
+ uses: astral-sh/setup-uv@v6
38
+
39
+ - name: Set up Python
40
+ run: uv python install 3.12
41
+
42
+ - name: Check version consistency
43
+ run: |
44
+ TAG_VERSION="${GITHUB_REF_NAME#v}"
45
+ PYPROJECT_VERSION=$(uv run python -c "import tomllib; print(tomllib.load(open('pyproject.toml','rb'))['project']['version'])")
46
+ if [ "$TAG_VERSION" != "$PYPROJECT_VERSION" ]; then
47
+ echo "::error::Tag version ($TAG_VERSION) does not match pyproject.toml version ($PYPROJECT_VERSION)"
48
+ exit 1
49
+ fi
50
+ echo "Version $TAG_VERSION confirmed"
51
+
52
+ - name: Build
53
+ run: uv build
54
+
55
+ - name: Publish to PyPI
56
+ uses: pypa/gh-action-pypi-publish@release/v1
@@ -4,6 +4,17 @@ All notable changes to this project will be documented in this file.
4
4
 
5
5
  This project follows [Semantic Versioning](https://semver.org/).
6
6
 
7
+ ## [0.2.1] — 2026-04-03
8
+
9
+ ### Added
10
+
11
+ - Published to [PyPI](https://pypi.org/project/things-api/) — install with `pip install things-api` or run with `uvx things-api`
12
+ - GitHub Actions CI/CD pipeline with tag-driven PyPI publishing via trusted publishers (OIDC)
13
+
14
+ ### Fixed
15
+
16
+ - Friendly error message when `THINGS_API_TOKEN` is missing instead of a Pydantic traceback
17
+
7
18
  ## [0.1.0] — 2026-04-03
8
19
 
9
20
  ### Added
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: things-api
3
- Version: 0.1.0
3
+ Version: 0.2.1
4
4
  Summary: REST API for Things 3 — expose your tasks over HTTP
5
5
  Project-URL: Homepage, https://github.com/jaydenk/things-api
6
6
  Project-URL: Documentation, https://github.com/jaydenk/things-api/tree/main/docs
@@ -36,24 +36,33 @@ Things API reads directly from the Things SQLite database via [things.py](https:
36
36
 
37
37
  ## Getting started
38
38
 
39
- **Requirements:** macOS with [Things 3](https://culturedcode.com/things/) installed, Python 3.12+, and [uv](https://docs.astral.sh/uv/).
39
+ **Requirements:** macOS with [Things 3](https://culturedcode.com/things/) installed and Python 3.12+.
40
40
 
41
- ### 1. Clone and install
41
+ ### 1. Install
42
+
43
+ Run directly with [`uvx`](https://docs.astral.sh/uv/) (no install needed):
42
44
 
43
45
  ```sh
44
- git clone https://github.com/jaydenk/things-api.git
45
- cd things-api
46
- uv venv
47
- uv pip install -e .
46
+ uvx things-api
48
47
  ```
49
48
 
50
- ### 2. Configure
49
+ Or install with pip:
50
+
51
+ ```sh
52
+ pip install things-api
53
+ ```
54
+
55
+ Or clone the repo for development:
51
56
 
52
57
  ```sh
53
- cp env.example .env
58
+ git clone https://github.com/jaydenk/things-api.git
59
+ cd things-api
60
+ uv venv && uv pip install -e .
54
61
  ```
55
62
 
56
- Open `.env` and set your API token — this is the bearer token that authenticates every request:
63
+ ### 2. Configure
64
+
65
+ Create a `.env` file in the directory you'll run the server from:
57
66
 
58
67
  ```dotenv
59
68
  THINGS_API_TOKEN=choose-a-secure-random-string
@@ -72,7 +81,7 @@ See [docs/configuration.md](docs/configuration.md) for all configuration options
72
81
  ### 3. Run
73
82
 
74
83
  ```sh
75
- uv run things-api
84
+ things-api
76
85
  ```
77
86
 
78
87
  The server starts on `http://localhost:5225`.
@@ -6,24 +6,33 @@ Things API reads directly from the Things SQLite database via [things.py](https:
6
6
 
7
7
  ## Getting started
8
8
 
9
- **Requirements:** macOS with [Things 3](https://culturedcode.com/things/) installed, Python 3.12+, and [uv](https://docs.astral.sh/uv/).
9
+ **Requirements:** macOS with [Things 3](https://culturedcode.com/things/) installed and Python 3.12+.
10
10
 
11
- ### 1. Clone and install
11
+ ### 1. Install
12
+
13
+ Run directly with [`uvx`](https://docs.astral.sh/uv/) (no install needed):
12
14
 
13
15
  ```sh
14
- git clone https://github.com/jaydenk/things-api.git
15
- cd things-api
16
- uv venv
17
- uv pip install -e .
16
+ uvx things-api
18
17
  ```
19
18
 
20
- ### 2. Configure
19
+ Or install with pip:
20
+
21
+ ```sh
22
+ pip install things-api
23
+ ```
24
+
25
+ Or clone the repo for development:
21
26
 
22
27
  ```sh
23
- cp env.example .env
28
+ git clone https://github.com/jaydenk/things-api.git
29
+ cd things-api
30
+ uv venv && uv pip install -e .
24
31
  ```
25
32
 
26
- Open `.env` and set your API token — this is the bearer token that authenticates every request:
33
+ ### 2. Configure
34
+
35
+ Create a `.env` file in the directory you'll run the server from:
27
36
 
28
37
  ```dotenv
29
38
  THINGS_API_TOKEN=choose-a-secure-random-string
@@ -42,7 +51,7 @@ See [docs/configuration.md](docs/configuration.md) for all configuration options
42
51
  ### 3. Run
43
52
 
44
53
  ```sh
45
- uv run things-api
54
+ things-api
46
55
  ```
47
56
 
48
57
  The server starts on `http://localhost:5225`.
@@ -2,7 +2,7 @@
2
2
  Things API launchd agent
3
3
 
4
4
  Install:
5
- 1. Edit this file — set WorkingDirectory and ProgramArguments paths
5
+ 1. Edit this file — set WorkingDirectory and the path to uvx/uv
6
6
  2. Ensure your .env file exists in the working directory with THINGS_API_TOKEN set
7
7
  3. cp com.things-api.server.plist ~/Library/LaunchAgents/
8
8
  4. launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/com.things-api.server.plist
@@ -18,30 +18,29 @@
18
18
  <key>Label</key>
19
19
  <string>com.things-api.server</string>
20
20
 
21
- <!-- Working directory the server reads .env from here -->
21
+ <!-- The directory containing your .env file -->
22
22
  <key>WorkingDirectory</key>
23
- <string>/path/to/things-api</string>
23
+ <string>/path/to/directory-with-env-file</string>
24
24
 
25
25
  <!--
26
- Option A: Run from local source (development / pre-PyPI)
27
- Uses uv run to execute from the project directory.
28
- Replace /path/to/uv with the output of: which uv
26
+ Run from PyPI via uvx (recommended).
27
+ Replace /path/to/uvx with the output of: which uvx
29
28
  -->
30
29
  <key>ProgramArguments</key>
31
30
  <array>
32
- <string>/path/to/uv</string>
33
- <string>run</string>
31
+ <string>/path/to/uvx</string>
34
32
  <string>things-api</string>
35
33
  </array>
36
34
 
37
35
  <!--
38
- Option B: Run from PyPI (after publishing)
39
- Uncomment this block and comment out Option A above.
40
- Replace /path/to/uvx with the output of: which uvx
36
+ Alternative: run from a cloned repo with uv.
37
+ Uncomment this block and comment out the uvx block above.
38
+ Replace /path/to/uv with the output of: which uv
41
39
 
42
40
  <key>ProgramArguments</key>
43
41
  <array>
44
- <string>/path/to/uvx</string>
42
+ <string>/path/to/uv</string>
43
+ <string>run</string>
45
44
  <string>things-api</string>
46
45
  </array>
47
46
  -->
@@ -1,6 +1,6 @@
1
1
  # Deployment
2
2
 
3
- These instructions assume you've already completed the [Getting Started](../README.md#getting-started) steps the repo is cloned, dependencies are installed, and your `.env` file is configured.
3
+ These instructions assume you've already completed the [Getting Started](../README.md#getting-started) steps and have a `.env` file configured.
4
4
 
5
5
  ## Running as a launchd service
6
6
 
@@ -8,16 +8,28 @@ A launchd agent keeps Things API running in the background. It starts automatica
8
8
 
9
9
  ### 1. Edit the plist template
10
10
 
11
- Open `com.things-api.server.plist` in the project root and set two paths:
11
+ Open `com.things-api.server.plist` and set two paths:
12
12
 
13
- **`WorkingDirectory`** — the absolute path to your cloned `things-api` directory. This is where the server looks for your `.env` file.
13
+ **`WorkingDirectory`** — the absolute path to the directory containing your `.env` file. If you cloned the repo, this is your `things-api` directory. If you installed via pip/uvx, this is wherever you put your `.env`.
14
14
 
15
15
  ```xml
16
16
  <key>WorkingDirectory</key>
17
17
  <string>/Users/yourname/things-api</string>
18
18
  ```
19
19
 
20
- **`ProgramArguments`** — the absolute path to `uv`. Find it with `which uv`.
20
+ **`ProgramArguments`** — how to launch the server. Use full paths launchd does not inherit your shell's `PATH`.
21
+
22
+ If installed via **pip** or **uvx**:
23
+
24
+ ```xml
25
+ <key>ProgramArguments</key>
26
+ <array>
27
+ <string>/opt/homebrew/bin/uvx</string>
28
+ <string>things-api</string>
29
+ </array>
30
+ ```
31
+
32
+ If running from a **cloned repo**:
21
33
 
22
34
  ```xml
23
35
  <key>ProgramArguments</key>
@@ -28,7 +40,7 @@ Open `com.things-api.server.plist` in the project root and set two paths:
28
40
  </array>
29
41
  ```
30
42
 
31
- > **Note:** launchd does not inherit your shell's `PATH`, so you must use the full path to `uv`.
43
+ Find the correct path with `which uvx` or `which uv`.
32
44
 
33
45
  ### 2. Install and load
34
46
 
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "things-api"
7
- version = "0.1.0"
7
+ version = "0.2.1"
8
8
  description = "REST API for Things 3 — expose your tasks over HTTP"
9
9
  readme = "README.md"
10
10
  license = "MIT"
@@ -89,7 +89,19 @@ def main() -> None:
89
89
  level=logging.INFO,
90
90
  format="%(asctime)s %(levelname)s %(name)s: %(message)s",
91
91
  )
92
- settings = Settings()
92
+ try:
93
+ settings = Settings()
94
+ except Exception:
95
+ print(
96
+ "Error: THINGS_API_TOKEN is not set.\n"
97
+ "\n"
98
+ "Set it as an environment variable:\n"
99
+ " THINGS_API_TOKEN=your-secret-token things-api\n"
100
+ "\n"
101
+ "Or create a .env file in the current directory:\n"
102
+ " echo 'THINGS_API_TOKEN=your-secret-token' > .env"
103
+ )
104
+ raise SystemExit(1)
93
105
  app = create_app(settings)
94
106
  uvicorn.run(
95
107
  app,
@@ -389,7 +389,7 @@ wheels = [
389
389
 
390
390
  [[package]]
391
391
  name = "things-api"
392
- version = "0.1.0"
392
+ version = "0.2.1"
393
393
  source = { editable = "." }
394
394
  dependencies = [
395
395
  { name = "fastapi" },
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes