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.
@@ -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,21 @@
1
+ __pycache__/
2
+ *.py[cod]
3
+ *$py.class
4
+ .pyirc
5
+ test_table.py
6
+
7
+ .venv/
8
+ venv/
9
+ env/
10
+
11
+ build/
12
+ dist/
13
+ *.egg-info/
14
+
15
+ .pytest_cache/
16
+ .tox/
17
+ .coverage
18
+ htmlcov/
19
+
20
+ .idea/
21
+ .vscode/
@@ -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.
@@ -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
+ ![Python](https://img.shields.io/badge/python-3.10%2B-blue)
23
+ ![License](https://img.shields.io/badge/license-MIT-green)
24
+ [![PyPI](https://img.shields.io/badge/PyPI-ramtable-blue)](https://pypi.org/project/ramtable/)
25
+ [![TestPyPI](https://img.shields.io/badge/TestPyPI-ramtable-orange)](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.