pyronites 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.
- pyronites-0.1.0/.gitignore +7 -0
- pyronites-0.1.0/CHANGELOG.md +33 -0
- pyronites-0.1.0/PKG-INFO +109 -0
- pyronites-0.1.0/README.md +82 -0
- pyronites-0.1.0/docs/PUBLISH.md +39 -0
- pyronites-0.1.0/docs/STRUCTURE.md +25 -0
- pyronites-0.1.0/docs/architect.md +55 -0
- pyronites-0.1.0/docs/features.md +30 -0
- pyronites-0.1.0/docs/plan.md +29 -0
- pyronites-0.1.0/docs/syntax.md +74 -0
- pyronites-0.1.0/examples/basic_usage.py +44 -0
- pyronites-0.1.0/pyproject.toml +57 -0
- pyronites-0.1.0/pyronites/__init__.py +14 -0
- pyronites-0.1.0/pyronites/auth.py +45 -0
- pyronites-0.1.0/pyronites/client.py +121 -0
- pyronites-0.1.0/pyronites/config.py +80 -0
- pyronites-0.1.0/pyronites/errors.py +40 -0
- pyronites-0.1.0/pyronites/http.py +124 -0
- pyronites-0.1.0/pyronites/local.py +128 -0
- pyronites-0.1.0/pyronites/storage.py +140 -0
- pyronites-0.1.0/pyronites/table.py +217 -0
- pyronites-0.1.0/tests/test_auth.py +51 -0
- pyronites-0.1.0/tests/test_client.py +46 -0
- pyronites-0.1.0/tests/test_config.py +38 -0
- pyronites-0.1.0/tests/test_errors.py +15 -0
- pyronites-0.1.0/tests/test_http.py +127 -0
- pyronites-0.1.0/tests/test_local.py +126 -0
- pyronites-0.1.0/tests/test_storage.py +126 -0
- pyronites-0.1.0/tests/test_table.py +101 -0
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to the **pyronites** client package are documented here.
|
|
4
|
+
|
|
5
|
+
Format based on [Keep a Changelog](https://keepachangelog.com/). Versioning follows [SemVer](https://semver.org/).
|
|
6
|
+
|
|
7
|
+
## [0.1.0] — 2026-07-25
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
#### Phase P1 — Core client
|
|
12
|
+
- `create_client()` with `PYRONITES_URL` / `PYRONITES_KEY` config
|
|
13
|
+
- HTTP transport (`httpx`) with Bearer auth and typed errors
|
|
14
|
+
- Auth: `sign_up`, `sign_in`, `sign_out`, `user`
|
|
15
|
+
- Tables: `select`, `insert`, `update().eq("id", ...)`, `delete().eq("id", ...)`, `get`, `sql`
|
|
16
|
+
- Errors: `ApiError`, `AuthError`, `NotFoundError`
|
|
17
|
+
|
|
18
|
+
#### Phase P2 — Storage
|
|
19
|
+
- `client.storage.upload` / `list` / `get` / `download` / `remove`
|
|
20
|
+
|
|
21
|
+
#### Phase P3 — Local vs remote policy
|
|
22
|
+
- `local_tables`, `cache_tables`, `remote_tables`, `local_db_path`
|
|
23
|
+
- SQLite local store
|
|
24
|
+
- `pull` / `push` / `sync` (v1 conflict policy: remote wins)
|
|
25
|
+
|
|
26
|
+
#### Phase P4 — Polish
|
|
27
|
+
- Changelog, expanded README, example script
|
|
28
|
+
- PyPI-ready `pyproject.toml` metadata
|
|
29
|
+
|
|
30
|
+
### Notes
|
|
31
|
+
- Default table policy is **remote**
|
|
32
|
+
- Minimum Python: 3.10
|
|
33
|
+
- Runtime dependency: `httpx>=0.27.0`
|
pyronites-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: pyronites
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Official Python client for the Pyronites (PyroCore) backend
|
|
5
|
+
Project-URL: Homepage, https://github.com/Ashutosh3021/Pyronites
|
|
6
|
+
Project-URL: Repository, https://github.com/Ashutosh3021/Pyronites
|
|
7
|
+
Project-URL: Documentation, https://github.com/Ashutosh3021/Pyronites/tree/main/pyronites/docs
|
|
8
|
+
Author: Ashutosh
|
|
9
|
+
License: MIT
|
|
10
|
+
Keywords: backend,client,pyrocore,pyronites,sqlite,supabase
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Typing :: Typed
|
|
19
|
+
Requires-Python: >=3.10
|
|
20
|
+
Requires-Dist: httpx>=0.27.0
|
|
21
|
+
Provides-Extra: dev
|
|
22
|
+
Requires-Dist: build>=1.0; extra == 'dev'
|
|
23
|
+
Requires-Dist: pytest-httpx>=0.30; extra == 'dev'
|
|
24
|
+
Requires-Dist: pytest>=8.0; extra == 'dev'
|
|
25
|
+
Requires-Dist: twine>=5.0; extra == 'dev'
|
|
26
|
+
Description-Content-Type: text/markdown
|
|
27
|
+
|
|
28
|
+
# pyronites
|
|
29
|
+
|
|
30
|
+
Official Python client for the [Pyronites](https://github.com/Ashutosh3021/Pyronites) backend.
|
|
31
|
+
|
|
32
|
+
Supabase-style API, zero mandatory paid services — point it at your own backend URL + API key.
|
|
33
|
+
|
|
34
|
+
## Install
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
# Development (from this repo)
|
|
38
|
+
pip install -e ./pyronites
|
|
39
|
+
|
|
40
|
+
# From PyPI (after publish)
|
|
41
|
+
pip install pyronites
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Requires **Python 3.10+**.
|
|
45
|
+
|
|
46
|
+
## 5-minute setup
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
export PYRONITES_URL="https://your-backend.example.com"
|
|
50
|
+
export PYRONITES_KEY="pyro_live_..."
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
```python
|
|
54
|
+
from pyronites import create_client
|
|
55
|
+
|
|
56
|
+
client = create_client()
|
|
57
|
+
|
|
58
|
+
# Auth (optional)
|
|
59
|
+
client.auth.sign_in("user@example.com", "password")
|
|
60
|
+
print(client.auth.user())
|
|
61
|
+
|
|
62
|
+
# Tables
|
|
63
|
+
note = client.table("notes").insert({"title": "Hello", "body": "World"})
|
|
64
|
+
for row in client.table("notes").select().limit(10):
|
|
65
|
+
print(row)
|
|
66
|
+
client.table("notes").update({"title": "Updated"}).eq("id", note["id"])
|
|
67
|
+
client.table("notes").delete().eq("id", note["id"])
|
|
68
|
+
|
|
69
|
+
# Storage
|
|
70
|
+
meta = client.storage.upload("photo.jpg")
|
|
71
|
+
data = client.storage.download(meta["id"])
|
|
72
|
+
client.storage.remove(meta["id"])
|
|
73
|
+
|
|
74
|
+
# Local-only / cache tables (optional)
|
|
75
|
+
client = create_client(
|
|
76
|
+
local_tables=["settings"],
|
|
77
|
+
cache_tables=["catalog"],
|
|
78
|
+
local_db_path="./.pyronites_local.db",
|
|
79
|
+
)
|
|
80
|
+
client.table("settings").insert({"theme": "dark"})
|
|
81
|
+
client.pull("catalog")
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## Config
|
|
85
|
+
|
|
86
|
+
| Source | Variables / args |
|
|
87
|
+
|--------|------------------|
|
|
88
|
+
| Env | `PYRONITES_URL`, `PYRONITES_KEY`, optional `PYRONITES_LOCAL_DB` |
|
|
89
|
+
| Constructor | `create_client(url=..., key=..., timeout=30, local_tables=..., cache_tables=..., remote_tables=..., local_db_path=...)` |
|
|
90
|
+
|
|
91
|
+
Args override env. Missing URL raises a clear error at create time.
|
|
92
|
+
|
|
93
|
+
**Security:** never put a powerful service key in a public frontend.
|
|
94
|
+
|
|
95
|
+
## Public API
|
|
96
|
+
|
|
97
|
+
See [`docs/syntax.md`](docs/syntax.md).
|
|
98
|
+
|
|
99
|
+
## Development
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
cd pyronites
|
|
103
|
+
pip install -e ".[dev]"
|
|
104
|
+
pytest
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
## License
|
|
108
|
+
|
|
109
|
+
MIT
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# pyronites
|
|
2
|
+
|
|
3
|
+
Official Python client for the [Pyronites](https://github.com/Ashutosh3021/Pyronites) backend.
|
|
4
|
+
|
|
5
|
+
Supabase-style API, zero mandatory paid services — point it at your own backend URL + API key.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
# Development (from this repo)
|
|
11
|
+
pip install -e ./pyronites
|
|
12
|
+
|
|
13
|
+
# From PyPI (after publish)
|
|
14
|
+
pip install pyronites
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Requires **Python 3.10+**.
|
|
18
|
+
|
|
19
|
+
## 5-minute setup
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
export PYRONITES_URL="https://your-backend.example.com"
|
|
23
|
+
export PYRONITES_KEY="pyro_live_..."
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
```python
|
|
27
|
+
from pyronites import create_client
|
|
28
|
+
|
|
29
|
+
client = create_client()
|
|
30
|
+
|
|
31
|
+
# Auth (optional)
|
|
32
|
+
client.auth.sign_in("user@example.com", "password")
|
|
33
|
+
print(client.auth.user())
|
|
34
|
+
|
|
35
|
+
# Tables
|
|
36
|
+
note = client.table("notes").insert({"title": "Hello", "body": "World"})
|
|
37
|
+
for row in client.table("notes").select().limit(10):
|
|
38
|
+
print(row)
|
|
39
|
+
client.table("notes").update({"title": "Updated"}).eq("id", note["id"])
|
|
40
|
+
client.table("notes").delete().eq("id", note["id"])
|
|
41
|
+
|
|
42
|
+
# Storage
|
|
43
|
+
meta = client.storage.upload("photo.jpg")
|
|
44
|
+
data = client.storage.download(meta["id"])
|
|
45
|
+
client.storage.remove(meta["id"])
|
|
46
|
+
|
|
47
|
+
# Local-only / cache tables (optional)
|
|
48
|
+
client = create_client(
|
|
49
|
+
local_tables=["settings"],
|
|
50
|
+
cache_tables=["catalog"],
|
|
51
|
+
local_db_path="./.pyronites_local.db",
|
|
52
|
+
)
|
|
53
|
+
client.table("settings").insert({"theme": "dark"})
|
|
54
|
+
client.pull("catalog")
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Config
|
|
58
|
+
|
|
59
|
+
| Source | Variables / args |
|
|
60
|
+
|--------|------------------|
|
|
61
|
+
| Env | `PYRONITES_URL`, `PYRONITES_KEY`, optional `PYRONITES_LOCAL_DB` |
|
|
62
|
+
| Constructor | `create_client(url=..., key=..., timeout=30, local_tables=..., cache_tables=..., remote_tables=..., local_db_path=...)` |
|
|
63
|
+
|
|
64
|
+
Args override env. Missing URL raises a clear error at create time.
|
|
65
|
+
|
|
66
|
+
**Security:** never put a powerful service key in a public frontend.
|
|
67
|
+
|
|
68
|
+
## Public API
|
|
69
|
+
|
|
70
|
+
See [`docs/syntax.md`](docs/syntax.md).
|
|
71
|
+
|
|
72
|
+
## Development
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
cd pyronites
|
|
76
|
+
pip install -e ".[dev]"
|
|
77
|
+
pytest
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## License
|
|
81
|
+
|
|
82
|
+
MIT
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# Publishing pyronites to PyPI
|
|
2
|
+
|
|
3
|
+
## Preconditions
|
|
4
|
+
|
|
5
|
+
- [x] P1–P3 feature-complete
|
|
6
|
+
- [x] Unit tests passing
|
|
7
|
+
- [x] `CHANGELOG.md` updated
|
|
8
|
+
- [x] Version in `pyproject.toml` and `pyronites/__init__.py` match
|
|
9
|
+
- [ ] PyPI account + API token
|
|
10
|
+
- [ ] Package name `pyronites` available (or use a scoped name if taken)
|
|
11
|
+
|
|
12
|
+
## Steps
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
cd pyronites
|
|
16
|
+
pip install build twine
|
|
17
|
+
|
|
18
|
+
python -m build
|
|
19
|
+
twine check dist/*
|
|
20
|
+
|
|
21
|
+
# TestPyPI first (recommended)
|
|
22
|
+
twine upload --repository testpypi dist/*
|
|
23
|
+
# then
|
|
24
|
+
twine upload dist/*
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## After publish
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
pip install pyronites
|
|
31
|
+
python -c "from pyronites import create_client, __version__; print(__version__)"
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Version bumps
|
|
35
|
+
|
|
36
|
+
1. Update `__version__` in `pyronites/__init__.py`
|
|
37
|
+
2. Update `version` in `pyproject.toml`
|
|
38
|
+
3. Add a section to `CHANGELOG.md`
|
|
39
|
+
4. Tag: `git tag v0.1.0 && git push --tags`
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# Package layout (canonical)
|
|
2
|
+
|
|
3
|
+
```
|
|
4
|
+
pyronites/ # installable root → pip install -e ./pyronites
|
|
5
|
+
├── docs/
|
|
6
|
+
│ ├── architect.md
|
|
7
|
+
│ ├── features.md
|
|
8
|
+
│ ├── plan.md
|
|
9
|
+
│ └── syntax.md
|
|
10
|
+
├── pyproject.toml
|
|
11
|
+
├── README.md
|
|
12
|
+
├── pyronites/ # importable Python package
|
|
13
|
+
│ ├── __init__.py
|
|
14
|
+
│ ├── client.py
|
|
15
|
+
│ ├── config.py
|
|
16
|
+
│ ├── http.py
|
|
17
|
+
│ ├── errors.py
|
|
18
|
+
│ ├── auth.py
|
|
19
|
+
│ ├── table.py
|
|
20
|
+
│ └── … # storage.py (P2), local.py (P3)
|
|
21
|
+
└── tests/
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Install: `pip install -e ./pyronites`
|
|
25
|
+
Import: `from pyronites import create_client`
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# pyronites — Client Package Architecture
|
|
2
|
+
|
|
3
|
+
> See also `docs/syntax.md` (public API) and `docs/features.md` (checklist).
|
|
4
|
+
|
|
5
|
+
Install: `pip install -e ./pyronites`
|
|
6
|
+
|
|
7
|
+
## Module layout
|
|
8
|
+
|
|
9
|
+
```text
|
|
10
|
+
pyronites/ # installable root
|
|
11
|
+
docs/ # plan, features, architect, syntax
|
|
12
|
+
pyproject.toml
|
|
13
|
+
README.md
|
|
14
|
+
pyronites/ # importable package
|
|
15
|
+
__init__.py # create_client, errors, __version__
|
|
16
|
+
client.py # PyronitesClient façade
|
|
17
|
+
config.py
|
|
18
|
+
http.py
|
|
19
|
+
auth.py
|
|
20
|
+
table.py
|
|
21
|
+
storage.py # P2
|
|
22
|
+
local.py # P3
|
|
23
|
+
errors.py
|
|
24
|
+
tests/
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Apps only need:
|
|
28
|
+
|
|
29
|
+
```python
|
|
30
|
+
from pyronites import create_client
|
|
31
|
+
client = create_client()
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Design principles
|
|
35
|
+
|
|
36
|
+
1. Thin over clever
|
|
37
|
+
2. Backend is source of truth
|
|
38
|
+
3. Env-first secrets (`PYRONITES_URL` / `PYRONITES_KEY`)
|
|
39
|
+
4. Remote by default
|
|
40
|
+
5. Zero cost (httpx only)
|
|
41
|
+
6. Match existing backend API
|
|
42
|
+
|
|
43
|
+
## Backend route mapping
|
|
44
|
+
|
|
45
|
+
| Client | Backend |
|
|
46
|
+
|--------|---------|
|
|
47
|
+
| `auth.sign_up` | `POST /auth/signup` |
|
|
48
|
+
| `auth.sign_in` | `POST /auth/login` |
|
|
49
|
+
| `auth.sign_out` | `POST /auth/logout` |
|
|
50
|
+
| `auth.user` | `GET /auth/me` |
|
|
51
|
+
| `table(t).select` | `GET /tables/{t}` |
|
|
52
|
+
| `table(t).insert` | `POST /tables/{t}` |
|
|
53
|
+
| `table(t).update...` | `PATCH /tables/{t}/{id}` |
|
|
54
|
+
| `table(t).delete...` | `DELETE /tables/{t}/{id}` |
|
|
55
|
+
| `storage.*` | `/storage/*` (P2) |
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# pyronites — Client Package Features
|
|
2
|
+
|
|
3
|
+
> Status: `[ ]` not started · `[~]` partial · `[x]` done
|
|
4
|
+
|
|
5
|
+
Install: `pip install -e ./pyronites`
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## F0 — Packaging
|
|
10
|
+
|
|
11
|
+
- [x] Package name, installable layout, `pyproject.toml`, public import, version, changelog, PyPI metadata
|
|
12
|
+
- [ ] Published on PyPI — needs maintainer token
|
|
13
|
+
|
|
14
|
+
## F1–F4 — Core (P1)
|
|
15
|
+
|
|
16
|
+
- [x] Config, HTTP, Auth, Tables, SQL escape hatch
|
|
17
|
+
|
|
18
|
+
## F5 — Storage (P2)
|
|
19
|
+
|
|
20
|
+
- [x] upload / list / get / download / remove
|
|
21
|
+
|
|
22
|
+
## F6 — Local vs remote (P3)
|
|
23
|
+
|
|
24
|
+
- [x] local / cache / remote policy, SQLite store, pull / push / sync
|
|
25
|
+
|
|
26
|
+
## F7–F8 — DX & quality (P4)
|
|
27
|
+
|
|
28
|
+
- [x] README, example script, 44 unit tests, PUBLISH.md
|
|
29
|
+
- [ ] Live integration against Render (manual)
|
|
30
|
+
- [ ] fluffy-spork migration
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# pyronites — Client Package Plan
|
|
2
|
+
|
|
3
|
+
> Reference & checklist for building the official Python client that talks to a self-hosted PyroCore / Pyronites backend.
|
|
4
|
+
>
|
|
5
|
+
> Goal: make using Pyronites feel as simple as `supabase-py`, with **zero cost** and clear control over what stays local vs remote.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Document map
|
|
10
|
+
|
|
11
|
+
| File | Use |
|
|
12
|
+
|------|-----|
|
|
13
|
+
| `docs/plan.md` | This file — phases, success criteria, non-goals |
|
|
14
|
+
| `docs/features.md` | Feature-level checklist |
|
|
15
|
+
| `docs/architect.md` | Architecture, modules, data flow, security |
|
|
16
|
+
| `docs/syntax.md` | Public API contract & usage examples |
|
|
17
|
+
|
|
18
|
+
Install: `pip install -e ./pyronites`
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## Phases (summary)
|
|
23
|
+
|
|
24
|
+
- **P1** Core client (config, http, auth, table) — done
|
|
25
|
+
- **P2** Storage + ergonomics
|
|
26
|
+
- **P3** Local vs remote policy
|
|
27
|
+
- **P4** Polish & publish
|
|
28
|
+
|
|
29
|
+
See the full plan history in git; this file is the living checklist. Update when phase decisions change.
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# pyronites — Syntax & Usage Guide
|
|
2
|
+
|
|
3
|
+
> **Public contract.** Apps write against this surface.
|
|
4
|
+
|
|
5
|
+
## Install & import
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pip install -e ./pyronites
|
|
9
|
+
# later: pip install pyronites
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
```python
|
|
13
|
+
from pyronites import create_client, ApiError, AuthError, NotFoundError
|
|
14
|
+
|
|
15
|
+
client = create_client() # reads PYRONITES_URL + PYRONITES_KEY
|
|
16
|
+
# or
|
|
17
|
+
client = create_client(url="https://...", key="pyro_live_...")
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Config
|
|
21
|
+
|
|
22
|
+
| Variable | Meaning |
|
|
23
|
+
|----------|---------|
|
|
24
|
+
| `PYRONITES_URL` | Backend base URL |
|
|
25
|
+
| `PYRONITES_KEY` | API key (Bearer) |
|
|
26
|
+
|
|
27
|
+
Args override env. Missing URL → clear error at create time.
|
|
28
|
+
|
|
29
|
+
## Auth (P1)
|
|
30
|
+
|
|
31
|
+
```python
|
|
32
|
+
client.auth.sign_up(email, password) -> dict
|
|
33
|
+
client.auth.sign_in(email, password) -> dict
|
|
34
|
+
client.auth.sign_out() -> None
|
|
35
|
+
client.auth.user() -> dict | None
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Tables (P1)
|
|
39
|
+
|
|
40
|
+
```python
|
|
41
|
+
client.table("notes").select()
|
|
42
|
+
client.table("notes").select().eq("status", "open").limit(20)
|
|
43
|
+
client.table("notes").insert({"title": "Hello"})
|
|
44
|
+
client.table("notes").update({"title": "X"}).eq("id", "...")
|
|
45
|
+
client.table("notes").delete().eq("id", "...")
|
|
46
|
+
client.table("notes").get("id")
|
|
47
|
+
client.sql("SELECT count(*) FROM notes") # admin key
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Storage (P2)
|
|
51
|
+
|
|
52
|
+
```python
|
|
53
|
+
client.storage.upload(...)
|
|
54
|
+
client.storage.list()
|
|
55
|
+
client.storage.download(id)
|
|
56
|
+
client.storage.remove(id)
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Errors
|
|
60
|
+
|
|
61
|
+
```python
|
|
62
|
+
ApiError
|
|
63
|
+
├─ AuthError # 401/403
|
|
64
|
+
└─ NotFoundError # 404
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## Document map
|
|
68
|
+
|
|
69
|
+
| File | Role |
|
|
70
|
+
|------|------|
|
|
71
|
+
| `docs/plan.md` | Phases |
|
|
72
|
+
| `docs/features.md` | Checklist |
|
|
73
|
+
| `docs/architect.md` | Internals |
|
|
74
|
+
| `docs/syntax.md` | This file |
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Minimal example against a live or local Pyronites backend.
|
|
3
|
+
|
|
4
|
+
Usage:
|
|
5
|
+
export PYRONITES_URL=https://pyrocore-backend.onrender.com
|
|
6
|
+
export PYRONITES_KEY=pyro_live_...
|
|
7
|
+
python examples/basic_usage.py
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
import os
|
|
13
|
+
import sys
|
|
14
|
+
|
|
15
|
+
from pyronites import ApiError, create_client
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def main() -> int:
|
|
19
|
+
if not os.environ.get("PYRONITES_URL"):
|
|
20
|
+
print("Set PYRONITES_URL (and usually PYRONITES_KEY) first.", file=sys.stderr)
|
|
21
|
+
return 1
|
|
22
|
+
|
|
23
|
+
client = create_client()
|
|
24
|
+
try:
|
|
25
|
+
print("Inserting demo row into 'notes' (table must exist on backend)...")
|
|
26
|
+
try:
|
|
27
|
+
row = client.table("notes").insert(
|
|
28
|
+
{"title": "pyronites demo", "body": "hello from examples/basic_usage.py"}
|
|
29
|
+
)
|
|
30
|
+
print("Inserted:", row)
|
|
31
|
+
rid = row.get("id")
|
|
32
|
+
if rid:
|
|
33
|
+
client.table("notes").delete().eq("id", rid)
|
|
34
|
+
print("Deleted:", rid)
|
|
35
|
+
except ApiError as e:
|
|
36
|
+
print(f"Table operation failed ({e}). Create a 'notes' table in the dashboard first.")
|
|
37
|
+
return 1
|
|
38
|
+
finally:
|
|
39
|
+
client.close()
|
|
40
|
+
return 0
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
if __name__ == "__main__":
|
|
44
|
+
raise SystemExit(main())
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "pyronites"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "Official Python client for the Pyronites (PyroCore) backend"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
requires-python = ">=3.10"
|
|
7
|
+
license = { text = "MIT" }
|
|
8
|
+
authors = [{ name = "Ashutosh" }]
|
|
9
|
+
keywords = ["pyronites", "pyrocore", "sqlite", "backend", "client", "supabase"]
|
|
10
|
+
classifiers = [
|
|
11
|
+
"Development Status :: 4 - Beta",
|
|
12
|
+
"Intended Audience :: Developers",
|
|
13
|
+
"License :: OSI Approved :: MIT License",
|
|
14
|
+
"Programming Language :: Python :: 3",
|
|
15
|
+
"Programming Language :: Python :: 3.10",
|
|
16
|
+
"Programming Language :: Python :: 3.11",
|
|
17
|
+
"Programming Language :: Python :: 3.12",
|
|
18
|
+
"Typing :: Typed",
|
|
19
|
+
]
|
|
20
|
+
dependencies = [
|
|
21
|
+
"httpx>=0.27.0",
|
|
22
|
+
]
|
|
23
|
+
|
|
24
|
+
[project.urls]
|
|
25
|
+
Homepage = "https://github.com/Ashutosh3021/Pyronites"
|
|
26
|
+
Repository = "https://github.com/Ashutosh3021/Pyronites"
|
|
27
|
+
Documentation = "https://github.com/Ashutosh3021/Pyronites/tree/main/pyronites/docs"
|
|
28
|
+
|
|
29
|
+
[project.optional-dependencies]
|
|
30
|
+
dev = [
|
|
31
|
+
"pytest>=8.0",
|
|
32
|
+
"pytest-httpx>=0.30",
|
|
33
|
+
"build>=1.0",
|
|
34
|
+
"twine>=5.0",
|
|
35
|
+
]
|
|
36
|
+
|
|
37
|
+
[build-system]
|
|
38
|
+
requires = ["hatchling"]
|
|
39
|
+
build-backend = "hatchling.build"
|
|
40
|
+
|
|
41
|
+
[tool.hatch.build.targets.wheel]
|
|
42
|
+
packages = ["pyronites"]
|
|
43
|
+
|
|
44
|
+
[tool.hatch.build.targets.sdist]
|
|
45
|
+
include = [
|
|
46
|
+
"pyronites/",
|
|
47
|
+
"tests/",
|
|
48
|
+
"examples/",
|
|
49
|
+
"docs/",
|
|
50
|
+
"README.md",
|
|
51
|
+
"CHANGELOG.md",
|
|
52
|
+
"pyproject.toml",
|
|
53
|
+
]
|
|
54
|
+
|
|
55
|
+
[tool.pytest.ini_options]
|
|
56
|
+
testpaths = ["tests"]
|
|
57
|
+
pythonpath = ["."]
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"""pyronites — official Python client for the Pyronites backend."""
|
|
2
|
+
|
|
3
|
+
from pyronites.client import create_client
|
|
4
|
+
from pyronites.errors import ApiError, AuthError, NotFoundError
|
|
5
|
+
|
|
6
|
+
__version__ = "0.1.0"
|
|
7
|
+
|
|
8
|
+
__all__ = [
|
|
9
|
+
"create_client",
|
|
10
|
+
"ApiError",
|
|
11
|
+
"AuthError",
|
|
12
|
+
"NotFoundError",
|
|
13
|
+
"__version__",
|
|
14
|
+
]
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"""Auth methods for the pyronites client."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import Any, Dict, Optional
|
|
6
|
+
|
|
7
|
+
from pyronites.errors import AuthError
|
|
8
|
+
from pyronites.http import HttpTransport
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class AuthClient:
|
|
12
|
+
def __init__(self, transport: HttpTransport) -> None:
|
|
13
|
+
self._http = transport
|
|
14
|
+
self._user: Optional[Dict[str, Any]] = None
|
|
15
|
+
|
|
16
|
+
def sign_up(self, email: str, password: str) -> Dict[str, Any]:
|
|
17
|
+
data = self._http.request(
|
|
18
|
+
"POST", "/auth/signup",
|
|
19
|
+
json={"email": email, "password": password},
|
|
20
|
+
)
|
|
21
|
+
self._user = data
|
|
22
|
+
return data # type: ignore[return-value]
|
|
23
|
+
|
|
24
|
+
def sign_in(self, email: str, password: str) -> Dict[str, Any]:
|
|
25
|
+
data = self._http.request(
|
|
26
|
+
"POST", "/auth/login",
|
|
27
|
+
json={"email": email, "password": password},
|
|
28
|
+
)
|
|
29
|
+
self._user = data
|
|
30
|
+
return data # type: ignore[return-value]
|
|
31
|
+
|
|
32
|
+
def sign_out(self) -> None:
|
|
33
|
+
try:
|
|
34
|
+
self._http.request("POST", "/auth/logout")
|
|
35
|
+
finally:
|
|
36
|
+
self._user = None
|
|
37
|
+
|
|
38
|
+
def user(self) -> Optional[Dict[str, Any]]:
|
|
39
|
+
try:
|
|
40
|
+
data = self._http.request("GET", "/auth/me")
|
|
41
|
+
self._user = data
|
|
42
|
+
return data # type: ignore[return-value]
|
|
43
|
+
except AuthError:
|
|
44
|
+
self._user = None
|
|
45
|
+
return None
|