tinytim 1.11.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 (55) hide show
  1. tinytim-1.13.0/PKG-INFO +429 -0
  2. tinytim-1.13.0/README.md +395 -0
  3. tinytim-1.13.0/pyproject.toml +112 -0
  4. tinytim-1.13.0/setup.py +11 -0
  5. {tinytim-1.11.0 → tinytim-1.13.0/src}/tinytim/__init__.py +4 -4
  6. tinytim-1.13.0/src/tinytim/columns.py +81 -0
  7. {tinytim-1.11.0 → tinytim-1.13.0/src}/tinytim/copy.py +12 -7
  8. tinytim-1.13.0/src/tinytim/custom_types.py +18 -0
  9. {tinytim-1.11.0 → tinytim-1.13.0/src}/tinytim/data.py +40 -39
  10. {tinytim-1.11.0 → tinytim-1.13.0/src}/tinytim/dropna.py +113 -108
  11. {tinytim-1.11.0 → tinytim-1.13.0/src}/tinytim/edit.py +114 -84
  12. {tinytim-1.11.0 → tinytim-1.13.0/src}/tinytim/fillna.py +137 -138
  13. {tinytim-1.11.0 → tinytim-1.13.0/src}/tinytim/filter.py +16 -18
  14. {tinytim-1.11.0 → tinytim-1.13.0/src}/tinytim/group.py +49 -46
  15. {tinytim-1.11.0 → tinytim-1.13.0/src}/tinytim/insert.py +5 -4
  16. tinytim-1.13.0/src/tinytim/interfaces.py +61 -0
  17. {tinytim-1.11.0 → tinytim-1.13.0/src}/tinytim/isna.py +8 -7
  18. {tinytim-1.11.0 → tinytim-1.13.0/src}/tinytim/join.py +202 -149
  19. {tinytim-1.11.0 → tinytim-1.13.0/src}/tinytim/json.py +14 -13
  20. tinytim-1.13.0/src/tinytim/na.py +4 -0
  21. tinytim-1.13.0/src/tinytim/py.typed +0 -0
  22. {tinytim-1.11.0 → tinytim-1.13.0/src}/tinytim/rows.py +44 -43
  23. tinytim-1.11.0/tinytim/columns.py → tinytim-1.13.0/src/tinytim/sequences.py +47 -123
  24. {tinytim-1.11.0 → tinytim-1.13.0/src}/tinytim/utils.py +29 -21
  25. {tinytim-1.11.0 → tinytim-1.13.0/src}/tinytim/validate.py +8 -7
  26. tinytim-1.13.0/src/tinytim.egg-info/PKG-INFO +429 -0
  27. tinytim-1.13.0/src/tinytim.egg-info/SOURCES.txt +45 -0
  28. tinytim-1.13.0/src/tinytim.egg-info/requires.txt +11 -0
  29. tinytim-1.13.0/tests/test_columns.py +16 -0
  30. tinytim-1.13.0/tests/test_copy.py +141 -0
  31. tinytim-1.13.0/tests/test_data.py +135 -0
  32. tinytim-1.13.0/tests/test_edit.py +309 -0
  33. tinytim-1.13.0/tests/test_filter.py +322 -0
  34. tinytim-1.13.0/tests/test_group.py +278 -0
  35. tinytim-1.13.0/tests/test_insert.py +106 -0
  36. tinytim-1.13.0/tests/test_isna.py +260 -0
  37. tinytim-1.13.0/tests/test_join.py +172 -0
  38. tinytim-1.13.0/tests/test_json.py +34 -0
  39. tinytim-1.13.0/tests/test_na.py +634 -0
  40. tinytim-1.13.0/tests/test_rows.py +214 -0
  41. tinytim-1.13.0/tests/test_sequences.py +226 -0
  42. tinytim-1.13.0/tests/test_utils.py +226 -0
  43. tinytim-1.13.0/tests/test_validate.py +67 -0
  44. tinytim-1.11.0/PKG-INFO +0 -51
  45. tinytim-1.11.0/README.md +0 -36
  46. tinytim-1.11.0/setup.py +0 -27
  47. tinytim-1.11.0/tinytim/na.py +0 -3
  48. tinytim-1.11.0/tinytim/types.py +0 -14
  49. tinytim-1.11.0/tinytim.egg-info/PKG-INFO +0 -51
  50. tinytim-1.11.0/tinytim.egg-info/SOURCES.txt +0 -26
  51. tinytim-1.11.0/tinytim.egg-info/requires.txt +0 -2
  52. {tinytim-1.11.0 → tinytim-1.13.0}/LICENSE.md +0 -0
  53. {tinytim-1.11.0 → tinytim-1.13.0}/setup.cfg +0 -0
  54. {tinytim-1.11.0 → tinytim-1.13.0/src}/tinytim.egg-info/dependency_links.txt +0 -0
  55. {tinytim-1.11.0 → tinytim-1.13.0/src}/tinytim.egg-info/top_level.txt +0 -0
@@ -0,0 +1,429 @@
1
+ Metadata-Version: 2.4
2
+ Name: tinytim
3
+ Version: 1.13.0
4
+ Summary: Pure Python data table functions.
5
+ Author-email: Odos Matthews <odosmatthews@gmail.com>
6
+ License-Expression: 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: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3 :: Only
15
+ Classifier: Programming Language :: Python :: 3.11
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
20
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
21
+ Requires-Python: >=3.11
22
+ Description-Content-Type: text/markdown
23
+ License-File: LICENSE.md
24
+ Provides-Extra: dev
25
+ Requires-Dist: pytest>=8.3.0; extra == "dev"
26
+ Requires-Dist: pytest-cov>=5.0.0; extra == "dev"
27
+ Requires-Dist: mypy>=1.11.0; extra == "dev"
28
+ Requires-Dist: ruff>=0.6.0; extra == "dev"
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
34
+
35
+ # TinyTim
36
+
37
+ A pure Python package for processing tabular data stored in dictionaries.
38
+
39
+ [![PyPI Latest Release](https://img.shields.io/pypi/v/tinytim.svg)](https://pypi.org/project/tinytim/)
40
+ [![Checks](https://github.com/eddiethedean/tinytim/actions/workflows/commit.yml/badge.svg)](https://github.com/eddiethedean/tinytim/actions/workflows/commit.yml)
41
+ [![Python Version](https://img.shields.io/pypi/pyversions/tinytim.svg)](https://pypi.org/project/tinytim/)
42
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
43
+
44
+ ## Description
45
+
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.
47
+
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.
49
+
50
+ ## Features
51
+
52
+ - **No runtime dependencies** - Uses only the Python standard library
53
+ - **Lightweight** - Minimal footprint, fast installation
54
+ - **Familiar API** - Intuitive functions for data manipulation
55
+ - **Type hints** - Full type annotations for better IDE support
56
+ - **Well tested** - Comprehensive test suite
57
+
58
+ ## Installation
59
+
60
+ ```bash
61
+ pip install tinytim
62
+ ```
63
+
64
+ ## Requirements
65
+
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.
71
+
72
+ ## Quick Start
73
+
74
+ ### Basic Data Operations
75
+
76
+ ```python
77
+ from tinytim.data import column_count, row_count, shape, head, tail
78
+
79
+ # Data is stored as {column_name: column_values}
80
+ data = {'x': [1, 2, 3, 4], 'y': [10, 20, 30, 40]}
81
+
82
+ # Get basic information
83
+ column_count(data)
84
+ # 2
85
+
86
+ row_count(data)
87
+ # 4
88
+
89
+ shape(data)
90
+ # (4, 2)
91
+
92
+ # Preview data
93
+ head(data, 2)
94
+ # {'x': [1, 2], 'y': [10, 20]}
95
+
96
+ tail(data, 2)
97
+ # {'x': [3, 4], 'y': [30, 40]}
98
+ ```
99
+
100
+ ### Working with Rows
101
+
102
+ ```python
103
+ from tinytim.rows import row_dict, iterrows, row_dicts_to_data
104
+
105
+ data = {'x': [1, 2, 3], 'y': [6, 7, 8]}
106
+
107
+ # Get a single row
108
+ row_dict(data, 1)
109
+ # {'x': 2, 'y': 7}
110
+
111
+ # Iterate over rows
112
+ for index, row in iterrows(data):
113
+ print(f"Row {index}: {row}")
114
+ # Row 0: {'x': 1, 'y': 6}
115
+ # Row 1: {'x': 2, 'y': 7}
116
+ # Row 2: {'x': 3, 'y': 8}
117
+
118
+ # Convert row dictionaries to data
119
+ rows = [{'x': 1, 'y': 20}, {'x': 2, 'y': 21}, {'x': 3, 'y': 22}]
120
+ result = row_dicts_to_data(rows)
121
+ # {'x': [1, 2, 3], 'y': [20, 21, 22]}
122
+ ```
123
+
124
+ ### Working with Columns
125
+
126
+ ```python
127
+ from tinytim.edit import add_to_column, multiply_column
128
+
129
+ data = {'x': [1, 2, 3, 4], 'y': [5, 6, 7, 8]}
130
+
131
+ # Add to a column
132
+ result = add_to_column(data, 'x', 10)
133
+ # {'x': [11, 12, 13, 14], 'y': [5, 6, 7, 8]}
134
+
135
+ # Multiply a column
136
+ result = multiply_column(data, 'x', 2)
137
+ # {'x': [2, 4, 6, 8], 'y': [5, 6, 7, 8]}
138
+
139
+ # Column-wise operations with sequences
140
+ result = add_to_column(data, 'x', [10, 20, 30, 40])
141
+ # {'x': [11, 22, 33, 44], 'y': [5, 6, 7, 8]}
142
+ ```
143
+
144
+ ### Filtering and Selection
145
+
146
+ ```python
147
+ from tinytim.filter import filter_by_column_gt, filter_by_column_isin
148
+
149
+ data = {'x': [1, 2, 3, 4, 5], 'y': [10, 20, 30, 40, 50]}
150
+
151
+ # Filter rows where column value is greater than threshold
152
+ filtered = filter_by_column_gt(data, 'x', 2)
153
+ # {'x': [3, 4, 5], 'y': [30, 40, 50]}
154
+
155
+ # Filter rows where column value is in a list
156
+ filtered = filter_by_column_isin(data, 'x', [1, 3, 5])
157
+ # {'x': [1, 3, 5], 'y': [10, 30, 50]}
158
+ ```
159
+
160
+ ### Handling Missing Values
161
+
162
+ ```python
163
+ from tinytim.na import isna, dropna, fillna
164
+
165
+ data = {'x': [1, None, 3], 'y': [10, 20, None]}
166
+
167
+ # Check for missing values
168
+ isna(data)
169
+ # {'x': [False, True, False], 'y': [False, False, True]}
170
+
171
+ # Drop rows with missing values
172
+ dropna(data)
173
+ # {'x': [1], 'y': [10]}
174
+
175
+ # Fill missing values
176
+ fillna(data, 0)
177
+ # {'x': [1, 0, 3], 'y': [10, 20, 0]}
178
+
179
+ # Forward fill
180
+ data2 = {'x': [None, 2, None, 4], 'y': [10, None, None, 40]}
181
+ fillna(data2, method='ffill')
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]
191
+ ```
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
+
195
+ ### Grouping and Aggregation
196
+
197
+ ```python
198
+ from tinytim.group import groupby, sum_groups
199
+
200
+ data = {'category': ['A', 'B', 'A', 'B'], 'value': [1, 2, 3, 4]}
201
+
202
+ # Group by column
203
+ groups = groupby(data, 'category')
204
+ # [('A', {'category': ['A', 'A'], 'value': [1, 3]}),
205
+ # ('B', {'category': ['B', 'B'], 'value': [2, 4]})]
206
+
207
+ # Sum grouped data
208
+ labels, sums = sum_groups(groups)
209
+ # labels: ['A', 'B']
210
+ # sums: {'value': [4, 6]}
211
+ ```
212
+
213
+ ### Joining Data
214
+
215
+ ```python
216
+ from tinytim.join import inner_join, left_join
217
+
218
+ left = {'id': [1, 2, 3], 'value': ['a', 'b', 'c']}
219
+ right = {'id': [2, 3, 4], 'score': [10, 20, 30]}
220
+
221
+ # Inner join on 'id' column
222
+ result = inner_join(left, right, 'id')
223
+ # {'id': [2, 3], 'value': ['b', 'c'], 'score': [10, 20]}
224
+
225
+ # Left join keeps all rows from left table
226
+ result = left_join(left, right, 'id')
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.
240
+ ```
241
+
242
+ ## More Examples
243
+
244
+ ### Editing Data
245
+
246
+ ```python
247
+ from tinytim.edit import edit_row_items, drop_row, drop_column
248
+
249
+ data = {'name': ['Alice', 'Bob', 'Charlie'],
250
+ 'age': [25, 30, 35],
251
+ 'city': ['NYC', 'LA', 'SF']}
252
+
253
+ # Edit specific row values
254
+ result = edit_row_items(data, 1, {'age': 31, 'city': 'Seattle'})
255
+ # {'name': ['Alice', 'Bob', 'Charlie'],
256
+ # 'age': [25, 31, 35],
257
+ # 'city': ['NYC', 'Seattle', 'SF']}
258
+
259
+ # Drop a row
260
+ result = drop_row(data, 0)
261
+ # {'name': ['Bob', 'Charlie'], 'age': [30, 35], 'city': ['LA', 'SF']}
262
+
263
+ # Drop a column
264
+ result = drop_column(data, 'city')
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])
270
+ ```
271
+
272
+ ### Inserting Data
273
+
274
+ ```python
275
+ from tinytim.insert import insert_row, insert_rows
276
+
277
+ data = {'x': [1, 2], 'y': [10, 20]}
278
+
279
+ # Insert a single row
280
+ result = insert_row(data, {'x': 3, 'y': 30})
281
+ # {'x': [1, 2, 3], 'y': [10, 20, 30]}
282
+
283
+ # Insert multiple rows
284
+ rows = [{'x': 4, 'y': 40}, {'x': 5, 'y': 50}]
285
+ result = insert_rows(data, rows)
286
+ # {'x': [1, 2, 4, 5], 'y': [10, 20, 40, 50]}
287
+ ```
288
+
289
+ ### Advanced Filtering
290
+
291
+ ```python
292
+ from tinytim.filter import (
293
+ filter_by_column_eq,
294
+ filter_by_column_ne,
295
+ filter_by_column_le,
296
+ sample
297
+ )
298
+
299
+ data = {'product': ['A', 'B', 'A', 'C', 'B'],
300
+ 'price': [10, 20, 15, 30, 25]}
301
+
302
+ # Filter by equality
303
+ result = filter_by_column_eq(data, 'product', 'A')
304
+ # {'product': ['A', 'A'], 'price': [10, 15]}
305
+
306
+ # Filter by inequality
307
+ result = filter_by_column_ne(data, 'product', 'A')
308
+ # {'product': ['B', 'C', 'B'], 'price': [20, 30, 25]}
309
+
310
+ # Filter by less than or equal
311
+ result = filter_by_column_le(data, 'price', 20)
312
+ # {'product': ['A', 'B', 'A'], 'price': [10, 20, 15]}
313
+
314
+ # Random sample
315
+ result = sample(data, 2, random_state=42)
316
+ # Returns 2 random rows (deterministic with random_state)
317
+ ```
318
+
319
+ ### Copying Data
320
+
321
+ ```python
322
+ from tinytim.copy import copy_table, deepcopy_table
323
+
324
+ data = {'x': [1, 2, 3], 'y': [[10], [20], [30]]}
325
+
326
+ # Shallow copy (copies dict and lists)
327
+ copy1 = copy_table(data)
328
+
329
+ # Deep copy (copies everything recursively)
330
+ copy2 = deepcopy_table(data)
331
+ copy2['y'][0][0] = 999
332
+ # Original data unchanged: data['y'][0][0] == 10
333
+ ```
334
+
335
+ ## Development
336
+
337
+ ### Setting up a development environment
338
+
339
+ ```bash
340
+ # Clone the repository
341
+ git clone https://github.com/eddiethedean/tinytim.git
342
+ cd tinytim
343
+
344
+ # Install development dependencies
345
+ pip install -e ".[dev,docs]"
346
+
347
+ # Or use the requirements file
348
+ pip install -r requirements_dev.txt
349
+ ```
350
+
351
+ ### Running Tests
352
+
353
+ ```bash
354
+ # Run tests with pytest
355
+ pytest
356
+
357
+ # Run tests with coverage
358
+ pytest --cov-report=xml
359
+
360
+ # Run tests across multiple Python versions
361
+ tox
362
+ ```
363
+
364
+ ### Linting and Type Checking
365
+
366
+ ```bash
367
+ # Lint with ruff
368
+ ruff check src tests
369
+
370
+ # Format code with ruff
371
+ ruff format src tests
372
+
373
+ # Type check with mypy
374
+ mypy src
375
+
376
+ # Build the Sphinx documentation
377
+ python -m sphinx -b html src/tinytim/docs build/docs
378
+ ```
379
+
380
+ ### Pre-commit Hooks
381
+
382
+ ```bash
383
+ # Install pre-commit hooks
384
+ pip install pre-commit
385
+ pre-commit install
386
+
387
+ # Run hooks manually
388
+ pre-commit run --all-files
389
+ ```
390
+
391
+ ## Examples
392
+
393
+ See the [examples](https://github.com/eddiethedean/tinytim/tree/main/examples) directory for Jupyter notebooks demonstrating various features:
394
+
395
+ - [data.ipynb](https://github.com/eddiethedean/tinytim/blob/main/examples/data.ipynb) - Basic data operations
396
+ - [rows.ipynb](https://github.com/eddiethedean/tinytim/blob/main/examples/rows.ipynb) - Working with rows
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
399
+ - [join.ipynb](https://github.com/eddiethedean/tinytim/blob/main/examples/join.ipynb) - Joining datasets
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
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
404
+
405
+ ## Contributing
406
+
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).
412
+
413
+ ## Author
414
+
415
+ **Odos Matthews** - [odosmatthews@gmail.com](mailto:odosmatthews@gmail.com)
416
+
417
+ ## License
418
+
419
+ This project is licensed under the MIT License - see the [LICENSE.md](https://github.com/eddiethedean/tinytim/blob/main/LICENSE.md) file for details.
420
+
421
+ ## Why TinyTim?
422
+
423
+ TinyTim is ideal for:
424
+
425
+ - **Embedded systems** or environments with limited resources
426
+ - **Lambda functions** or serverless applications where package size matters
427
+ - **Learning** data manipulation concepts without the complexity of Pandas
428
+ - **Scripts** where you need basic data operations without heavy dependencies
429
+ - **Distribution** of tools where you want to minimize user installation burden