Move parsing into BaseDataset.import_dataset and replace BaseParser with a plugin API - #478
Move parsing into BaseDataset.import_dataset and replace BaseParser with a plugin API#478kozlov721 wants to merge 5 commits into
BaseDataset.import_dataset and replace BaseParser with a plugin API#478Conversation
|
Important Review skippedDraft detected. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
`rsplit("/")` never splits a local Windows path, so `prepare_source`
returned the whole absolute path as the dataset name there. `PurePath`
uses the platform's separator, while a backslash on POSIX stays the
ordinary file name character it is there.
The Roboflow test compared its download destination as a string ending
in `/project`, which is a backslash on Windows; it compares the path's
name now.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #478 +/- ##
==========================================
+ Coverage 95.03% 96.94% +1.90%
==========================================
Files 177 179 +2
Lines 14557 15500 +943
==========================================
+ Hits 13834 15026 +1192
+ Misses 723 474 -249
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. |
Part 1 of 2, split out of #461.
#461 bundles two separable changes: a public API change, and a performance
rewrite of the parsers. This branch is the API change on its own. The
streaming rewrite, the benchmark suite and its CI job, and a second round of
review fixes stay on the follow-up branch
feat/parser-optimizations, whichis stacked on this one.
The split is exact: merging this branch and the follow-up into
mainreproduces #461's tree byte for byte (
b3cb1907), with an empty diff againstfeat/parsers-refactor.What changes
A parser no longer owns the dataset it fills. It used to construct a
LuxonisDataset, write records into it, and hand it back. Now it is adata-only plugin that yields records, and
BaseDataset.import_datasetbuildsthe dataset around them.
import_datasetis a classmethod onBaseDataset, so every registereddataset implementation inherits it and gets back an instance of the class it
was called on.
LuxonisParserstill works and still returns the same dataset. It is now athin wrapper over
import_datasetthat raises aDeprecationWarningonconstruction.
Breaking changes
BaseParserParserPlugin/SplitParserPluginParserOutput(a bare 3-tuple)ParsedDataset(records, skeletons, files, splits)BaseParser.from_dir()/from_split()ParserPlugin.parse()/SplitParserPlugin._parse_split()BaseParser.validate()ParserPlugin.supports()BaseParser.discover_dir_splits()SplitParserPlugin.discover_splits()BaseParser.parse_dir()/parse_split()BaseDataset.import_dataset()LuxonisParserBaseDataset.import_dataset, still presentA parser is registered with
register_parser_plugin, or by publishing theclass through a
parser_pluginsentry point. The type names it answers toare its
dataset_typesclass variable.So a third-party parser needs:
supports(),parse()— or_parse_split()plus
validate_split()for split layouts — and adataset_typesentry.Bugs fixed
Each has a regression test that fails without its fix.
Silent data loss
_prepare_import_recordsdropped annotation-less images — backgroundimages in YOLOv6/v8, COCO, VOC and Darknet — until the first annotated
record. A string
task_namebecame adefaultdict, which is onlypopulated on lookup, so the fan-out set for unannotated records was empty.
Order-dependent loss.
images/train+images/vallayout matched bothYOLOv6 and YOLOv8 and hard-errored as ambiguous. Resolved by split
coverage; genuine ties still raise.
use_keypoint_annandkeypoint_ann_paths, so a pose model could be trained on a keypoint-freedataset. It raises now.
Failures that landed after the dataset was already on disk
split_ratiosraised a bareKeyErrorafterthe dataset had been created.
make_splitsand left anorphaned registered dataset.
Both are validated before construction now.
Plugin and API surface
dataset_typescollided with a built-in madeplain
import luxonis_ml.dataraiseKeyError, breaking every downstreamconsumer. It warns and skips now, and registration is atomic — a collision
on a later type no longer leaves the earlier ones registered.
LuxonisParserdeferred source acquisition intoparse(), soconstruction-time errors stopped firing and every
parse()callre-downloaded the source and returned a new dataset. The source is
acquired and its format resolved in
__init__again.Pre-existing, fixed along the way
_list_imageswas case-sensitive — it listed.WebPbut not.JPG— sodatasets with uppercase extensions were rejected or silently truncated.
UnboundLocalErroron a label line with fewer than fivevalues; it is skipped via
ParserIssue.MALFORMED_ANNOTATIONnow./on the source produced the dataset name"", writingstorage directories into the datasets root and merging into prior imports.
ClassificationDirectoryParser.validate_splitexcludeddata,rawandmasks, but the parse then ingested them as classes.Deliberately not in this branch
These are in
feat/parser-optimizations, and reviewing this branch as if theywere missing oversights would be reading it wrong:
enumerate_files) — every parser here still walksits source twice, once for records and once for the file list
model_copy(deep=True)ParseResultandLayout; this branch still hasParsedDatasetandcombine_split_outputstools/profile_parsers.py,tools/compare_benchmarks.py, and the CI benchmark jobTesting
tests/test_data/test_parser_plugins.pyis new — 61 credential-free testscovering registration, detection, split discovery and the plugin base — and
test_parsers.pyis extended alongside it.ruff checkandruff format --checkare clean.I ran the parser suite locally. The only failures were the tests that download
from the test bucket, which fail on expired GCS credentials in my environment
rather than on anything in this change; the credential-free tests all pass.
🤖 Generated with Claude Code