TSVZ 4.7__tar.gz → 4.8__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.
- {tsvz-4.7 → tsvz-4.8}/PKG-INFO +3 -3
- {tsvz-4.7 → tsvz-4.8}/README.md +2 -2
- {tsvz-4.7 → tsvz-4.8}/TSVZ.egg-info/PKG-INFO +3 -3
- {tsvz-4.7 → tsvz-4.8}/TSVZ.py +23 -11
- {tsvz-4.7 → tsvz-4.8}/TSVZ.egg-info/SOURCES.txt +0 -0
- {tsvz-4.7 → tsvz-4.8}/TSVZ.egg-info/dependency_links.txt +0 -0
- {tsvz-4.7 → tsvz-4.8}/TSVZ.egg-info/entry_points.txt +0 -0
- {tsvz-4.7 → tsvz-4.8}/TSVZ.egg-info/requires.txt +0 -0
- {tsvz-4.7 → tsvz-4.8}/TSVZ.egg-info/top_level.txt +0 -0
- {tsvz-4.7 → tsvz-4.8}/setup.cfg +0 -0
- {tsvz-4.7 → tsvz-4.8}/setup.py +0 -0
{tsvz-4.7 → tsvz-4.8}/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: TSVZ
|
|
3
|
-
Version: 4.
|
|
3
|
+
Version: 4.8
|
|
4
4
|
Summary: Key-value store kept in a TSV / CSV / NSV / PSV file, with tsvz-spec-v1 support
|
|
5
5
|
Home-page: https://github.com/yufei-pan/TSVZ
|
|
6
6
|
Author: Yufei Pan
|
|
@@ -34,7 +34,7 @@ key-value store in a delimiter-separated text file**. The first column of each
|
|
|
34
34
|
row is the key; the file behaves like an ordered dictionary that is persisted to
|
|
35
35
|
disk as you change it.
|
|
36
36
|
|
|
37
|
-
**Version 4.
|
|
37
|
+
**Version 4.8**, Python **3.6+**, one self-contained module (`TSVZ.py`): drop it
|
|
38
38
|
next to your code and `import TSVZ`, or install it.
|
|
39
39
|
|
|
40
40
|
```bash
|
|
@@ -258,7 +258,7 @@ and `-d=,`, except the ones C5 and C9 list.
|
|
|
258
258
|
| C3 | `read` and `scrub` of a missing store exit 1 with a message (3.39: exit 0, and `read` printed "File not found" on stdout). |
|
|
259
259
|
| C4 | `delete` deletes every KEY it is given (3.39: only the first). |
|
|
260
260
|
| C5 | `append` or `delete` without a KEY, or with an empty KEY, is a usage error with exit 2 (3.39 wrote an empty line). |
|
|
261
|
-
| C6 | A `clear` or `scrub` that writes nothing (one part of a multi-part store, a store that kept changing) exits 1. |
|
|
261
|
+
| C6 | A `clear` or `scrub` that writes nothing (one part of a multi-part store, a store that kept changing, a part that declares a spec version newer than 1, per spec §19.4 and §19.8) exits 1. |
|
|
262
262
|
| C7 | `-c/--header`, `--defaults`, `-s/--strict` and `-f/--force` are undocumented aliases of the `--x-` options. `--x-header` and `--x-defaults` keep non-ASCII text. |
|
|
263
263
|
| C8 | Usage errors print tsvz's own message, exit 2; the `-h` text is new. |
|
|
264
264
|
| C9 | Arguments after STORE for `read`, `clear` and `scrub` are a usage error, exit 2 (3.39 ignored them, so `clear junk` cleared the file). |
|
{tsvz-4.7 → tsvz-4.8}/README.md
RENAMED
|
@@ -7,7 +7,7 @@ key-value store in a delimiter-separated text file**. The first column of each
|
|
|
7
7
|
row is the key; the file behaves like an ordered dictionary that is persisted to
|
|
8
8
|
disk as you change it.
|
|
9
9
|
|
|
10
|
-
**Version 4.
|
|
10
|
+
**Version 4.8**, Python **3.6+**, one self-contained module (`TSVZ.py`): drop it
|
|
11
11
|
next to your code and `import TSVZ`, or install it.
|
|
12
12
|
|
|
13
13
|
```bash
|
|
@@ -231,7 +231,7 @@ and `-d=,`, except the ones C5 and C9 list.
|
|
|
231
231
|
| C3 | `read` and `scrub` of a missing store exit 1 with a message (3.39: exit 0, and `read` printed "File not found" on stdout). |
|
|
232
232
|
| C4 | `delete` deletes every KEY it is given (3.39: only the first). |
|
|
233
233
|
| C5 | `append` or `delete` without a KEY, or with an empty KEY, is a usage error with exit 2 (3.39 wrote an empty line). |
|
|
234
|
-
| C6 | A `clear` or `scrub` that writes nothing (one part of a multi-part store, a store that kept changing) exits 1. |
|
|
234
|
+
| C6 | A `clear` or `scrub` that writes nothing (one part of a multi-part store, a store that kept changing, a part that declares a spec version newer than 1, per spec §19.4 and §19.8) exits 1. |
|
|
235
235
|
| C7 | `-c/--header`, `--defaults`, `-s/--strict` and `-f/--force` are undocumented aliases of the `--x-` options. `--x-header` and `--x-defaults` keep non-ASCII text. |
|
|
236
236
|
| C8 | Usage errors print tsvz's own message, exit 2; the `-h` text is new. |
|
|
237
237
|
| C9 | Arguments after STORE for `read`, `clear` and `scrub` are a usage error, exit 2 (3.39 ignored them, so `clear junk` cleared the file). |
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: TSVZ
|
|
3
|
-
Version: 4.
|
|
3
|
+
Version: 4.8
|
|
4
4
|
Summary: Key-value store kept in a TSV / CSV / NSV / PSV file, with tsvz-spec-v1 support
|
|
5
5
|
Home-page: https://github.com/yufei-pan/TSVZ
|
|
6
6
|
Author: Yufei Pan
|
|
@@ -34,7 +34,7 @@ key-value store in a delimiter-separated text file**. The first column of each
|
|
|
34
34
|
row is the key; the file behaves like an ordered dictionary that is persisted to
|
|
35
35
|
disk as you change it.
|
|
36
36
|
|
|
37
|
-
**Version 4.
|
|
37
|
+
**Version 4.8**, Python **3.6+**, one self-contained module (`TSVZ.py`): drop it
|
|
38
38
|
next to your code and `import TSVZ`, or install it.
|
|
39
39
|
|
|
40
40
|
```bash
|
|
@@ -258,7 +258,7 @@ and `-d=,`, except the ones C5 and C9 list.
|
|
|
258
258
|
| C3 | `read` and `scrub` of a missing store exit 1 with a message (3.39: exit 0, and `read` printed "File not found" on stdout). |
|
|
259
259
|
| C4 | `delete` deletes every KEY it is given (3.39: only the first). |
|
|
260
260
|
| C5 | `append` or `delete` without a KEY, or with an empty KEY, is a usage error with exit 2 (3.39 wrote an empty line). |
|
|
261
|
-
| C6 | A `clear` or `scrub` that writes nothing (one part of a multi-part store, a store that kept changing) exits 1. |
|
|
261
|
+
| C6 | A `clear` or `scrub` that writes nothing (one part of a multi-part store, a store that kept changing, a part that declares a spec version newer than 1, per spec §19.4 and §19.8) exits 1. |
|
|
262
262
|
| C7 | `-c/--header`, `--defaults`, `-s/--strict` and `-f/--force` are undocumented aliases of the `--x-` options. `--x-header` and `--x-defaults` keep non-ASCII text. |
|
|
263
263
|
| C8 | Usage errors print tsvz's own message, exit 2; the `-h` text is new. |
|
|
264
264
|
| C9 | Arguments after STORE for `read`, `clear` and `scrub` are a usage error, exit 2 (3.39 ignored them, so `clear junk` cleared the file). |
|
{tsvz-4.7 → tsvz-4.8}/TSVZ.py
RENAMED
|
@@ -40,10 +40,10 @@ if os.name == 'nt':
|
|
|
40
40
|
elif os.name == 'posix':
|
|
41
41
|
import fcntl
|
|
42
42
|
|
|
43
|
-
version = '4.
|
|
43
|
+
version = '4.8'
|
|
44
44
|
__version__ = version
|
|
45
45
|
author = 'pan@zopyr.us'
|
|
46
|
-
COMMIT_DATE = '2026-10-
|
|
46
|
+
COMMIT_DATE = '2026-10-14'
|
|
47
47
|
|
|
48
48
|
DEFAULT_DELIMITER = '\t'
|
|
49
49
|
DEFAULTS_INDICATOR_KEY = '#_defaults_#'
|
|
@@ -1608,7 +1608,7 @@ _MARKER_RE = re.compile(r'^#_[A-Za-z0-9_-]+_#$')
|
|
|
1608
1608
|
#: What a lookup gets for a key that is not live (spec §20.2.7: then the stripped key is tried).
|
|
1609
1609
|
_NO_ROW = object()
|
|
1610
1610
|
_CHECKSUM_RE = re.compile(r'^#_checksum_([A-Za-z0-9_-]+)_#$', re.IGNORECASE)
|
|
1611
|
-
_ASCII_DIGITS_RE = re.compile(r'^[0-9]
|
|
1611
|
+
_ASCII_DIGITS_RE = re.compile(r'^[0-9]+\Z') # \Z: '$' would also match before a final newline
|
|
1612
1612
|
_SPEC_DECODE_RE = re.compile(r'<(?:sep|LF|CR|NUL|lt|#)>')
|
|
1613
1613
|
_SPEC_TOKENS = {'<LF>': '\n', '<CR>': '\r', '<NUL>': '\0', '<lt>': '<', '<#>': '#'}
|
|
1614
1614
|
_RowState = namedtuple('_RowState', 'defaults strip fillEmpty')
|
|
@@ -1742,6 +1742,7 @@ class _SpecState(object):
|
|
|
1742
1742
|
|
|
1743
1743
|
def __init__(self, defaults=None):
|
|
1744
1744
|
self.version = 1
|
|
1745
|
+
self.newestVersion = 1 # the highest version a #_version_# line declared (spec §19.4, §19.8)
|
|
1745
1746
|
self.defaults = list(defaults) if defaults and len(defaults) > 1 else [DEFAULTS_INDICATOR_KEY]
|
|
1746
1747
|
self.strip = True
|
|
1747
1748
|
self.fillEmpty = False
|
|
@@ -1786,16 +1787,17 @@ def _specApplyMarker(state, keyLower, values, reporter, where):
|
|
|
1786
1787
|
else:
|
|
1787
1788
|
number = 0
|
|
1788
1789
|
if _ASCII_DIGITS_RE.match(value):
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
pass
|
|
1790
|
+
digits = value.lstrip('0') or '0'
|
|
1791
|
+
# int() refuses very long values (Python 3.11+); any such value is above every implemented version.
|
|
1792
|
+
number = int(digits) if len(digits) <= 64 else MAX_SPEC_VERSION + 1
|
|
1793
1793
|
if number < 1:
|
|
1794
1794
|
reporter.note('bad-marker', where, 'ignored #_version_# with invalid value {!r}'.format(value))
|
|
1795
1795
|
return False
|
|
1796
1796
|
if number > MAX_SPEC_VERSION:
|
|
1797
|
-
|
|
1797
|
+
shown = value if len(value) <= 20 else '{}… ({} digits)'.format(value[:20], len(value))
|
|
1798
|
+
reporter.note('newer-version', where, 'declares spec version {}; read as version {}'.format(shown, MAX_SPEC_VERSION))
|
|
1798
1799
|
state.version = number
|
|
1800
|
+
state.newestVersion = max(state.newestVersion, number)
|
|
1799
1801
|
elif keyLower in _BOOL_MARKERS:
|
|
1800
1802
|
attr, default = _BOOL_MARKERS[keyLower]
|
|
1801
1803
|
if not value:
|
|
@@ -3040,7 +3042,8 @@ def _specClearTabularFile(fileName, teeLogger=None, header='', verifyHeader=Fals
|
|
|
3040
3042
|
A single file is read without a lock and rewritten in place only if no
|
|
3041
3043
|
other writer changed it since the read (else it is read again, up to
|
|
3042
3044
|
``_SPEC_REWRITE_ATTEMPTS`` times). A path naming one part of a multi-part
|
|
3043
|
-
store is refused
|
|
3045
|
+
store is refused, and so is a single file declaring a spec version newer
|
|
3046
|
+
than ``MAX_SPEC_VERSION``.
|
|
3044
3047
|
"""
|
|
3045
3048
|
reporter = _Reporter(fileName, teeLogger)
|
|
3046
3049
|
attempt = None
|
|
@@ -3074,6 +3077,10 @@ def _specClearTabularFile(fileName, teeLogger=None, header='', verifyHeader=Fals
|
|
|
3074
3077
|
break
|
|
3075
3078
|
if stamp is None or load.parts != parts:
|
|
3076
3079
|
continue # the set of parts changed under the read
|
|
3080
|
+
if load.state.newestVersion > MAX_SPEC_VERSION:
|
|
3081
|
+
attempt.note('refused', None, 'clear skipped: the part declares a spec version newer than {} (#_version_#), whose '
|
|
3082
|
+
'markers this TSVZ cannot keep (spec §19.8); nothing was written'.format(MAX_SPEC_VERSION))
|
|
3083
|
+
return False
|
|
3077
3084
|
if any(header) and verifyHeader and load.headerLine is not None and not headerChecked:
|
|
3078
3085
|
headerChecked = True
|
|
3079
3086
|
if not _lineContainHeader(header, load.headerLine[1:], verbose=verbose, teeLogger=teeLogger, strict=strict, delimiter=delimiter):
|
|
@@ -3156,8 +3163,8 @@ def _specScrub(fileName, teeLogger=None, header='', createIfNotExist=False, veri
|
|
|
3156
3163
|
writer changed it since the read (else it is read again, up to
|
|
3157
3164
|
``_SPEC_REWRITE_ATTEMPTS`` times), so a record committed meanwhile is
|
|
3158
3165
|
never compacted away. ``done`` is False when nothing was written because
|
|
3159
|
-
the store is missing, has several parts (or the path names one part),
|
|
3160
|
-
kept changing. It is None when the read stopped at damaged data (spec
|
|
3166
|
+
the store is missing, has several parts (or the path names one part),
|
|
3167
|
+
declares a spec version newer than ``MAX_SPEC_VERSION``, or kept changing. It is None when the read stopped at damaged data (spec
|
|
3161
3168
|
§4.10): the part was rewritten from what was read, the original kept.
|
|
3162
3169
|
"""
|
|
3163
3170
|
if taskDic is None:
|
|
@@ -3193,6 +3200,11 @@ def _specScrub(fileName, teeLogger=None, header='', createIfNotExist=False, veri
|
|
|
3193
3200
|
return taskDic, False
|
|
3194
3201
|
if stamp is None or load.parts != parts:
|
|
3195
3202
|
continue # the set of parts changed under the read
|
|
3203
|
+
if load.state.newestVersion > MAX_SPEC_VERSION:
|
|
3204
|
+
attempt.note('refused', None, 'scrub skipped: the store declares a spec version newer than {0} (#_version_#), which '
|
|
3205
|
+
'this TSVZ reads as version {0} only (spec §6.3); a rewrite would make that reading permanent; '
|
|
3206
|
+
'nothing was written'.format(MAX_SPEC_VERSION))
|
|
3207
|
+
return taskDic, False
|
|
3196
3208
|
info = load.infos[0]
|
|
3197
3209
|
if (info.lost or info.damaged) and backedUp != stamp:
|
|
3198
3210
|
# Damaged data is not in what is written, or only unverified (spec §4.10, §16.6): keep the original
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tsvz-4.7 → tsvz-4.8}/setup.cfg
RENAMED
|
File without changes
|
{tsvz-4.7 → tsvz-4.8}/setup.py
RENAMED
|
File without changes
|