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.
- json_shaper_lite-1.0.0/CHANGELOG.md +11 -0
- json_shaper_lite-1.0.0/LICENSE +9 -0
- json_shaper_lite-1.0.0/MANIFEST.in +2 -0
- json_shaper_lite-1.0.0/PKG-INFO +133 -0
- json_shaper_lite-1.0.0/README.md +104 -0
- json_shaper_lite-1.0.0/json_shaper_lite.egg-info/PKG-INFO +133 -0
- json_shaper_lite-1.0.0/json_shaper_lite.egg-info/SOURCES.txt +13 -0
- json_shaper_lite-1.0.0/json_shaper_lite.egg-info/dependency_links.txt +1 -0
- json_shaper_lite-1.0.0/json_shaper_lite.egg-info/entry_points.txt +2 -0
- json_shaper_lite-1.0.0/json_shaper_lite.egg-info/top_level.txt +1 -0
- json_shaper_lite-1.0.0/json_shaper_lite.py +87 -0
- json_shaper_lite-1.0.0/llms.txt +17 -0
- json_shaper_lite-1.0.0/pyproject.toml +42 -0
- json_shaper_lite-1.0.0/setup.cfg +4 -0
- json_shaper_lite-1.0.0/tests/test_lite.py +42 -0
|
@@ -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,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
|
+
[](https://github.com/tidybytetools/json-shaper-lite/blob/main/LICENSE)
|
|
33
|
+
[](https://www.python.org/)
|
|
34
|
+
[](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
|
+
[](https://github.com/tidybytetools/json-shaper-lite/blob/main/LICENSE)
|
|
4
|
+
[](https://www.python.org/)
|
|
5
|
+
[](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
|
+
[](https://github.com/tidybytetools/json-shaper-lite/blob/main/LICENSE)
|
|
33
|
+
[](https://www.python.org/)
|
|
34
|
+
[](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 @@
|
|
|
1
|
+
|
|
@@ -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,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()
|