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.
@@ -0,0 +1,7 @@
1
+ .venv/
2
+ .pytest_cache/
3
+ __pycache__/
4
+ .vscode/
5
+ # Local secrets / runtime env (keep .env.example tracked)
6
+ .env
7
+ .env.*.local
@@ -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`
@@ -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