ramtable 0.3.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.
- ramtable-0.3.1/.github/workflows/publish-test.yml +126 -0
- ramtable-0.3.1/.github/workflows/publish.yml +124 -0
- ramtable-0.3.1/.github/workflows/tests.yml +57 -0
- ramtable-0.3.1/.gitignore +21 -0
- ramtable-0.3.1/CHANGELOG.md +79 -0
- ramtable-0.3.1/LICENSE +21 -0
- ramtable-0.3.1/PKG-INFO +232 -0
- ramtable-0.3.1/README.md +213 -0
- ramtable-0.3.1/docs/api.md +441 -0
- ramtable-0.3.1/docs/development.md +134 -0
- ramtable-0.3.1/docs/guide.md +384 -0
- ramtable-0.3.1/docs/types-and-validation.md +161 -0
- ramtable-0.3.1/pyproject.toml +33 -0
- ramtable-0.3.1/src/ramtable/__init__.py +15 -0
- ramtable-0.3.1/src/ramtable/columns.py +181 -0
- ramtable-0.3.1/src/ramtable/rows.py +397 -0
- ramtable-0.3.1/src/ramtable/table.py +58 -0
- ramtable-0.3.1/src/ramtable/types.py +181 -0
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
name: Publish to TestPyPI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
pull_request:
|
|
5
|
+
branches:
|
|
6
|
+
- test_pypi
|
|
7
|
+
types: [opened, synchronize, reopened, closed]
|
|
8
|
+
|
|
9
|
+
permissions:
|
|
10
|
+
contents: read
|
|
11
|
+
|
|
12
|
+
concurrency:
|
|
13
|
+
group: publish-testpypi-${{ github.ref }}
|
|
14
|
+
cancel-in-progress: false
|
|
15
|
+
|
|
16
|
+
jobs:
|
|
17
|
+
validate:
|
|
18
|
+
name: Validate and build
|
|
19
|
+
# Build on every PR activity, and also on a merged close so the artifact
|
|
20
|
+
# exists for the publish job. A closed, unmerged PR is skipped.
|
|
21
|
+
if: github.event.action != 'closed' || github.event.pull_request.merged == true
|
|
22
|
+
runs-on: ubuntu-latest
|
|
23
|
+
timeout-minutes: 15
|
|
24
|
+
|
|
25
|
+
steps:
|
|
26
|
+
- name: Check out repository
|
|
27
|
+
uses: actions/checkout@v4
|
|
28
|
+
|
|
29
|
+
- name: Set up Python
|
|
30
|
+
uses: actions/setup-python@v5
|
|
31
|
+
with:
|
|
32
|
+
python-version: "3.12"
|
|
33
|
+
cache: pip
|
|
34
|
+
cache-dependency-path: pyproject.toml
|
|
35
|
+
|
|
36
|
+
- name: Install build tools and package
|
|
37
|
+
run: |
|
|
38
|
+
python -m pip install --upgrade pip
|
|
39
|
+
python -m pip install build twine packaging
|
|
40
|
+
python -m pip install .
|
|
41
|
+
|
|
42
|
+
# The repository does not ship an automated test suite yet. These
|
|
43
|
+
# checks verify that the package compiles and is importable. Replace
|
|
44
|
+
# them with the project's test command once tests are added.
|
|
45
|
+
- name: Run checks
|
|
46
|
+
run: |
|
|
47
|
+
python -m compileall -q src/ramtable
|
|
48
|
+
python -c "from ramtable import Columns, Rows, Table"
|
|
49
|
+
|
|
50
|
+
- name: Validate version for TestPyPI
|
|
51
|
+
run: |
|
|
52
|
+
python - <<'PY'
|
|
53
|
+
import pathlib
|
|
54
|
+
import tomllib
|
|
55
|
+
|
|
56
|
+
from packaging.version import InvalidVersion, Version
|
|
57
|
+
|
|
58
|
+
version = tomllib.loads(
|
|
59
|
+
pathlib.Path("pyproject.toml").read_text(encoding="utf-8")
|
|
60
|
+
)["project"]["version"]
|
|
61
|
+
|
|
62
|
+
try:
|
|
63
|
+
parsed = Version(version)
|
|
64
|
+
except InvalidVersion:
|
|
65
|
+
raise SystemExit(
|
|
66
|
+
f"::error::'{version}' is not a valid PEP 440 version."
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
# TestPyPI accepts release candidates (X.Y.ZrcN) and stable
|
|
70
|
+
# releases (X.Y.Z). Development, alpha, beta, post, and local
|
|
71
|
+
# versions are rejected.
|
|
72
|
+
allowed = (
|
|
73
|
+
not parsed.is_devrelease
|
|
74
|
+
and not parsed.is_postrelease
|
|
75
|
+
and parsed.local is None
|
|
76
|
+
and (parsed.pre is None or parsed.pre[0] == "rc")
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
if not allowed:
|
|
80
|
+
raise SystemExit(
|
|
81
|
+
"::error::TestPyPI accepts stable versions (X.Y.Z) or "
|
|
82
|
+
"release candidates (X.Y.ZrcN); got "
|
|
83
|
+
f"'{version}'."
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
print(f"Version '{version}' is valid for TestPyPI.")
|
|
87
|
+
PY
|
|
88
|
+
|
|
89
|
+
- name: Build distributions
|
|
90
|
+
run: python -m build
|
|
91
|
+
|
|
92
|
+
- name: Validate distributions
|
|
93
|
+
run: python -m twine check dist/*
|
|
94
|
+
|
|
95
|
+
- name: Upload distributions
|
|
96
|
+
uses: actions/upload-artifact@v4
|
|
97
|
+
with:
|
|
98
|
+
name: testpypi-dists
|
|
99
|
+
path: dist/
|
|
100
|
+
if-no-files-found: error
|
|
101
|
+
retention-days: 7
|
|
102
|
+
|
|
103
|
+
publish:
|
|
104
|
+
name: Publish to TestPyPI
|
|
105
|
+
needs:
|
|
106
|
+
- validate
|
|
107
|
+
if: github.event.action == 'closed' && github.event.pull_request.merged == true
|
|
108
|
+
runs-on: ubuntu-latest
|
|
109
|
+
timeout-minutes: 10
|
|
110
|
+
environment:
|
|
111
|
+
name: testpypi
|
|
112
|
+
permissions:
|
|
113
|
+
id-token: write
|
|
114
|
+
|
|
115
|
+
steps:
|
|
116
|
+
- name: Download built distributions
|
|
117
|
+
uses: actions/download-artifact@v4
|
|
118
|
+
with:
|
|
119
|
+
name: testpypi-dists
|
|
120
|
+
path: dist/
|
|
121
|
+
|
|
122
|
+
- name: Publish to TestPyPI
|
|
123
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
124
|
+
with:
|
|
125
|
+
repository-url: https://test.pypi.org/legacy/
|
|
126
|
+
packages-dir: dist/
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
name: Publish to PyPI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
pull_request:
|
|
5
|
+
branches:
|
|
6
|
+
- main
|
|
7
|
+
types: [opened, synchronize, reopened, closed]
|
|
8
|
+
|
|
9
|
+
permissions:
|
|
10
|
+
contents: read
|
|
11
|
+
|
|
12
|
+
concurrency:
|
|
13
|
+
group: publish-pypi-${{ github.ref }}
|
|
14
|
+
cancel-in-progress: false
|
|
15
|
+
|
|
16
|
+
jobs:
|
|
17
|
+
validate:
|
|
18
|
+
name: Validate and build
|
|
19
|
+
# Build on every PR activity, and also on a merged close so the artifact
|
|
20
|
+
# exists for the publish job. A closed, unmerged PR is skipped.
|
|
21
|
+
if: github.event.action != 'closed' || github.event.pull_request.merged == true
|
|
22
|
+
runs-on: ubuntu-latest
|
|
23
|
+
timeout-minutes: 15
|
|
24
|
+
|
|
25
|
+
steps:
|
|
26
|
+
- name: Check out repository
|
|
27
|
+
uses: actions/checkout@v4
|
|
28
|
+
|
|
29
|
+
- name: Set up Python
|
|
30
|
+
uses: actions/setup-python@v5
|
|
31
|
+
with:
|
|
32
|
+
python-version: "3.12"
|
|
33
|
+
cache: pip
|
|
34
|
+
cache-dependency-path: pyproject.toml
|
|
35
|
+
|
|
36
|
+
- name: Install build tools and package
|
|
37
|
+
run: |
|
|
38
|
+
python -m pip install --upgrade pip
|
|
39
|
+
python -m pip install build twine packaging
|
|
40
|
+
python -m pip install .
|
|
41
|
+
|
|
42
|
+
# The repository does not ship an automated test suite yet. These
|
|
43
|
+
# checks verify that the package compiles and is importable. Replace
|
|
44
|
+
# them with the project's test command once tests are added.
|
|
45
|
+
- name: Run checks
|
|
46
|
+
run: |
|
|
47
|
+
python -m compileall -q src/ramtable
|
|
48
|
+
python -c "from ramtable import Columns, Rows, Table"
|
|
49
|
+
|
|
50
|
+
- name: Validate version for PyPI
|
|
51
|
+
run: |
|
|
52
|
+
python - <<'PY'
|
|
53
|
+
import pathlib
|
|
54
|
+
import tomllib
|
|
55
|
+
|
|
56
|
+
from packaging.version import InvalidVersion, Version
|
|
57
|
+
|
|
58
|
+
version = tomllib.loads(
|
|
59
|
+
pathlib.Path("pyproject.toml").read_text(encoding="utf-8")
|
|
60
|
+
)["project"]["version"]
|
|
61
|
+
|
|
62
|
+
try:
|
|
63
|
+
parsed = Version(version)
|
|
64
|
+
except InvalidVersion:
|
|
65
|
+
raise SystemExit(
|
|
66
|
+
f"::error::'{version}' is not a valid PEP 440 version."
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
# PyPI accepts stable releases (X.Y.Z) only. Pre-releases,
|
|
70
|
+
# development releases, post releases, and local versions are
|
|
71
|
+
# rejected.
|
|
72
|
+
allowed = (
|
|
73
|
+
not parsed.is_prerelease
|
|
74
|
+
and not parsed.is_devrelease
|
|
75
|
+
and not parsed.is_postrelease
|
|
76
|
+
and parsed.local is None
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
if not allowed:
|
|
80
|
+
raise SystemExit(
|
|
81
|
+
"::error::PyPI accepts stable versions (X.Y.Z) only; "
|
|
82
|
+
f"got '{version}'."
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
print(f"Version '{version}' is valid for PyPI.")
|
|
86
|
+
PY
|
|
87
|
+
|
|
88
|
+
- name: Build distributions
|
|
89
|
+
run: python -m build
|
|
90
|
+
|
|
91
|
+
- name: Validate distributions
|
|
92
|
+
run: python -m twine check dist/*
|
|
93
|
+
|
|
94
|
+
- name: Upload distributions
|
|
95
|
+
uses: actions/upload-artifact@v4
|
|
96
|
+
with:
|
|
97
|
+
name: pypi-dists
|
|
98
|
+
path: dist/
|
|
99
|
+
if-no-files-found: error
|
|
100
|
+
retention-days: 7
|
|
101
|
+
|
|
102
|
+
publish:
|
|
103
|
+
name: Publish to PyPI
|
|
104
|
+
needs:
|
|
105
|
+
- validate
|
|
106
|
+
if: github.event.action == 'closed' && github.event.pull_request.merged == true
|
|
107
|
+
runs-on: ubuntu-latest
|
|
108
|
+
timeout-minutes: 10
|
|
109
|
+
environment:
|
|
110
|
+
name: pypi
|
|
111
|
+
permissions:
|
|
112
|
+
id-token: write
|
|
113
|
+
|
|
114
|
+
steps:
|
|
115
|
+
- name: Download built distributions
|
|
116
|
+
uses: actions/download-artifact@v4
|
|
117
|
+
with:
|
|
118
|
+
name: pypi-dists
|
|
119
|
+
path: dist/
|
|
120
|
+
|
|
121
|
+
- name: Publish to PyPI
|
|
122
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
123
|
+
with:
|
|
124
|
+
packages-dir: dist/
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
name: Tests
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches:
|
|
6
|
+
- dev
|
|
7
|
+
pull_request:
|
|
8
|
+
branches:
|
|
9
|
+
- dev
|
|
10
|
+
- test_pypi
|
|
11
|
+
- main
|
|
12
|
+
|
|
13
|
+
permissions:
|
|
14
|
+
contents: read
|
|
15
|
+
|
|
16
|
+
concurrency:
|
|
17
|
+
group: tests-${{ github.workflow }}-${{ github.ref }}
|
|
18
|
+
cancel-in-progress: true
|
|
19
|
+
|
|
20
|
+
jobs:
|
|
21
|
+
test:
|
|
22
|
+
name: Python ${{ matrix.python-version }}
|
|
23
|
+
runs-on: ubuntu-latest
|
|
24
|
+
timeout-minutes: 10
|
|
25
|
+
strategy:
|
|
26
|
+
fail-fast: false
|
|
27
|
+
matrix:
|
|
28
|
+
python-version:
|
|
29
|
+
- "3.10"
|
|
30
|
+
- "3.11"
|
|
31
|
+
- "3.12"
|
|
32
|
+
- "3.13"
|
|
33
|
+
|
|
34
|
+
steps:
|
|
35
|
+
- name: Check out repository
|
|
36
|
+
uses: actions/checkout@v4
|
|
37
|
+
|
|
38
|
+
- name: Set up Python ${{ matrix.python-version }}
|
|
39
|
+
uses: actions/setup-python@v5
|
|
40
|
+
with:
|
|
41
|
+
python-version: ${{ matrix.python-version }}
|
|
42
|
+
cache: pip
|
|
43
|
+
cache-dependency-path: pyproject.toml
|
|
44
|
+
|
|
45
|
+
- name: Install package
|
|
46
|
+
run: |
|
|
47
|
+
python -m pip install --upgrade pip
|
|
48
|
+
python -m pip install .
|
|
49
|
+
|
|
50
|
+
- name: Byte-compile package
|
|
51
|
+
run: python -m compileall -q src/ramtable
|
|
52
|
+
|
|
53
|
+
# The repository does not ship an automated test suite yet. This import
|
|
54
|
+
# check verifies that the installed package is importable. Replace this
|
|
55
|
+
# step with the project's test command once tests are added.
|
|
56
|
+
- name: Import check
|
|
57
|
+
run: python -c "from ramtable import Columns, Rows, Table"
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
Notable changes to RAMTable are documented in this file. The history starts
|
|
4
|
+
with the project's first version.
|
|
5
|
+
|
|
6
|
+
## [0.3.1]
|
|
7
|
+
|
|
8
|
+
Publishes RAMTable to the official PyPI index alongside TestPyPI.
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- Stable releases are now published to PyPI under the name `ramtable`.
|
|
13
|
+
- Branch-based release flow (`dev` → `test_pypi` → `main`) with PEP 440
|
|
14
|
+
version validation in GitHub Actions.
|
|
15
|
+
- Trusted Publishing with OIDC for both PyPI and TestPyPI; no API tokens are
|
|
16
|
+
stored in the repository.
|
|
17
|
+
|
|
18
|
+
### Changed
|
|
19
|
+
|
|
20
|
+
- Installation documentation covers stable releases from PyPI and
|
|
21
|
+
pre-releases from TestPyPI.
|
|
22
|
+
- `pyproject.toml` reports version `0.3.1rc0`.
|
|
23
|
+
|
|
24
|
+
## [0.3.0]
|
|
25
|
+
|
|
26
|
+
Adds declarative filtering and shares one condition engine across filtering,
|
|
27
|
+
updating, and deleting rows.
|
|
28
|
+
|
|
29
|
+
### Added
|
|
30
|
+
|
|
31
|
+
- `Rows.filter(where)` returns the rows that match a set of conditions.
|
|
32
|
+
- `Rows.delete(where)` removes every matching row and returns the number
|
|
33
|
+
deleted.
|
|
34
|
+
- Flexible conditions in `where`: comparison operators (`==`, `!=`, `>`,
|
|
35
|
+
`>=`, `<`, `<=`), membership (`in`, `not_in`), string and container
|
|
36
|
+
matching (`contains`, `startswith`, `endswith`), and callable predicates.
|
|
37
|
+
- Documentation for filtering, deletion, and the shared condition format.
|
|
38
|
+
|
|
39
|
+
### Changed
|
|
40
|
+
|
|
41
|
+
- `Rows.update(where, values)` now accepts the same flexible conditions;
|
|
42
|
+
plain values still mean equality.
|
|
43
|
+
- A dictionary in `where` is now interpreted as an operator specification;
|
|
44
|
+
to compare a column against a dictionary value, use `{"==": value}`.
|
|
45
|
+
- `pyproject.toml` and the README now report version `0.3.0`.
|
|
46
|
+
|
|
47
|
+
## [0.2.0]
|
|
48
|
+
|
|
49
|
+
This version prepares complete project documentation and a more useful
|
|
50
|
+
onboarding experience for users installing RAMTable from TestPyPI.
|
|
51
|
+
|
|
52
|
+
### Added
|
|
53
|
+
|
|
54
|
+
- Expanded README covering the project's purpose, status, installation, quick
|
|
55
|
+
start, features, and documentation links.
|
|
56
|
+
- Detailed user guide, API reference, type-validation guide, and development
|
|
57
|
+
guide.
|
|
58
|
+
- Project changelog.
|
|
59
|
+
|
|
60
|
+
### Changed
|
|
61
|
+
|
|
62
|
+
- Updated the `pyproject.toml` project version to `0.2.0`.
|
|
63
|
+
|
|
64
|
+
## [0.1.1]
|
|
65
|
+
|
|
66
|
+
### Fixed
|
|
67
|
+
|
|
68
|
+
- Corrected the `pyproject.toml` packaging configuration to include the
|
|
69
|
+
package located at `src/ramtable` when building distributions.
|
|
70
|
+
|
|
71
|
+
## [0.1.0]
|
|
72
|
+
|
|
73
|
+
### Added
|
|
74
|
+
|
|
75
|
+
- First RAMTable version: in-memory tables with a typed column schema and
|
|
76
|
+
basic row operations.
|
|
77
|
+
- Runtime validation of row structure and value types.
|
|
78
|
+
- Publish to Test PyPi.
|
|
79
|
+
|
ramtable-0.3.1/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 RAMTable contributors
|
|
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.
|
ramtable-0.3.1/PKG-INFO
ADDED
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: ramtable
|
|
3
|
+
Version: 0.3.1
|
|
4
|
+
Summary: A lightweight in-memory table library for Python.
|
|
5
|
+
Author: Thiago Valentín Stilo Limarino
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
License-File: LICENSE
|
|
8
|
+
Keywords: data-structure,in-memory,python,table
|
|
9
|
+
Classifier: Development Status :: 3 - Alpha
|
|
10
|
+
Classifier: Intended Audience :: Developers
|
|
11
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
17
|
+
Requires-Python: >=3.10
|
|
18
|
+
Description-Content-Type: text/markdown
|
|
19
|
+
|
|
20
|
+
# RAMTable
|
|
21
|
+
|
|
22
|
+

|
|
23
|
+

|
|
24
|
+
[](https://pypi.org/project/ramtable/)
|
|
25
|
+
[](https://test.pypi.org/project/ramtable/)
|
|
26
|
+
|
|
27
|
+
RAMTable provides typed in-memory tables for data that only needs to live
|
|
28
|
+
while a program is running. It gives records an explicit schema and common
|
|
29
|
+
operations, without requiring you to manage lists and dictionaries by hand
|
|
30
|
+
or set up a persistent SQL database.
|
|
31
|
+
|
|
32
|
+
RAMTable is a lightweight Python library with no runtime dependencies. Data
|
|
33
|
+
is kept in memory and is lost when the process ends. RAMTable is not a
|
|
34
|
+
database: it does not execute SQL and does not write data to disk.
|
|
35
|
+
|
|
36
|
+
## Where it fits
|
|
37
|
+
|
|
38
|
+
Reach for RAMTable when a plain `list` or `dict` does not provide enough
|
|
39
|
+
structure, but a persistent database is too much:
|
|
40
|
+
|
|
41
|
+
| | Plain `list` / `dict` | RAMTable | SQL database |
|
|
42
|
+
|---|:---:|:---:|:---:|
|
|
43
|
+
| Schema with declared types | — | ✓ | ✓ |
|
|
44
|
+
| Rows validated on write | — | ✓ | ✓ |
|
|
45
|
+
| Schema changes with data present | manual | ✓ | ✓ |
|
|
46
|
+
| Query language, indexes, constraints | — | — | ✓ |
|
|
47
|
+
| Survives process exit | — | — | ✓ |
|
|
48
|
+
| Setup | none | none | server or files |
|
|
49
|
+
|
|
50
|
+
Typical scenarios:
|
|
51
|
+
|
|
52
|
+
- intermediate results of a multi-step process;
|
|
53
|
+
- temporary records staged during a calculation or import;
|
|
54
|
+
- the working set of a long-running task;
|
|
55
|
+
- prototypes that want typed rows before a real database exists.
|
|
56
|
+
|
|
57
|
+
For simple collections, a list or dictionary is still the right answer. If
|
|
58
|
+
data must survive restarts, be shared between processes, or be queried with
|
|
59
|
+
SQL, use an appropriate persistence solution instead. For analysis and
|
|
60
|
+
vectorized operations, use a data-frame library: RAMTable targets structured
|
|
61
|
+
temporary storage, not analytics.
|
|
62
|
+
|
|
63
|
+
## Installation
|
|
64
|
+
|
|
65
|
+
RAMTable requires Python 3.10 or later.
|
|
66
|
+
|
|
67
|
+
Install the latest stable release from PyPI:
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
python -m pip install ramtable
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Pre-releases are published to TestPyPI. To try one:
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
python -m pip install --pre --index-url https://test.pypi.org/simple/ ramtable
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
TestPyPI is a separate testing index, not the official package index. Stable
|
|
80
|
+
releases are published to PyPI under the name `ramtable`.
|
|
81
|
+
|
|
82
|
+
Install from a local checkout:
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
python -m pip install .
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Install in editable mode for development:
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
python -m pip install --editable .
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
## Quick start
|
|
95
|
+
|
|
96
|
+
```python
|
|
97
|
+
from ramtable import Table
|
|
98
|
+
|
|
99
|
+
people = Table(
|
|
100
|
+
name="people",
|
|
101
|
+
columns={
|
|
102
|
+
"id": int,
|
|
103
|
+
"name": str,
|
|
104
|
+
"age": int,
|
|
105
|
+
"email": str,
|
|
106
|
+
},
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
# Every row must contain exactly the columns declared above.
|
|
110
|
+
people.rows.insert(
|
|
111
|
+
{"id": 1, "name": "Ada", "age": 36, "email": "ada@example.com"}
|
|
112
|
+
)
|
|
113
|
+
people.rows.insert(
|
|
114
|
+
{"id": 2, "name": "Linus", "age": 28, "email": "linus@example.com"}
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
print(people.rows.get_column("name"))
|
|
118
|
+
# ['Ada', 'Linus']
|
|
119
|
+
|
|
120
|
+
# Update every row matching the conditions; returns the number of rows changed.
|
|
121
|
+
updated = people.rows.update(
|
|
122
|
+
where={"id": 1},
|
|
123
|
+
values={"name": "Ada Lovelace"},
|
|
124
|
+
)
|
|
125
|
+
print(updated)
|
|
126
|
+
# 1
|
|
127
|
+
|
|
128
|
+
print(people.rows.get_one(0))
|
|
129
|
+
# {'id': 1, 'name': 'Ada Lovelace', 'age': 36, 'email': 'ada@example.com'}
|
|
130
|
+
|
|
131
|
+
# Conditions go beyond equality in filter(), update(), and delete().
|
|
132
|
+
older = people.rows.filter({"age": {">": 30}})
|
|
133
|
+
print([row["name"] for row in older])
|
|
134
|
+
# ['Ada Lovelace']
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
A `Table` exposes two views over the same storage:
|
|
138
|
+
|
|
139
|
+
- `table.rows`: the data. Insert, read, update, and remove rows.
|
|
140
|
+
- `table.columns`: the schema. Add, remove, and retype columns.
|
|
141
|
+
|
|
142
|
+
The [user guide](docs/guide.md) walks through every operation step by step.
|
|
143
|
+
|
|
144
|
+
## Features
|
|
145
|
+
|
|
146
|
+
- **Explicit schema:** declare column names and types when the table is
|
|
147
|
+
created.
|
|
148
|
+
- **Runtime validation:** every row must contain exactly the schema's
|
|
149
|
+
columns, and each value must match its declared type.
|
|
150
|
+
- **Row operations:** insert, retrieve, update, filter, and delete rows.
|
|
151
|
+
- **Flexible conditions:** one condition format powers `filter`, `update`,
|
|
152
|
+
and `delete`, with comparison, membership, and string operators.
|
|
153
|
+
- **Schema evolution:** add, remove, or retype columns while accounting for
|
|
154
|
+
existing rows.
|
|
155
|
+
- **Validate-then-write:** update requests are checked in full before any
|
|
156
|
+
row is modified, so a rejected request never leaves a partial change.
|
|
157
|
+
- **Zero dependencies:** no server, no SQL setup, nothing beyond the package
|
|
158
|
+
itself.
|
|
159
|
+
|
|
160
|
+
## Supported types
|
|
161
|
+
|
|
162
|
+
Besides plain classes, RAMTable understands `Any`, `None`, unions
|
|
163
|
+
(`str | None`), `Annotated`, `Literal`, `type[T]`, and parameterized lists,
|
|
164
|
+
sets, frozensets, sequences, mappings, dictionaries, and tuples. Nested
|
|
165
|
+
arguments are checked recursively:
|
|
166
|
+
|
|
167
|
+
| Annotation | Example | Rule |
|
|
168
|
+
|---|---|---|
|
|
169
|
+
| Classes | `int`, `str`, `bytes` | `isinstance` |
|
|
170
|
+
| Unions | `str \| None` | any alternative may match |
|
|
171
|
+
| `Literal` | `Literal["pending", "done"]` | value and exact type |
|
|
172
|
+
| Sequence types | `list[str]`, `set[int]`, `Sequence[float]` | container class, then every item |
|
|
173
|
+
| Mapping types | `dict[str, int]`, `Mapping[str, list[int]]` | container class, then every key and value |
|
|
174
|
+
| Tuples | `tuple[int, str]`, `tuple[int, ...]` | fixed positions or one repeated type |
|
|
175
|
+
| `Annotated` | `Annotated[int, "id"]` | base type only; metadata is ignored |
|
|
176
|
+
| Class objects | `type[int]` | subclasses of `T` |
|
|
177
|
+
| `Any` / `None` | — | any value / only `None` |
|
|
178
|
+
|
|
179
|
+
```python
|
|
180
|
+
from typing import Literal
|
|
181
|
+
from ramtable import Table
|
|
182
|
+
|
|
183
|
+
events = Table(
|
|
184
|
+
"events",
|
|
185
|
+
{
|
|
186
|
+
"name": str,
|
|
187
|
+
"status": Literal["pending", "complete"],
|
|
188
|
+
"tags": list[str],
|
|
189
|
+
},
|
|
190
|
+
)
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
Simple classes follow `isinstance` semantics, so a `bool` value also matches
|
|
194
|
+
`int`. `Literal` is stricter: it compares both value and exact type. See
|
|
195
|
+
[types and validation](docs/types-and-validation.md) for the complete rules
|
|
196
|
+
and known limitations.
|
|
197
|
+
|
|
198
|
+
## Copies and lifecycle
|
|
199
|
+
|
|
200
|
+
Rows are stored as dictionaries. Inserting a row stores a shallow copy of
|
|
201
|
+
the dictionary; retrieving a row returns a new dictionary containing the same
|
|
202
|
+
values. Mutable objects used as cell values may therefore remain shared
|
|
203
|
+
with the code that supplied or retrieved them.
|
|
204
|
+
|
|
205
|
+
`table.clear()` removes all rows and preserves the schema. No operation
|
|
206
|
+
writes to disk: records disappear when the process ends.
|
|
207
|
+
|
|
208
|
+
## Documentation
|
|
209
|
+
|
|
210
|
+
| Document | Contents |
|
|
211
|
+
|---|---|
|
|
212
|
+
| [User guide](docs/guide.md) | Tables, rows, filtering, schema changes, errors, and limits. |
|
|
213
|
+
| [API reference](docs/api.md) | Every class and method, with arguments, returns, and exceptions. |
|
|
214
|
+
| [Types and validation](docs/types-and-validation.md) | Supported annotations and runtime checking rules. |
|
|
215
|
+
| [Development and releases](docs/development.md) | Project layout, checks, and the release process. |
|
|
216
|
+
| [CHANGELOG](CHANGELOG.md) | Release history. |
|
|
217
|
+
| [LICENSE](LICENSE) | MIT license terms. |
|
|
218
|
+
|
|
219
|
+
## Project status
|
|
220
|
+
|
|
221
|
+
The current development version is **0.3.1rc0**. RAMTable is published as
|
|
222
|
+
`ramtable` on both [PyPI](https://pypi.org/project/ramtable/) and
|
|
223
|
+
[TestPyPI](https://test.pypi.org/project/ramtable/). Use PyPI for stable
|
|
224
|
+
releases and TestPyPI to try release candidates and other pre-releases.
|
|
225
|
+
|
|
226
|
+
The project is at an early stage and will continue to evolve. See the
|
|
227
|
+
[CHANGELOG](CHANGELOG.md) for release history.
|
|
228
|
+
|
|
229
|
+
## License
|
|
230
|
+
|
|
231
|
+
RAMTable is distributed under the MIT License. See [LICENSE](LICENSE) for
|
|
232
|
+
the terms.
|