json-shaper-lite 1.0.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.
@@ -0,0 +1,11 @@
1
+ # Changelog
2
+
3
+ What changed in json-shaper-lite, newest first.
4
+
5
+ ## 1.0.0 - 2026-11-04
6
+
7
+ - First release.
8
+ - Turns `key: value` notes, CSV/TSV and Markdown tables into JSON. Numbers, yes/no and empty values get the right type.
9
+ - `--json` gives one clean object for scripts and AI agents. `--quiet` hides the tip line.
10
+ - You can install it from PyPI with `pip install json-shaper-lite`.
11
+ - Needs Python 3.10 or newer.
@@ -0,0 +1,9 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 tidybyte
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
6
+
7
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
8
+
9
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,2 @@
1
+ include CHANGELOG.md
2
+ include llms.txt
@@ -0,0 +1,133 @@
1
+ Metadata-Version: 2.4
2
+ Name: json-shaper-lite
3
+ Version: 1.0.0
4
+ Summary: Turn key: value notes, CSV/TSV and Markdown tables into clean, typed JSON. No dependencies.
5
+ Author: Tidy Byte Tools
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://tidybyte.gumroad.com/l/cznmeo
8
+ Project-URL: Source, https://github.com/tidybytetools/json-shaper-lite
9
+ Project-URL: Issues, https://github.com/tidybytetools/json-shaper-lite/issues
10
+ Project-URL: Changelog, https://github.com/tidybytetools/json-shaper-lite/blob/main/CHANGELOG.md
11
+ Keywords: json,csv,tsv,markdown,markdown-table,converter,text-to-json,cli
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Environment :: Console
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: Intended Audience :: End Users/Desktop
16
+ Classifier: Operating System :: OS Independent
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Programming Language :: Python :: 3 :: Only
19
+ Classifier: Programming Language :: Python :: 3.10
20
+ Classifier: Programming Language :: Python :: 3.11
21
+ Classifier: Programming Language :: Python :: 3.12
22
+ Classifier: Programming Language :: Python :: 3.13
23
+ Classifier: Topic :: Text Processing
24
+ Classifier: Topic :: Utilities
25
+ Requires-Python: >=3.10
26
+ Description-Content-Type: text/markdown
27
+ License-File: LICENSE
28
+ Dynamic: license-file
29
+
30
+ # json-shaper-lite
31
+
32
+ [![License: MIT](https://img.shields.io/badge/license-MIT-green.svg)](https://github.com/tidybytetools/json-shaper-lite/blob/main/LICENSE)
33
+ [![Python 3.10+](https://img.shields.io/badge/python-3.10%2B-blue.svg)](https://www.python.org/)
34
+ [![No dependencies](https://img.shields.io/badge/dependencies-none-brightgreen.svg)](https://github.com/tidybytetools/json-shaper-lite/blob/main/json_shaper_lite.py)
35
+
36
+ Free tool that turns `key: value` notes, CSV/TSV and Markdown tables into clean JSON.
37
+ Need app logs or US addresses parsed too? The paid version does that: **[json-shaper on Gumroad](https://tidybyte.gumroad.com/l/cznmeo)**
38
+
39
+ One Python file, no dependencies, MIT license. Works with Python 3.10 and newer, on Windows, Mac and Linux.
40
+
41
+ ## Install
42
+
43
+ ```
44
+ pip install json-shaper-lite
45
+ ```
46
+
47
+ Or use pipx, which keeps it in its own space:
48
+
49
+ ```
50
+ pipx install json-shaper-lite
51
+ ```
52
+
53
+ Want the newest code from GitHub instead?
54
+
55
+ ```
56
+ pip install git+https://github.com/tidybytetools/json-shaper-lite
57
+ ```
58
+
59
+ Or just download `json_shaper_lite.py` and run it with `python3`.
60
+
61
+ ## Use it
62
+
63
+ ```
64
+ printf 'Name: Ada\nAge: 36\nActive: yes' | json-shaper-lite
65
+ json-shaper-lite export.csv
66
+ json-shaper-lite notes.md --format markdown
67
+ json-shaper-lite export.csv --json # {"ok": true, "format": "csv", "data": [...]}
68
+ ```
69
+
70
+ Output:
71
+
72
+ ```json
73
+ {"name": "Ada", "age": 36, "active": true}
74
+ ```
75
+
76
+ Numbers come out as numbers, yes/no and true/false as booleans, and empty or "null" as null. The format is detected for you, or you can set it with `--format kv|csv|markdown`.
77
+
78
+ From Python:
79
+
80
+ ```python
81
+ from json_shaper_lite import shape
82
+ shape("x,y\n1,2") # {'format': 'csv', 'data': [{'x': 1, 'y': 2}]}
83
+ ```
84
+
85
+ When you run it in a terminal it prints one short line about the paid version to stderr after the result. It never goes into your JSON output, it only shows when you are looking at a terminal, and `--quiet` turns it off.
86
+
87
+ ## Known limits
88
+
89
+ - **It makes flat JSON.** It does not flatten or unflatten nested JSON. For that, use a tool like flatten-json.
90
+ - **Types are a best guess.** A value like `007` or a zip code can turn into a number. Fix those by hand after.
91
+ - **One table per run.** Two Markdown tables in one file get mixed together. Split them first.
92
+ - **No app logs or addresses.** Those are in the paid version.
93
+
94
+ ## How it compares to other free tools
95
+
96
+ | | json-shaper-lite | [flatten-json](https://pypi.org/project/flatten-json/) | csvkit `csvjson` | pandas |
97
+ |---|---|---|---|---|
98
+ | Main job | messy text → JSON | nested JSON → flat (and back) | CSV → JSON | full data toolkit |
99
+ | Install size | one file, no deps | small | medium | large |
100
+ | `key: value` notes | yes | no | no | no |
101
+ | Markdown tables | yes | no | no | no, not built in |
102
+ | CSV/TSV | yes | no | yes | yes |
103
+ | Guesses numbers and true/false | yes | no | yes | yes |
104
+ | Nested JSON flatten/unflatten | no | yes | no | yes (`json_normalize`) |
105
+
106
+ If your data is already JSON and just too nested, flatten-json is the better pick.
107
+
108
+ ## For AI agents
109
+
110
+ - **Use when:** you have plain text in `key: value` lines, CSV/TSV, or a Markdown table and need typed JSON.
111
+ - **Don't use when:** the input is already JSON, it's app logs, or it's nested data. Use the paid version for logs.
112
+ - **Input:** text on stdin or a file path. Optional `--format kv|csv|markdown`.
113
+ - **Output:** with `--json`, one object: `{"ok": true, "format": "csv", "data": [...]}`. On error `ok` is false. Exit code 0 ok, 1 error.
114
+ - Hint lines go to stderr only, and only in a terminal, so stdout is always clean JSON. See also [`llms.txt`](https://github.com/tidybytetools/json-shaper-lite/blob/main/llms.txt).
115
+
116
+ ## Lite vs paid
117
+
118
+ | | lite (free) | [json-shaper](https://tidybyte.gumroad.com/l/cznmeo) |
119
+ |---|---|---|
120
+ | key: value notes, CSV/TSV, Markdown tables | yes | yes |
121
+ | App logs (timestamp, level, message, key=value fields) | no | yes |
122
+ | One-line US address splitter | no | yes |
123
+ | `tool.json` manifest for scripts and AI agents | no | yes |
124
+
125
+ ## Tests
126
+
127
+ ```
128
+ python3 -m unittest discover tests
129
+ ```
130
+
131
+ ## License
132
+
133
+ MIT. See `LICENSE`.
@@ -0,0 +1,104 @@
1
+ # json-shaper-lite
2
+
3
+ [![License: MIT](https://img.shields.io/badge/license-MIT-green.svg)](https://github.com/tidybytetools/json-shaper-lite/blob/main/LICENSE)
4
+ [![Python 3.10+](https://img.shields.io/badge/python-3.10%2B-blue.svg)](https://www.python.org/)
5
+ [![No dependencies](https://img.shields.io/badge/dependencies-none-brightgreen.svg)](https://github.com/tidybytetools/json-shaper-lite/blob/main/json_shaper_lite.py)
6
+
7
+ Free tool that turns `key: value` notes, CSV/TSV and Markdown tables into clean JSON.
8
+ Need app logs or US addresses parsed too? The paid version does that: **[json-shaper on Gumroad](https://tidybyte.gumroad.com/l/cznmeo)**
9
+
10
+ One Python file, no dependencies, MIT license. Works with Python 3.10 and newer, on Windows, Mac and Linux.
11
+
12
+ ## Install
13
+
14
+ ```
15
+ pip install json-shaper-lite
16
+ ```
17
+
18
+ Or use pipx, which keeps it in its own space:
19
+
20
+ ```
21
+ pipx install json-shaper-lite
22
+ ```
23
+
24
+ Want the newest code from GitHub instead?
25
+
26
+ ```
27
+ pip install git+https://github.com/tidybytetools/json-shaper-lite
28
+ ```
29
+
30
+ Or just download `json_shaper_lite.py` and run it with `python3`.
31
+
32
+ ## Use it
33
+
34
+ ```
35
+ printf 'Name: Ada\nAge: 36\nActive: yes' | json-shaper-lite
36
+ json-shaper-lite export.csv
37
+ json-shaper-lite notes.md --format markdown
38
+ json-shaper-lite export.csv --json # {"ok": true, "format": "csv", "data": [...]}
39
+ ```
40
+
41
+ Output:
42
+
43
+ ```json
44
+ {"name": "Ada", "age": 36, "active": true}
45
+ ```
46
+
47
+ Numbers come out as numbers, yes/no and true/false as booleans, and empty or "null" as null. The format is detected for you, or you can set it with `--format kv|csv|markdown`.
48
+
49
+ From Python:
50
+
51
+ ```python
52
+ from json_shaper_lite import shape
53
+ shape("x,y\n1,2") # {'format': 'csv', 'data': [{'x': 1, 'y': 2}]}
54
+ ```
55
+
56
+ When you run it in a terminal it prints one short line about the paid version to stderr after the result. It never goes into your JSON output, it only shows when you are looking at a terminal, and `--quiet` turns it off.
57
+
58
+ ## Known limits
59
+
60
+ - **It makes flat JSON.** It does not flatten or unflatten nested JSON. For that, use a tool like flatten-json.
61
+ - **Types are a best guess.** A value like `007` or a zip code can turn into a number. Fix those by hand after.
62
+ - **One table per run.** Two Markdown tables in one file get mixed together. Split them first.
63
+ - **No app logs or addresses.** Those are in the paid version.
64
+
65
+ ## How it compares to other free tools
66
+
67
+ | | json-shaper-lite | [flatten-json](https://pypi.org/project/flatten-json/) | csvkit `csvjson` | pandas |
68
+ |---|---|---|---|---|
69
+ | Main job | messy text → JSON | nested JSON → flat (and back) | CSV → JSON | full data toolkit |
70
+ | Install size | one file, no deps | small | medium | large |
71
+ | `key: value` notes | yes | no | no | no |
72
+ | Markdown tables | yes | no | no | no, not built in |
73
+ | CSV/TSV | yes | no | yes | yes |
74
+ | Guesses numbers and true/false | yes | no | yes | yes |
75
+ | Nested JSON flatten/unflatten | no | yes | no | yes (`json_normalize`) |
76
+
77
+ If your data is already JSON and just too nested, flatten-json is the better pick.
78
+
79
+ ## For AI agents
80
+
81
+ - **Use when:** you have plain text in `key: value` lines, CSV/TSV, or a Markdown table and need typed JSON.
82
+ - **Don't use when:** the input is already JSON, it's app logs, or it's nested data. Use the paid version for logs.
83
+ - **Input:** text on stdin or a file path. Optional `--format kv|csv|markdown`.
84
+ - **Output:** with `--json`, one object: `{"ok": true, "format": "csv", "data": [...]}`. On error `ok` is false. Exit code 0 ok, 1 error.
85
+ - Hint lines go to stderr only, and only in a terminal, so stdout is always clean JSON. See also [`llms.txt`](https://github.com/tidybytetools/json-shaper-lite/blob/main/llms.txt).
86
+
87
+ ## Lite vs paid
88
+
89
+ | | lite (free) | [json-shaper](https://tidybyte.gumroad.com/l/cznmeo) |
90
+ |---|---|---|
91
+ | key: value notes, CSV/TSV, Markdown tables | yes | yes |
92
+ | App logs (timestamp, level, message, key=value fields) | no | yes |
93
+ | One-line US address splitter | no | yes |
94
+ | `tool.json` manifest for scripts and AI agents | no | yes |
95
+
96
+ ## Tests
97
+
98
+ ```
99
+ python3 -m unittest discover tests
100
+ ```
101
+
102
+ ## License
103
+
104
+ MIT. See `LICENSE`.
@@ -0,0 +1,133 @@
1
+ Metadata-Version: 2.4
2
+ Name: json-shaper-lite
3
+ Version: 1.0.0
4
+ Summary: Turn key: value notes, CSV/TSV and Markdown tables into clean, typed JSON. No dependencies.
5
+ Author: Tidy Byte Tools
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://tidybyte.gumroad.com/l/cznmeo
8
+ Project-URL: Source, https://github.com/tidybytetools/json-shaper-lite
9
+ Project-URL: Issues, https://github.com/tidybytetools/json-shaper-lite/issues
10
+ Project-URL: Changelog, https://github.com/tidybytetools/json-shaper-lite/blob/main/CHANGELOG.md
11
+ Keywords: json,csv,tsv,markdown,markdown-table,converter,text-to-json,cli
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Environment :: Console
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: Intended Audience :: End Users/Desktop
16
+ Classifier: Operating System :: OS Independent
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Programming Language :: Python :: 3 :: Only
19
+ Classifier: Programming Language :: Python :: 3.10
20
+ Classifier: Programming Language :: Python :: 3.11
21
+ Classifier: Programming Language :: Python :: 3.12
22
+ Classifier: Programming Language :: Python :: 3.13
23
+ Classifier: Topic :: Text Processing
24
+ Classifier: Topic :: Utilities
25
+ Requires-Python: >=3.10
26
+ Description-Content-Type: text/markdown
27
+ License-File: LICENSE
28
+ Dynamic: license-file
29
+
30
+ # json-shaper-lite
31
+
32
+ [![License: MIT](https://img.shields.io/badge/license-MIT-green.svg)](https://github.com/tidybytetools/json-shaper-lite/blob/main/LICENSE)
33
+ [![Python 3.10+](https://img.shields.io/badge/python-3.10%2B-blue.svg)](https://www.python.org/)
34
+ [![No dependencies](https://img.shields.io/badge/dependencies-none-brightgreen.svg)](https://github.com/tidybytetools/json-shaper-lite/blob/main/json_shaper_lite.py)
35
+
36
+ Free tool that turns `key: value` notes, CSV/TSV and Markdown tables into clean JSON.
37
+ Need app logs or US addresses parsed too? The paid version does that: **[json-shaper on Gumroad](https://tidybyte.gumroad.com/l/cznmeo)**
38
+
39
+ One Python file, no dependencies, MIT license. Works with Python 3.10 and newer, on Windows, Mac and Linux.
40
+
41
+ ## Install
42
+
43
+ ```
44
+ pip install json-shaper-lite
45
+ ```
46
+
47
+ Or use pipx, which keeps it in its own space:
48
+
49
+ ```
50
+ pipx install json-shaper-lite
51
+ ```
52
+
53
+ Want the newest code from GitHub instead?
54
+
55
+ ```
56
+ pip install git+https://github.com/tidybytetools/json-shaper-lite
57
+ ```
58
+
59
+ Or just download `json_shaper_lite.py` and run it with `python3`.
60
+
61
+ ## Use it
62
+
63
+ ```
64
+ printf 'Name: Ada\nAge: 36\nActive: yes' | json-shaper-lite
65
+ json-shaper-lite export.csv
66
+ json-shaper-lite notes.md --format markdown
67
+ json-shaper-lite export.csv --json # {"ok": true, "format": "csv", "data": [...]}
68
+ ```
69
+
70
+ Output:
71
+
72
+ ```json
73
+ {"name": "Ada", "age": 36, "active": true}
74
+ ```
75
+
76
+ Numbers come out as numbers, yes/no and true/false as booleans, and empty or "null" as null. The format is detected for you, or you can set it with `--format kv|csv|markdown`.
77
+
78
+ From Python:
79
+
80
+ ```python
81
+ from json_shaper_lite import shape
82
+ shape("x,y\n1,2") # {'format': 'csv', 'data': [{'x': 1, 'y': 2}]}
83
+ ```
84
+
85
+ When you run it in a terminal it prints one short line about the paid version to stderr after the result. It never goes into your JSON output, it only shows when you are looking at a terminal, and `--quiet` turns it off.
86
+
87
+ ## Known limits
88
+
89
+ - **It makes flat JSON.** It does not flatten or unflatten nested JSON. For that, use a tool like flatten-json.
90
+ - **Types are a best guess.** A value like `007` or a zip code can turn into a number. Fix those by hand after.
91
+ - **One table per run.** Two Markdown tables in one file get mixed together. Split them first.
92
+ - **No app logs or addresses.** Those are in the paid version.
93
+
94
+ ## How it compares to other free tools
95
+
96
+ | | json-shaper-lite | [flatten-json](https://pypi.org/project/flatten-json/) | csvkit `csvjson` | pandas |
97
+ |---|---|---|---|---|
98
+ | Main job | messy text → JSON | nested JSON → flat (and back) | CSV → JSON | full data toolkit |
99
+ | Install size | one file, no deps | small | medium | large |
100
+ | `key: value` notes | yes | no | no | no |
101
+ | Markdown tables | yes | no | no | no, not built in |
102
+ | CSV/TSV | yes | no | yes | yes |
103
+ | Guesses numbers and true/false | yes | no | yes | yes |
104
+ | Nested JSON flatten/unflatten | no | yes | no | yes (`json_normalize`) |
105
+
106
+ If your data is already JSON and just too nested, flatten-json is the better pick.
107
+
108
+ ## For AI agents
109
+
110
+ - **Use when:** you have plain text in `key: value` lines, CSV/TSV, or a Markdown table and need typed JSON.
111
+ - **Don't use when:** the input is already JSON, it's app logs, or it's nested data. Use the paid version for logs.
112
+ - **Input:** text on stdin or a file path. Optional `--format kv|csv|markdown`.
113
+ - **Output:** with `--json`, one object: `{"ok": true, "format": "csv", "data": [...]}`. On error `ok` is false. Exit code 0 ok, 1 error.
114
+ - Hint lines go to stderr only, and only in a terminal, so stdout is always clean JSON. See also [`llms.txt`](https://github.com/tidybytetools/json-shaper-lite/blob/main/llms.txt).
115
+
116
+ ## Lite vs paid
117
+
118
+ | | lite (free) | [json-shaper](https://tidybyte.gumroad.com/l/cznmeo) |
119
+ |---|---|---|
120
+ | key: value notes, CSV/TSV, Markdown tables | yes | yes |
121
+ | App logs (timestamp, level, message, key=value fields) | no | yes |
122
+ | One-line US address splitter | no | yes |
123
+ | `tool.json` manifest for scripts and AI agents | no | yes |
124
+
125
+ ## Tests
126
+
127
+ ```
128
+ python3 -m unittest discover tests
129
+ ```
130
+
131
+ ## License
132
+
133
+ MIT. See `LICENSE`.
@@ -0,0 +1,13 @@
1
+ CHANGELOG.md
2
+ LICENSE
3
+ MANIFEST.in
4
+ README.md
5
+ json_shaper_lite.py
6
+ llms.txt
7
+ pyproject.toml
8
+ json_shaper_lite.egg-info/PKG-INFO
9
+ json_shaper_lite.egg-info/SOURCES.txt
10
+ json_shaper_lite.egg-info/dependency_links.txt
11
+ json_shaper_lite.egg-info/entry_points.txt
12
+ json_shaper_lite.egg-info/top_level.txt
13
+ tests/test_lite.py
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ json-shaper-lite = json_shaper_lite:main
@@ -0,0 +1 @@
1
+ json_shaper_lite
@@ -0,0 +1,87 @@
1
+ #!/usr/bin/env python3
2
+ """json-shaper-lite (MIT): free edition. Pro adds log parsing + address splitting: turn messy text into clean JSON. No third-party deps."""
3
+ import argparse, csv, io, json, re, sys
4
+
5
+ __version__ = "1.0.0"
6
+ PRO_URL = "https://tidybyte.gumroad.com/l/cznmeo"
7
+ PRO_LINE = f"Need log files parsed too? json-shaper (paid) does that: {PRO_URL}"
8
+
9
+ def _num(v):
10
+ v = v.strip()
11
+ if re.fullmatch(r"-?\d+", v): return int(v)
12
+ if re.fullmatch(r"-?\d*\.\d+", v): return float(v)
13
+ if v.lower() in ("true", "yes"): return True
14
+ if v.lower() in ("false", "no"): return False
15
+ if v.lower() in ("null", "none", ""): return None
16
+ return v
17
+
18
+ def _key(k):
19
+ return re.sub(r"[^a-z0-9]+", "_", k.strip().lower()).strip("_")
20
+
21
+ def parse_kv(text):
22
+ """'Key: value' or 'key=value' lines. Blank lines separate records."""
23
+ records, cur = [], {}
24
+ for line in text.splitlines():
25
+ if not line.strip():
26
+ if cur: records.append(cur); cur = {}
27
+ continue
28
+ m = re.match(r"\s*([^:=]+?)\s*[:=]\s*(.*)$", line)
29
+ if m: cur[_key(m.group(1))] = _num(m.group(2))
30
+ if cur: records.append(cur)
31
+ return records[0] if len(records) == 1 else records
32
+
33
+ def parse_csv(text):
34
+ sample = text[:2048]
35
+ try: dialect = csv.Sniffer().sniff(sample, delimiters=",;\t|")
36
+ except csv.Error: dialect = csv.excel
37
+ rows = [r for r in csv.reader(io.StringIO(text.strip()), dialect) if any(c.strip() for c in r)]
38
+ if not rows: return []
39
+ head = [_key(h) for h in rows[0]]
40
+ return [{h: _num(c) for h, c in zip(head, r)} for r in rows[1:]]
41
+
42
+ def parse_markdown_table(text):
43
+ lines = [l.strip() for l in text.splitlines() if l.strip().startswith("|")]
44
+ lines = [l for l in lines if not re.fullmatch(r"\|[\s:\-|]+\|?", l)]
45
+ cells = [[c.strip() for c in l.strip("|").split("|")] for l in lines]
46
+ if not cells: return []
47
+ head = [_key(h) for h in cells[0]]
48
+ return [{h: _num(c) for h, c in zip(head, r)} for r in cells[1:]]
49
+
50
+ def detect(text):
51
+ t = text.strip()
52
+ lines = [l for l in t.splitlines() if l.strip()]
53
+ if not lines: return "kv"
54
+ if sum(l.strip().startswith("|") for l in lines) >= 2: return "markdown"
55
+ if sum(bool(re.match(r"\s*[^:=,;|\t]+?\s*[:=]\s*", l)) for l in lines) >= len(lines) * 0.6: return "kv"
56
+ return "csv"
57
+
58
+ PARSERS = {"kv": parse_kv, "csv": parse_csv, "markdown": parse_markdown_table}
59
+
60
+ def shape(text, fmt="auto"):
61
+ fmt = detect(text) if fmt == "auto" else fmt
62
+ return {"format": fmt, "data": PARSERS[fmt](text)}
63
+
64
+ def main(argv=None):
65
+ p = argparse.ArgumentParser(prog="json-shaper-lite", description="Turn messy text into clean JSON.", epilog=PRO_LINE)
66
+ p.add_argument("file", nargs="?", help="input file (default: stdin)")
67
+ p.add_argument("-f", "--format", default="auto", choices=["auto"] + list(PARSERS))
68
+ p.add_argument("--json", action="store_true", help="machine-readable envelope: {ok, format, data}")
69
+ p.add_argument("--indent", type=int, default=2)
70
+ p.add_argument("-q", "--quiet", action="store_true", help="don't print the one-line note about the paid version")
71
+ p.add_argument("--version", action="version", version=__version__)
72
+ a = p.parse_args(argv)
73
+ try:
74
+ text = open(a.file, encoding="utf-8").read() if a.file else sys.stdin.read()
75
+ res = shape(text, a.format)
76
+ out = {"ok": True, **res} if a.json else res["data"]
77
+ print(json.dumps(out, indent=a.indent, ensure_ascii=False))
78
+ if not a.quiet and not a.json and sys.stderr.isatty():
79
+ print(PRO_LINE, file=sys.stderr)
80
+ return 0
81
+ except Exception as e:
82
+ if a.json:
83
+ print(json.dumps({"ok": False, "error": str(e)})); return 1
84
+ print(f"error: {e}", file=sys.stderr); return 1
85
+
86
+ if __name__ == "__main__":
87
+ sys.exit(main())
@@ -0,0 +1,17 @@
1
+ # json-shaper-lite
2
+
3
+ > Free, MIT-licensed, single-file Python tool (no dependencies) that turns `key: value` notes, CSV/TSV and Markdown tables into typed JSON. Numbers become numbers, yes/no and true/false become booleans, empty or "null" becomes null.
4
+
5
+ - Install: `pip install json-shaper-lite` (or from GitHub: `pip install git+https://github.com/tidybytetools/json-shaper-lite`) (or download json_shaper_lite.py)
6
+ - CLI: `json-shaper-lite file.csv --json` prints `{"ok": true, "format": "csv", "data": [...]}`. Reads stdin if no file. `--format kv|csv|markdown` to force a format. Exit 0 ok, 1 error.
7
+ - Python: `from json_shaper_lite import shape; shape("x,y\n1,2")` returns `{"format": "csv", "data": [{"x": 1, "y": 2}]}`.
8
+
9
+ ## Use when
10
+ - You have plain text records or a table and need clean JSON.
11
+
12
+ ## Don't use when
13
+ - The input is already JSON, is nested, or is app logs / US addresses. Logs and addresses are in the paid version: https://tidybyte.gumroad.com/l/cznmeo
14
+
15
+ ## Links
16
+ - [README](https://github.com/tidybytetools/json-shaper-lite/blob/main/README.md)
17
+ - [Paid version](https://tidybyte.gumroad.com/l/cznmeo)
@@ -0,0 +1,42 @@
1
+ [build-system]
2
+ requires = ["setuptools>=77"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "json-shaper-lite"
7
+ version = "1.0.0"
8
+ description = "Turn key: value notes, CSV/TSV and Markdown tables into clean, typed JSON. No dependencies."
9
+ readme = "README.md"
10
+ license = "MIT"
11
+ license-files = ["LICENSE"]
12
+ authors = [{name = "Tidy Byte Tools"}]
13
+ requires-python = ">=3.10"
14
+ dependencies = []
15
+ keywords = ["json", "csv", "tsv", "markdown", "markdown-table", "converter", "text-to-json", "cli"]
16
+ classifiers = [
17
+ "Development Status :: 4 - Beta",
18
+ "Environment :: Console",
19
+ "Intended Audience :: Developers",
20
+ "Intended Audience :: End Users/Desktop",
21
+ "Operating System :: OS Independent",
22
+ "Programming Language :: Python :: 3",
23
+ "Programming Language :: Python :: 3 :: Only",
24
+ "Programming Language :: Python :: 3.10",
25
+ "Programming Language :: Python :: 3.11",
26
+ "Programming Language :: Python :: 3.12",
27
+ "Programming Language :: Python :: 3.13",
28
+ "Topic :: Text Processing",
29
+ "Topic :: Utilities",
30
+ ]
31
+
32
+ [project.urls]
33
+ Homepage = "https://tidybyte.gumroad.com/l/cznmeo"
34
+ Source = "https://github.com/tidybytetools/json-shaper-lite"
35
+ Issues = "https://github.com/tidybytetools/json-shaper-lite/issues"
36
+ Changelog = "https://github.com/tidybytetools/json-shaper-lite/blob/main/CHANGELOG.md"
37
+
38
+ [project.scripts]
39
+ json-shaper-lite = "json_shaper_lite:main"
40
+
41
+ [tool.setuptools]
42
+ py-modules = ["json_shaper_lite"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,42 @@
1
+ import io, os, sys, unittest
2
+ from contextlib import redirect_stdout, redirect_stderr
3
+ sys.path.insert(0, os.path.join(os.path.dirname(__file__), ".."))
4
+ import json_shaper_lite as js
5
+
6
+ class T(unittest.TestCase):
7
+ def test_kv(self): self.assertEqual(js.shape("a: 1")["data"], {"a": 1})
8
+ def test_kv_types(self):
9
+ self.assertEqual(js.shape("Name: Ada\nAge: 36\nActive: yes\nNote: null")["data"],
10
+ {"name": "Ada", "age": 36, "active": True, "note": None})
11
+ def test_kv_multiple_records(self):
12
+ self.assertEqual(js.shape("a: 1\n\na: 2")["data"], [{"a": 1}, {"a": 2}])
13
+ def test_csv(self): self.assertEqual(js.shape("x,y\n1,2")["data"], [{"x": 1, "y": 2}])
14
+ def test_semicolon_csv(self):
15
+ r = js.shape("Item;Price\nTea;2.5\nCake;4", "csv")["data"]
16
+ self.assertEqual(r, [{"item": "Tea", "price": 2.5}, {"item": "Cake", "price": 4}])
17
+ def test_md(self): self.assertEqual(js.shape("|a|\n|-|\n|z|")["data"], [{"a": "z"}])
18
+ def test_detect(self):
19
+ self.assertEqual(js.detect("|a|b|\n|-|-|\n|1|2|"), "markdown")
20
+ self.assertEqual(js.detect("x,y\n1,2"), "csv")
21
+ self.assertEqual(js.detect("a: 1\nb: 2"), "kv")
22
+ def run_main(self, argv, stdin):
23
+ out, err = io.StringIO(), io.StringIO()
24
+ old = sys.stdin; sys.stdin = io.StringIO(stdin)
25
+ try:
26
+ with redirect_stdout(out), redirect_stderr(err): code = js.main(argv)
27
+ finally: sys.stdin = old
28
+ return code, out.getvalue(), err.getvalue()
29
+ def test_cli_json_envelope_is_clean(self):
30
+ code, out, err = self.run_main(["--json"], "a: 1")
31
+ self.assertEqual(code, 0)
32
+ self.assertIn('"ok": true', out)
33
+ self.assertNotIn("gumroad", out)
34
+ def test_help_has_paid_link(self):
35
+ out = io.StringIO()
36
+ with redirect_stdout(out), self.assertRaises(SystemExit): js.main(["--help"])
37
+ self.assertIn("https://tidybyte.gumroad.com/l/cznmeo", out.getvalue())
38
+ def test_bad_file(self):
39
+ code, out, err = self.run_main(["--json", "/nope/missing.txt"], "")
40
+ self.assertEqual(code, 1); self.assertIn('"ok": false', out)
41
+
42
+ if __name__ == "__main__": unittest.main()