tinytim 1.12.0__tar.gz → 1.13.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.
Files changed (48) hide show
  1. {tinytim-1.12.0 → tinytim-1.13.0}/PKG-INFO +59 -17
  2. tinytim-1.12.0/src/tinytim.egg-info/PKG-INFO → tinytim-1.13.0/README.md +48 -40
  3. {tinytim-1.12.0 → tinytim-1.13.0}/pyproject.toml +19 -13
  4. {tinytim-1.12.0 → tinytim-1.13.0}/src/tinytim/__init__.py +1 -1
  5. {tinytim-1.12.0 → tinytim-1.13.0}/src/tinytim/columns.py +3 -2
  6. {tinytim-1.12.0 → tinytim-1.13.0}/src/tinytim/copy.py +3 -3
  7. {tinytim-1.12.0 → tinytim-1.13.0}/src/tinytim/custom_types.py +4 -3
  8. {tinytim-1.12.0 → tinytim-1.13.0}/src/tinytim/data.py +7 -13
  9. {tinytim-1.12.0 → tinytim-1.13.0}/src/tinytim/dropna.py +105 -101
  10. {tinytim-1.12.0 → tinytim-1.13.0}/src/tinytim/edit.py +27 -25
  11. {tinytim-1.12.0 → tinytim-1.13.0}/src/tinytim/fillna.py +110 -106
  12. {tinytim-1.12.0 → tinytim-1.13.0}/src/tinytim/filter.py +11 -12
  13. {tinytim-1.12.0 → tinytim-1.13.0}/src/tinytim/group.py +19 -18
  14. {tinytim-1.12.0 → tinytim-1.13.0}/src/tinytim/insert.py +1 -1
  15. {tinytim-1.12.0 → tinytim-1.13.0}/src/tinytim/interfaces.py +9 -3
  16. {tinytim-1.12.0 → tinytim-1.13.0}/src/tinytim/isna.py +6 -5
  17. {tinytim-1.12.0 → tinytim-1.13.0}/src/tinytim/join.py +127 -72
  18. {tinytim-1.12.0 → tinytim-1.13.0}/src/tinytim/json.py +4 -3
  19. {tinytim-1.12.0 → tinytim-1.13.0}/src/tinytim/rows.py +12 -11
  20. {tinytim-1.12.0 → tinytim-1.13.0}/src/tinytim/sequences.py +20 -19
  21. {tinytim-1.12.0 → tinytim-1.13.0}/src/tinytim/utils.py +18 -9
  22. {tinytim-1.12.0 → tinytim-1.13.0}/src/tinytim/validate.py +1 -2
  23. tinytim-1.12.0/README.md → tinytim-1.13.0/src/tinytim.egg-info/PKG-INFO +83 -9
  24. {tinytim-1.12.0 → tinytim-1.13.0}/src/tinytim.egg-info/SOURCES.txt +0 -1
  25. {tinytim-1.12.0 → tinytim-1.13.0}/src/tinytim.egg-info/requires.txt +4 -1
  26. {tinytim-1.12.0 → tinytim-1.13.0}/tests/test_data.py +1 -1
  27. {tinytim-1.12.0 → tinytim-1.13.0}/tests/test_json.py +1 -2
  28. {tinytim-1.12.0 → tinytim-1.13.0}/tests/test_na.py +1 -2
  29. {tinytim-1.12.0 → tinytim-1.13.0}/tests/test_utils.py +2 -3
  30. tinytim-1.12.0/src/tinytim/docs/conf.py +0 -73
  31. {tinytim-1.12.0 → tinytim-1.13.0}/LICENSE.md +0 -0
  32. {tinytim-1.12.0 → tinytim-1.13.0}/setup.cfg +0 -0
  33. {tinytim-1.12.0 → tinytim-1.13.0}/setup.py +0 -0
  34. {tinytim-1.12.0 → tinytim-1.13.0}/src/tinytim/na.py +0 -0
  35. {tinytim-1.12.0 → tinytim-1.13.0}/src/tinytim/py.typed +0 -0
  36. {tinytim-1.12.0 → tinytim-1.13.0}/src/tinytim.egg-info/dependency_links.txt +0 -0
  37. {tinytim-1.12.0 → tinytim-1.13.0}/src/tinytim.egg-info/top_level.txt +0 -0
  38. {tinytim-1.12.0 → tinytim-1.13.0}/tests/test_columns.py +0 -0
  39. {tinytim-1.12.0 → tinytim-1.13.0}/tests/test_copy.py +0 -0
  40. {tinytim-1.12.0 → tinytim-1.13.0}/tests/test_edit.py +0 -0
  41. {tinytim-1.12.0 → tinytim-1.13.0}/tests/test_filter.py +0 -0
  42. {tinytim-1.12.0 → tinytim-1.13.0}/tests/test_group.py +0 -0
  43. {tinytim-1.12.0 → tinytim-1.13.0}/tests/test_insert.py +0 -0
  44. {tinytim-1.12.0 → tinytim-1.13.0}/tests/test_isna.py +0 -0
  45. {tinytim-1.12.0 → tinytim-1.13.0}/tests/test_join.py +0 -0
  46. {tinytim-1.12.0 → tinytim-1.13.0}/tests/test_rows.py +0 -0
  47. {tinytim-1.12.0 → tinytim-1.13.0}/tests/test_sequences.py +0 -0
  48. {tinytim-1.12.0 → tinytim-1.13.0}/tests/test_validate.py +0 -0
@@ -1,53 +1,55 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: tinytim
3
- Version: 1.12.0
3
+ Version: 1.13.0
4
4
  Summary: Pure Python data table functions.
5
5
  Author-email: Odos Matthews <odosmatthews@gmail.com>
6
- License: MIT
6
+ License-Expression: MIT
7
7
  Project-URL: Homepage, https://github.com/eddiethedean/tinytim
8
8
  Project-URL: Repository, https://github.com/eddiethedean/tinytim
9
9
  Project-URL: Issues, https://github.com/eddiethedean/tinytim/issues
10
10
  Keywords: data,table,dataframe,pure-python,lightweight
11
11
  Classifier: Development Status :: 5 - Production/Stable
12
12
  Classifier: Intended Audience :: Developers
13
- Classifier: License :: OSI Approved :: MIT License
14
13
  Classifier: Programming Language :: Python :: 3
15
14
  Classifier: Programming Language :: Python :: 3 :: Only
16
- Classifier: Programming Language :: Python :: 3.8
17
- Classifier: Programming Language :: Python :: 3.9
18
- Classifier: Programming Language :: Python :: 3.10
19
15
  Classifier: Programming Language :: Python :: 3.11
20
16
  Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: Programming Language :: Python :: 3.13
18
+ Classifier: Programming Language :: Python :: 3.14
19
+ Classifier: Programming Language :: Python :: 3.15
21
20
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
22
- Requires-Python: >=3.8
21
+ Requires-Python: >=3.11
23
22
  Description-Content-Type: text/markdown
24
23
  License-File: LICENSE.md
25
- Requires-Dist: hasattrs>=0.0.2
26
24
  Provides-Extra: dev
27
25
  Requires-Dist: pytest>=8.3.0; extra == "dev"
28
26
  Requires-Dist: pytest-cov>=5.0.0; extra == "dev"
29
27
  Requires-Dist: mypy>=1.11.0; extra == "dev"
30
28
  Requires-Dist: ruff>=0.6.0; extra == "dev"
31
29
  Requires-Dist: tox>=4.0.0; extra == "dev"
30
+ Provides-Extra: docs
31
+ Requires-Dist: sphinx>=8.0; extra == "docs"
32
+ Requires-Dist: furo>=2024.8.6; extra == "docs"
33
+ Dynamic: license-file
32
34
 
33
35
  # TinyTim
34
36
 
35
37
  A pure Python package for processing tabular data stored in dictionaries.
36
38
 
37
39
  [![PyPI Latest Release](https://img.shields.io/pypi/v/tinytim.svg)](https://pypi.org/project/tinytim/)
38
- ![Tests](https://github.com/eddiethedean/tinytim/actions/workflows/tests.yml/badge.svg)
40
+ [![Checks](https://github.com/eddiethedean/tinytim/actions/workflows/commit.yml/badge.svg)](https://github.com/eddiethedean/tinytim/actions/workflows/commit.yml)
39
41
  [![Python Version](https://img.shields.io/pypi/pyversions/tinytim.svg)](https://pypi.org/project/tinytim/)
40
42
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
41
43
 
42
44
  ## Description
43
45
 
44
- TinyTim is a lightweight alternative to Pandas for processing tabular data. It's perfect for when you want to work with structured data but don't want to install Pandas and its many dependencies. TinyTim has **zero dependencies** outside of Python's standard library.
46
+ TinyTim provides small, pure-Python tools for working with tabular data when a full dataframe library is more than a project needs. It has **no runtime dependencies** beyond the Python standard library.
45
47
 
46
- Data is stored in a simple dictionary format: `{column_name: column_values}`, making it easy to understand and work with.
48
+ Tables are mappings of column names to sequences of values, such as `{"name": ["Ada", "Lin"], "score": [95, 88]}`. Keep every column the same length; use `tinytim.validate.valid_table_mapping` to check a table. Functions without an `_inplace` suffix return new table data, while their `_inplace` counterparts modify the input.
47
49
 
48
50
  ## Features
49
51
 
50
- - **Zero dependencies** - Pure Python implementation
52
+ - **No runtime dependencies** - Uses only the Python standard library
51
53
  - **Lightweight** - Minimal footprint, fast installation
52
54
  - **Familiar API** - Intuitive functions for data manipulation
53
55
  - **Type hints** - Full type annotations for better IDE support
@@ -61,7 +63,11 @@ pip install tinytim
61
63
 
62
64
  ## Requirements
63
65
 
64
- - Python >= 3.8
66
+ - Python >= 3.11
67
+
68
+ ## Documentation
69
+
70
+ The [Sphinx user guide](src/tinytim/docs/index.rst) covers common operations, and the [API reference](src/tinytim/docs/modules.rst) documents the public modules. Runnable notebooks are available in the [examples](examples/) directory.
65
71
 
66
72
  ## Quick Start
67
73
 
@@ -174,8 +180,18 @@ fillna(data, 0)
174
180
  data2 = {'x': [None, 2, None, 4], 'y': [10, None, None, 40]}
175
181
  fillna(data2, method='ffill')
176
182
  # {'x': [None, 2, 2, 4], 'y': [10, 10, 10, 40]}
183
+
184
+ # Limit each forward-filled gap to one value
185
+ fillna({'x': [1, None, None, 4, None]}, method='ffill', limit=1)
186
+ # {'x': [1, 1, None, 4, 4]}
187
+
188
+ # Get indexes of rows retained by dropna
189
+ dropna(data, remaining=True)
190
+ # [0]
177
191
  ```
178
192
 
193
+ `dropna(..., axis='columns', remaining=True)` returns the names of the retained columns. Missing values default to `None`; pass `na_value` to use another sentinel.
194
+
179
195
  ### Grouping and Aggregation
180
196
 
181
197
  ```python
@@ -209,6 +225,18 @@ result = inner_join(left, right, 'id')
209
225
  # Left join keeps all rows from left table
210
226
  result = left_join(left, right, 'id')
211
227
  # {'id': [1, 2, 3], 'value': ['a', 'b', 'c'], 'score': [None, 10, 20]}
228
+
229
+ # Same-named non-key columns receive suffixes
230
+ left = {'id': [1, 2], 'value': ['a', 'b']}
231
+ right = {'id': [2, 3], 'value': ['c', 'd']}
232
+ result = inner_join(left, right, 'id')
233
+ # {'id': [2], 'value_x': ['b'], 'value_y': ['c']}
234
+
235
+ # Join on multiple columns and choose custom suffixes
236
+ left = {'account': [10, 10], 'year': [2025, 2026], 'amount': [100, 120]}
237
+ right = {'account': [10, 10], 'year': [2025, 2026], 'amount': [95, 125]}
238
+ result = inner_join(left, right, ['account', 'year'], suffixes=('_left', '_right'))
239
+ # The result contains amount_left and amount_right.
212
240
  ```
213
241
 
214
242
  ## More Examples
@@ -235,6 +263,10 @@ result = drop_row(data, 0)
235
263
  # Drop a column
236
264
  result = drop_column(data, 'city')
237
265
  # {'name': ['Alice', 'Bob', 'Charlie'], 'age': [25, 30, 35]}
266
+
267
+ # Add a column to a table in place
268
+ from tinytim.edit import edit_column_inplace
269
+ edit_column_inplace(data, 'active', [True, False, True])
238
270
  ```
239
271
 
240
272
  ### Inserting Data
@@ -310,7 +342,7 @@ git clone https://github.com/eddiethedean/tinytim.git
310
342
  cd tinytim
311
343
 
312
344
  # Install development dependencies
313
- pip install -e ".[dev]"
345
+ pip install -e ".[dev,docs]"
314
346
 
315
347
  # Or use the requirements file
316
348
  pip install -r requirements_dev.txt
@@ -323,7 +355,7 @@ pip install -r requirements_dev.txt
323
355
  pytest
324
356
 
325
357
  # Run tests with coverage
326
- pytest --cov=tinytim
358
+ pytest --cov-report=xml
327
359
 
328
360
  # Run tests across multiple Python versions
329
361
  tox
@@ -340,6 +372,9 @@ ruff format src tests
340
372
 
341
373
  # Type check with mypy
342
374
  mypy src
375
+
376
+ # Build the Sphinx documentation
377
+ python -m sphinx -b html src/tinytim/docs build/docs
343
378
  ```
344
379
 
345
380
  ### Pre-commit Hooks
@@ -360,13 +395,20 @@ See the [examples](https://github.com/eddiethedean/tinytim/tree/main/examples) d
360
395
  - [data.ipynb](https://github.com/eddiethedean/tinytim/blob/main/examples/data.ipynb) - Basic data operations
361
396
  - [rows.ipynb](https://github.com/eddiethedean/tinytim/blob/main/examples/rows.ipynb) - Working with rows
362
397
  - [columns.ipynb](https://github.com/eddiethedean/tinytim/blob/main/examples/columns.ipynb) - Working with columns
398
+ - [edit.ipynb](https://github.com/eddiethedean/tinytim/blob/main/examples/edit.ipynb) - Editing data
363
399
  - [join.ipynb](https://github.com/eddiethedean/tinytim/blob/main/examples/join.ipynb) - Joining datasets
364
400
  - [group.ipynb](https://github.com/eddiethedean/tinytim/blob/main/examples/group.ipynb) - Grouping and aggregation
401
+ - [dropna.ipynb](https://github.com/eddiethedean/tinytim/blob/main/examples/dropna.ipynb) - Dropping missing values
365
402
  - [fillna.ipynb](https://github.com/eddiethedean/tinytim/blob/main/examples/fillna.ipynb) - Handling missing values
403
+ - [json.ipynb](https://github.com/eddiethedean/tinytim/blob/main/examples/json.ipynb) - Reading and writing JSON
366
404
 
367
405
  ## Contributing
368
406
 
369
- Contributions are welcome! Please feel free to submit a Pull Request.
407
+ Contributions are welcome. See [CONTRIBUTING.md](CONTRIBUTING.md) for development, CI, and release instructions.
408
+
409
+ ## Releasing
410
+
411
+ Push a `vX.Y.Z` tag matching the package version to run the release workflow. It checks the code, builds the source and wheel distributions, and publishes them to PyPI using Trusted Publishing. Configure the PyPI publisher as described in [CONTRIBUTING.md](CONTRIBUTING.md).
370
412
 
371
413
  ## Author
372
414
 
@@ -1,53 +1,21 @@
1
- Metadata-Version: 2.1
2
- Name: tinytim
3
- Version: 1.12.0
4
- Summary: Pure Python data table functions.
5
- Author-email: Odos Matthews <odosmatthews@gmail.com>
6
- License: MIT
7
- Project-URL: Homepage, https://github.com/eddiethedean/tinytim
8
- Project-URL: Repository, https://github.com/eddiethedean/tinytim
9
- Project-URL: Issues, https://github.com/eddiethedean/tinytim/issues
10
- Keywords: data,table,dataframe,pure-python,lightweight
11
- Classifier: Development Status :: 5 - Production/Stable
12
- Classifier: Intended Audience :: Developers
13
- Classifier: License :: OSI Approved :: MIT License
14
- Classifier: Programming Language :: Python :: 3
15
- Classifier: Programming Language :: Python :: 3 :: Only
16
- Classifier: Programming Language :: Python :: 3.8
17
- Classifier: Programming Language :: Python :: 3.9
18
- Classifier: Programming Language :: Python :: 3.10
19
- Classifier: Programming Language :: Python :: 3.11
20
- Classifier: Programming Language :: Python :: 3.12
21
- Classifier: Topic :: Software Development :: Libraries :: Python Modules
22
- Requires-Python: >=3.8
23
- Description-Content-Type: text/markdown
24
- License-File: LICENSE.md
25
- Requires-Dist: hasattrs>=0.0.2
26
- Provides-Extra: dev
27
- Requires-Dist: pytest>=8.3.0; extra == "dev"
28
- Requires-Dist: pytest-cov>=5.0.0; extra == "dev"
29
- Requires-Dist: mypy>=1.11.0; extra == "dev"
30
- Requires-Dist: ruff>=0.6.0; extra == "dev"
31
- Requires-Dist: tox>=4.0.0; extra == "dev"
32
-
33
1
  # TinyTim
34
2
 
35
3
  A pure Python package for processing tabular data stored in dictionaries.
36
4
 
37
5
  [![PyPI Latest Release](https://img.shields.io/pypi/v/tinytim.svg)](https://pypi.org/project/tinytim/)
38
- ![Tests](https://github.com/eddiethedean/tinytim/actions/workflows/tests.yml/badge.svg)
6
+ [![Checks](https://github.com/eddiethedean/tinytim/actions/workflows/commit.yml/badge.svg)](https://github.com/eddiethedean/tinytim/actions/workflows/commit.yml)
39
7
  [![Python Version](https://img.shields.io/pypi/pyversions/tinytim.svg)](https://pypi.org/project/tinytim/)
40
8
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
41
9
 
42
10
  ## Description
43
11
 
44
- TinyTim is a lightweight alternative to Pandas for processing tabular data. It's perfect for when you want to work with structured data but don't want to install Pandas and its many dependencies. TinyTim has **zero dependencies** outside of Python's standard library.
12
+ TinyTim provides small, pure-Python tools for working with tabular data when a full dataframe library is more than a project needs. It has **no runtime dependencies** beyond the Python standard library.
45
13
 
46
- Data is stored in a simple dictionary format: `{column_name: column_values}`, making it easy to understand and work with.
14
+ Tables are mappings of column names to sequences of values, such as `{"name": ["Ada", "Lin"], "score": [95, 88]}`. Keep every column the same length; use `tinytim.validate.valid_table_mapping` to check a table. Functions without an `_inplace` suffix return new table data, while their `_inplace` counterparts modify the input.
47
15
 
48
16
  ## Features
49
17
 
50
- - **Zero dependencies** - Pure Python implementation
18
+ - **No runtime dependencies** - Uses only the Python standard library
51
19
  - **Lightweight** - Minimal footprint, fast installation
52
20
  - **Familiar API** - Intuitive functions for data manipulation
53
21
  - **Type hints** - Full type annotations for better IDE support
@@ -61,7 +29,11 @@ pip install tinytim
61
29
 
62
30
  ## Requirements
63
31
 
64
- - Python >= 3.8
32
+ - Python >= 3.11
33
+
34
+ ## Documentation
35
+
36
+ The [Sphinx user guide](src/tinytim/docs/index.rst) covers common operations, and the [API reference](src/tinytim/docs/modules.rst) documents the public modules. Runnable notebooks are available in the [examples](examples/) directory.
65
37
 
66
38
  ## Quick Start
67
39
 
@@ -174,8 +146,18 @@ fillna(data, 0)
174
146
  data2 = {'x': [None, 2, None, 4], 'y': [10, None, None, 40]}
175
147
  fillna(data2, method='ffill')
176
148
  # {'x': [None, 2, 2, 4], 'y': [10, 10, 10, 40]}
149
+
150
+ # Limit each forward-filled gap to one value
151
+ fillna({'x': [1, None, None, 4, None]}, method='ffill', limit=1)
152
+ # {'x': [1, 1, None, 4, 4]}
153
+
154
+ # Get indexes of rows retained by dropna
155
+ dropna(data, remaining=True)
156
+ # [0]
177
157
  ```
178
158
 
159
+ `dropna(..., axis='columns', remaining=True)` returns the names of the retained columns. Missing values default to `None`; pass `na_value` to use another sentinel.
160
+
179
161
  ### Grouping and Aggregation
180
162
 
181
163
  ```python
@@ -209,6 +191,18 @@ result = inner_join(left, right, 'id')
209
191
  # Left join keeps all rows from left table
210
192
  result = left_join(left, right, 'id')
211
193
  # {'id': [1, 2, 3], 'value': ['a', 'b', 'c'], 'score': [None, 10, 20]}
194
+
195
+ # Same-named non-key columns receive suffixes
196
+ left = {'id': [1, 2], 'value': ['a', 'b']}
197
+ right = {'id': [2, 3], 'value': ['c', 'd']}
198
+ result = inner_join(left, right, 'id')
199
+ # {'id': [2], 'value_x': ['b'], 'value_y': ['c']}
200
+
201
+ # Join on multiple columns and choose custom suffixes
202
+ left = {'account': [10, 10], 'year': [2025, 2026], 'amount': [100, 120]}
203
+ right = {'account': [10, 10], 'year': [2025, 2026], 'amount': [95, 125]}
204
+ result = inner_join(left, right, ['account', 'year'], suffixes=('_left', '_right'))
205
+ # The result contains amount_left and amount_right.
212
206
  ```
213
207
 
214
208
  ## More Examples
@@ -235,6 +229,10 @@ result = drop_row(data, 0)
235
229
  # Drop a column
236
230
  result = drop_column(data, 'city')
237
231
  # {'name': ['Alice', 'Bob', 'Charlie'], 'age': [25, 30, 35]}
232
+
233
+ # Add a column to a table in place
234
+ from tinytim.edit import edit_column_inplace
235
+ edit_column_inplace(data, 'active', [True, False, True])
238
236
  ```
239
237
 
240
238
  ### Inserting Data
@@ -310,7 +308,7 @@ git clone https://github.com/eddiethedean/tinytim.git
310
308
  cd tinytim
311
309
 
312
310
  # Install development dependencies
313
- pip install -e ".[dev]"
311
+ pip install -e ".[dev,docs]"
314
312
 
315
313
  # Or use the requirements file
316
314
  pip install -r requirements_dev.txt
@@ -323,7 +321,7 @@ pip install -r requirements_dev.txt
323
321
  pytest
324
322
 
325
323
  # Run tests with coverage
326
- pytest --cov=tinytim
324
+ pytest --cov-report=xml
327
325
 
328
326
  # Run tests across multiple Python versions
329
327
  tox
@@ -340,6 +338,9 @@ ruff format src tests
340
338
 
341
339
  # Type check with mypy
342
340
  mypy src
341
+
342
+ # Build the Sphinx documentation
343
+ python -m sphinx -b html src/tinytim/docs build/docs
343
344
  ```
344
345
 
345
346
  ### Pre-commit Hooks
@@ -360,13 +361,20 @@ See the [examples](https://github.com/eddiethedean/tinytim/tree/main/examples) d
360
361
  - [data.ipynb](https://github.com/eddiethedean/tinytim/blob/main/examples/data.ipynb) - Basic data operations
361
362
  - [rows.ipynb](https://github.com/eddiethedean/tinytim/blob/main/examples/rows.ipynb) - Working with rows
362
363
  - [columns.ipynb](https://github.com/eddiethedean/tinytim/blob/main/examples/columns.ipynb) - Working with columns
364
+ - [edit.ipynb](https://github.com/eddiethedean/tinytim/blob/main/examples/edit.ipynb) - Editing data
363
365
  - [join.ipynb](https://github.com/eddiethedean/tinytim/blob/main/examples/join.ipynb) - Joining datasets
364
366
  - [group.ipynb](https://github.com/eddiethedean/tinytim/blob/main/examples/group.ipynb) - Grouping and aggregation
367
+ - [dropna.ipynb](https://github.com/eddiethedean/tinytim/blob/main/examples/dropna.ipynb) - Dropping missing values
365
368
  - [fillna.ipynb](https://github.com/eddiethedean/tinytim/blob/main/examples/fillna.ipynb) - Handling missing values
369
+ - [json.ipynb](https://github.com/eddiethedean/tinytim/blob/main/examples/json.ipynb) - Reading and writing JSON
366
370
 
367
371
  ## Contributing
368
372
 
369
- Contributions are welcome! Please feel free to submit a Pull Request.
373
+ Contributions are welcome. See [CONTRIBUTING.md](CONTRIBUTING.md) for development, CI, and release instructions.
374
+
375
+ ## Releasing
376
+
377
+ Push a `vX.Y.Z` tag matching the package version to run the release workflow. It checks the code, builds the source and wheel distributions, and publishes them to PyPI using Trusted Publishing. Configure the PyPI publisher as described in [CONTRIBUTING.md](CONTRIBUTING.md).
370
378
 
371
379
  ## Author
372
380
 
@@ -1,34 +1,31 @@
1
1
  [build-system]
2
- requires = ["setuptools>=61.0", "wheel"]
2
+ requires = ["setuptools>=77.0.0", "wheel"]
3
3
  build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "tinytim"
7
- version = "1.12.0"
7
+ version = "1.13.0"
8
8
  description = "Pure Python data table functions."
9
9
  readme = "README.md"
10
10
  authors = [
11
11
  {name = "Odos Matthews", email = "odosmatthews@gmail.com"}
12
12
  ]
13
- license = {text = "MIT"}
13
+ license = "MIT"
14
+ license-files = ["LICENSE.md"]
14
15
  classifiers = [
15
16
  "Development Status :: 5 - Production/Stable",
16
17
  "Intended Audience :: Developers",
17
- "License :: OSI Approved :: MIT License",
18
18
  "Programming Language :: Python :: 3",
19
19
  "Programming Language :: Python :: 3 :: Only",
20
- "Programming Language :: Python :: 3.8",
21
- "Programming Language :: Python :: 3.9",
22
- "Programming Language :: Python :: 3.10",
23
20
  "Programming Language :: Python :: 3.11",
24
21
  "Programming Language :: Python :: 3.12",
22
+ "Programming Language :: Python :: 3.13",
23
+ "Programming Language :: Python :: 3.14",
24
+ "Programming Language :: Python :: 3.15",
25
25
  "Topic :: Software Development :: Libraries :: Python Modules",
26
26
  ]
27
27
  keywords = ["data", "table", "dataframe", "pure-python", "lightweight"]
28
- requires-python = ">=3.8"
29
- dependencies = [
30
- "hasattrs>=0.0.2",
31
- ]
28
+ requires-python = ">=3.11"
32
29
 
33
30
  [project.urls]
34
31
  Homepage = "https://github.com/eddiethedean/tinytim"
@@ -43,16 +40,25 @@ dev = [
43
40
  "ruff>=0.6.0",
44
41
  "tox>=4.0.0",
45
42
  ]
43
+ docs = [
44
+ "sphinx>=8.0",
45
+ "furo>=2024.8.6",
46
+ ]
46
47
 
47
48
  [tool.setuptools]
48
49
  package-dir = {"" = "src"}
49
50
 
50
51
  [tool.setuptools.packages.find]
51
52
  where = ["src"]
53
+ namespaces = false
54
+ exclude = ["tinytim.docs", "tinytim.docs.*"]
52
55
 
53
56
  [tool.setuptools.package-data]
54
57
  tinytim = ["py.typed"]
55
58
 
59
+ [tool.setuptools.exclude-package-data]
60
+ tinytim = ["docs/*"]
61
+
56
62
  [tool.pytest.ini_options]
57
63
  addopts = "--cov=tinytim"
58
64
  testpaths = [
@@ -83,7 +89,7 @@ no_implicit_reexport = true
83
89
 
84
90
  [tool.ruff]
85
91
  line-length = 160
86
- target-version = "py38"
92
+ target-version = "py311"
87
93
  src = ["src", "tests"]
88
94
 
89
95
  [tool.ruff.lint]
@@ -103,4 +109,4 @@ ignore = [
103
109
  ]
104
110
 
105
111
  [tool.ruff.lint.per-file-ignores]
106
- "__init__.py" = ["F401"] # unused imports in __init__.py
112
+ "__init__.py" = ["F401"] # unused imports in __init__.py
@@ -1,4 +1,4 @@
1
- __version__ = '1.12.0'
1
+ __version__ = '1.13.0'
2
2
 
3
3
 
4
4
  import tinytim.columns
@@ -1,6 +1,7 @@
1
1
  """Description: Functions for operating on columns of data."""
2
2
 
3
- from typing import Any, Generator, List, Tuple
3
+ from collections.abc import Generator
4
+ from typing import Any
4
5
 
5
6
  import tinytim.data as data_functions
6
7
  from tinytim.custom_types import DataDict
@@ -53,7 +54,7 @@ def column_mapping(data: GetSequence, col: str) -> DataDict:
53
54
  return {col: data_functions.column_values(data, col)}
54
55
 
55
56
 
56
- def itercolumns(data: KeyNamesGetSequence) -> Generator[Tuple[str, List[Any]], None, None]:
57
+ def itercolumns(data: KeyNamesGetSequence) -> Generator[tuple[str, list[Any]], None, None]:
57
58
  """
58
59
  Return a generator of tuple column name, column values.
59
60
 
@@ -1,5 +1,6 @@
1
1
  import copy
2
- from typing import Any, Sequence, TypeVar
2
+ from collections.abc import Sequence
3
+ from typing import Any, TypeVar
3
4
 
4
5
  from tinytim.custom_types import DataMapping
5
6
 
@@ -50,8 +51,7 @@ def deepcopy_table(data: TypeVarDataMapping) -> TypeVarDataMapping:
50
51
  >>> deepcopy_table(data)
51
52
  {'x': [1, 2, 3], 'y': [6, 7, 8]}
52
53
  """
53
- constructor = type(data)
54
- return constructor({col: copy.deepcopy(values) for col, values in data.items()}) # type: ignore
54
+ return copy.deepcopy(data)
55
55
 
56
56
 
57
57
  def copy_sequence(values: TypeVarSequence) -> TypeVarSequence:
@@ -1,12 +1,13 @@
1
- from typing import Any, Dict, List, Mapping, MutableMapping, MutableSequence, Sequence
1
+ from collections.abc import Mapping, MutableMapping, MutableSequence, Sequence
2
+ from typing import Any
2
3
 
3
4
  from tinytim.interfaces import SequenceItems
4
5
 
5
6
  DataMapping = Mapping[str, Sequence[Any]]
6
7
  MutableDataMapping = MutableMapping[str, MutableSequence[Any]]
7
8
  RowMapping = Mapping[str, Any]
8
- DataDict = Dict[str, List[Any]]
9
- RowDict = Dict[str, Any]
9
+ DataDict = dict[str, list[Any]]
10
+ RowDict = dict[str, Any]
10
11
 
11
12
 
12
13
  def data_dict(m: SequenceItems) -> DataDict:
@@ -1,4 +1,4 @@
1
- from typing import Any, List, Tuple
1
+ from typing import Any
2
2
 
3
3
  from tinytim.custom_types import DataDict
4
4
  from tinytim.interfaces import GetSequence, KeyNames, KeyNamesSequenceValues, SequenceItems, SequenceValues
@@ -76,16 +76,10 @@ def row_count(data: SequenceValues) -> int:
76
76
  >>> row_count(data)
77
77
  3
78
78
  """
79
- try:
80
- return max(len(v) for v in data.values())
81
- except ValueError as e:
82
- if str(e) == "max() arg is an empty sequence":
83
- return 0
84
- else:
85
- raise e
79
+ return max((len(v) for v in data.values()), default=0)
86
80
 
87
81
 
88
- def shape(data: KeyNamesSequenceValues) -> Tuple[int, int]:
82
+ def shape(data: KeyNamesSequenceValues) -> tuple[int, int]:
89
83
  """
90
84
  Return data row count, column count tuple.
91
85
 
@@ -135,7 +129,7 @@ def size(data: KeyNamesSequenceValues) -> int:
135
129
  return rows * columns
136
130
 
137
131
 
138
- def column_names(data: KeyNames) -> List[str]:
132
+ def column_names(data: KeyNames) -> list[str]:
139
133
  """
140
134
  Return data column names.
141
135
 
@@ -206,10 +200,10 @@ def tail(data: SequenceItems, n: int = 5) -> DataDict:
206
200
  >>> tail(data, 2)
207
201
  {'x': [2, 3], 'y': [7, 8]}
208
202
  """
209
- return {k: list(v[-n:]) for k, v in data.items()}
203
+ return {k: list(v[-n:]) if n else [] for k, v in data.items()}
210
204
 
211
205
 
212
- def index(data: SequenceValues) -> Tuple[int, ...]:
206
+ def index(data: SequenceValues) -> tuple[int, ...]:
213
207
  """
214
208
  Return tuple of data column indexes.
215
209
 
@@ -259,7 +253,7 @@ def table_value(data: GetSequence, column_name: str, index: int) -> Any:
259
253
  return data[column_name][index]
260
254
 
261
255
 
262
- def column_values(data: GetSequence, column_name: str) -> List[Any]:
256
+ def column_values(data: GetSequence, column_name: str) -> list[Any]:
263
257
  """
264
258
  Return all the values from one column.
265
259