Skip to content

Commit 3e0a944

Browse files
committed
Prepare 0.25.0 release
1 parent 81b1d22 commit 3e0a944

7 files changed

Lines changed: 230 additions & 43 deletions

File tree

Cargo.lock

Lines changed: 108 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "flatterer"
3-
version = "0.24.1"
3+
version = "0.25.0"
44
authors = ["David Raznick <kindly@gmail.com>"]
55
edition = "2024"
66
license = "MIT"
@@ -14,7 +14,7 @@ serde_json = { version = "1.0.150", features = ["preserve_order"] }
1414
pyo3 = { version = "0.28.3", features = ["extension-module", "eyre"] }
1515
eyre = "0.6.12"
1616
#libflatterer={path = "../libflatterer"}
17-
libflatterer = "0.24.1"
17+
libflatterer = "0.25.0"
1818

1919
flatterer-web = "0.24.1"
2020
#flatterer-web={path = "../flatterer-web"}

docs/changelog.md

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,23 @@ All notable changes to this project will be documented in this file.
44

55
and this project adheres to [Semantic Versioning](http://semver.org/).
66

7+
## [0.25.0] - 2026-06-28
8+
9+
### Changed
10+
- Upgrade `libflatterer` to 0.25.0.
11+
- Python API and CLI now expose `schema_only`/`--schema-only` and `stream_wrapped`/`--stream-wrapped`.
12+
- JSON flattening now uses the new jiter streaming parser from `libflatterer`, replacing the previous YAJL parser path.
13+
- Expect 1.5-2x speed improvements for most JSON shapes in both single-threaded and multithreaded modes.
14+
- For nested lists of dictionaries, multithreaded runs can be 3-4x faster because the jiter parser is much faster.
15+
- Wrapped JSON objects now stream arrays of objects by default, reducing memory use for large wrapped inputs.
16+
- JSON stream input now uses the jiter streaming parser, improving streaming behavior while preserving NDJSON-compatible output.
17+
- Schema-only output now uses the new structural scan path where supported, avoiding full row materialization.
18+
- Output cell handling now keeps short strings in `SmartString`, reducing allocation overhead in the hot flattening path.
19+
- One-to-many link level handling has been simplified in `libflatterer`.
20+
21+
### Fixed
22+
- Mixed arrays whose first item is an object are now handled consistently, including non-object elements as `value` rows instead of regressing in multicore processing.
23+
724
## [0.24.1] - 2026-06-02
825

926
### Fixed
@@ -430,4 +447,3 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
430447
### Added
431448

432449
- [Inline One to One option](https://flatterer.opendata.coop/options.html#inline-one-to-one) to mean that if an array only has one item in for all the data then treat it as sub-object.
433-

docs/options.md

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,9 @@ Options:
6767
--stats Produce stats about the data in the
6868
datapackage.json file
6969
--all-strings Convert all fields to strings
70+
--schema-only Only output schema files, not data files
71+
--stream-wrapped / --no-stream-wrapped
72+
Stream wrapped JSON objects, default true
7073
--help Show this message and exit.
7174
```
7275

@@ -888,4 +891,40 @@ import flatterer
888891

889892
flatterer.flatten('inputfile.json', 'ouput_dir', all_strings=True)
890893
```
894+
895+
## Schema Only
896+
897+
Only output schema files (`datapackage.json`, `fields.csv`, and `tables.csv`) and skip data files.
898+
899+
### CLI Usage
900+
901+
```bash
902+
flatterer INPUT_FILE OUTPUT_DIRECTORY --schema-only
903+
```
904+
905+
### Python Usage
906+
907+
```python
908+
import flatterer
909+
910+
flatterer.flatten('inputfile.json', 'ouput_dir', schema_only=True)
911+
```
912+
913+
## Stream Wrapped
914+
915+
Stream arrays of objects inside wrapped JSON objects without buffering the whole document. This is enabled by default.
916+
917+
### CLI Usage
918+
919+
```bash
920+
flatterer INPUT_FILE OUTPUT_DIRECTORY --no-stream-wrapped
921+
```
922+
923+
### Python Usage
924+
925+
```python
926+
import flatterer
927+
928+
flatterer.flatten('inputfile.json', 'ouput_dir', stream_wrapped=False)
929+
```
891930

flatterer/__init__.py

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,9 @@ def flatten(
9999
json_path="",
100100
arrays_new_table=False,
101101
truncate=False,
102-
all_strings=False
102+
all_strings=False,
103+
schema_only=False,
104+
stream_wrapped=True
103105
):
104106
global LOGGING_SETUP
105107
if not LOGGING_SETUP:
@@ -148,7 +150,7 @@ def flatten(
148150
schema, schema_titles, path, json_stream, ndjson,
149151
sqlite_path, threads, log_error, postgres, postgres_schema,
150152
drop, pushdown, sql_scripts, evolve, no_link, stats, low_disk, low_memory,
151-
gzip_input, json_path, arrays_new_table, truncate, all_strings)
153+
gzip_input, json_path, arrays_new_table, truncate, all_strings, schema_only, stream_wrapped)
152154
elif method == 'iter':
153155
if path:
154156
raise AttributeError("path not allowed when supplying an iterator")
@@ -161,7 +163,8 @@ def flatten(
161163
table_prefix, id_prefix, emit_obj, force,
162164
schema, schema_titles, sqlite_path, threads, log_error,
163165
postgres, postgres_schema, drop, pushdown, sql_scripts, evolve,
164-
no_link, stats, low_disk, low_memory, gzip_input, json_path, arrays_new_table, truncate, all_strings)
166+
no_link, stats, low_disk, low_memory, gzip_input, json_path, arrays_new_table, truncate, all_strings,
167+
schema_only, stream_wrapped)
165168
else:
166169
raise AttributeError("input needs to be a string or a generator of strings, dicts or bytes")
167170

@@ -175,7 +178,7 @@ def flatten(
175178
data=PrettyDict()
176179
)
177180

178-
if csv:
181+
if csv and not schema_only:
179182
for name, title in output['tables'].values:
180183
csv_path = os.path.join(output_dir, 'csv', str(title) + '.csv')
181184
if dataframe:
@@ -187,13 +190,13 @@ def flatten(
187190
else:
188191
output['data'][title] = csv_path
189192

190-
if sqlite:
193+
if sqlite and not schema_only:
191194
output['sqlite'] = os.path.join(output_dir, 'sqlite.db')
192195

193-
if xlsx:
196+
if xlsx and not schema_only:
194197
output['xlsx'] = os.path.join(output_dir, 'output.xlsx')
195198

196-
if ods:
199+
if ods and not schema_only:
197200
output['ods'] = os.path.join(output_dir, 'output.ods')
198201

199202
return output
@@ -257,6 +260,8 @@ def iterator_flatten(*args, **kw):
257260
@click.option('--id-prefix', default="", help='Prefix for all `_link` id fields')
258261
@click.option('--stats', is_flag=True, default=False, help='Produce stats about the data in the datapackage.json file')
259262
@click.option('--all-strings', is_flag=True, default=False, help='Convert all fields to strings')
263+
@click.option('--schema-only', is_flag=True, default=False, help='Only output schema files, not data files')
264+
@click.option('--stream-wrapped/--no-stream-wrapped', default=True, help='Stream wrapped JSON objects, default true')
260265
@click.argument('inputs', required=False, nargs=-1)
261266
@click.argument('output_directory', required=False)
262267
def cli(
@@ -296,7 +301,9 @@ def cli(
296301
json_path="",
297302
arrays_new_table=False,
298303
truncate=False,
299-
all_strings=False
304+
all_strings=False,
305+
schema_only=False,
306+
stream_wrapped=True
300307
):
301308
if web:
302309
import pathlib
@@ -370,6 +377,8 @@ def cli(
370377
json_path=json_path,
371378
arrays_new_table=arrays_new_table,
372379
truncate=truncate,
373-
all_strings=all_strings)
380+
all_strings=all_strings,
381+
schema_only=schema_only,
382+
stream_wrapped=stream_wrapped)
374383
except IOError:
375384
pass

0 commit comments

Comments
 (0)