lannotex 0.1.0__tar.gz → 0.1.1__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.
Files changed (60) hide show
  1. {lannotex-0.1.0 → lannotex-0.1.1}/CHANGELOG.md +9 -0
  2. {lannotex-0.1.0 → lannotex-0.1.1}/PKG-INFO +4 -4
  3. {lannotex-0.1.0 → lannotex-0.1.1}/README.md +3 -3
  4. {lannotex-0.1.0 → lannotex-0.1.1}/docs/guide/import-export.md +28 -8
  5. {lannotex-0.1.0 → lannotex-0.1.1}/src/lannotex/__init__.py +1 -1
  6. {lannotex-0.1.0 → lannotex-0.1.1}/src/lannotex/exporters.py +28 -3
  7. {lannotex-0.1.0 → lannotex-0.1.1}/src/lannotex.egg-info/PKG-INFO +4 -4
  8. {lannotex-0.1.0 → lannotex-0.1.1}/tests/test_exporters.py +27 -0
  9. {lannotex-0.1.0 → lannotex-0.1.1}/LICENSE +0 -0
  10. {lannotex-0.1.0 → lannotex-0.1.1}/LICENSES/GPL-3.0-only.txt +0 -0
  11. {lannotex-0.1.0 → lannotex-0.1.1}/LICENSES/LGPL-3.0-only.txt +0 -0
  12. {lannotex-0.1.0 → lannotex-0.1.1}/LICENSES/Qt-GPL-exception-1.0.txt +0 -0
  13. {lannotex-0.1.0 → lannotex-0.1.1}/LICENSES/THIRD_PARTY_NOTICES.md +0 -0
  14. {lannotex-0.1.0 → lannotex-0.1.1}/Lannotex.spec +0 -0
  15. {lannotex-0.1.0 → lannotex-0.1.1}/MANIFEST.in +0 -0
  16. {lannotex-0.1.0 → lannotex-0.1.1}/docs/MICROSOFT_STORE.md +0 -0
  17. {lannotex-0.1.0 → lannotex-0.1.1}/docs/PERFORMANCE.md +0 -0
  18. {lannotex-0.1.0 → lannotex-0.1.1}/docs/ROADMAP.md +0 -0
  19. {lannotex-0.1.0 → lannotex-0.1.1}/docs/TEAM.md +0 -0
  20. {lannotex-0.1.0 → lannotex-0.1.1}/docs/VERIFICATION.md +0 -0
  21. {lannotex-0.1.0 → lannotex-0.1.1}/docs/cli.md +0 -0
  22. {lannotex-0.1.0 → lannotex-0.1.1}/docs/getting-started/installation.md +0 -0
  23. {lannotex-0.1.0 → lannotex-0.1.1}/docs/getting-started/quickstart.md +0 -0
  24. {lannotex-0.1.0 → lannotex-0.1.1}/docs/guide/annotating.md +0 -0
  25. {lannotex-0.1.0 → lannotex-0.1.1}/docs/guide/projects.md +0 -0
  26. {lannotex-0.1.0 → lannotex-0.1.1}/docs/index.md +0 -0
  27. {lannotex-0.1.0 → lannotex-0.1.1}/docs/migrate-from-labelme.md +0 -0
  28. {lannotex-0.1.0 → lannotex-0.1.1}/pyproject.toml +0 -0
  29. {lannotex-0.1.0 → lannotex-0.1.1}/requirements-windows-build.txt +0 -0
  30. {lannotex-0.1.0 → lannotex-0.1.1}/run_lannotex.py +0 -0
  31. {lannotex-0.1.0 → lannotex-0.1.1}/scripts/benchmark.py +0 -0
  32. {lannotex-0.1.0 → lannotex-0.1.1}/scripts/build_linux.sh +0 -0
  33. {lannotex-0.1.0 → lannotex-0.1.1}/scripts/build_macos.sh +0 -0
  34. {lannotex-0.1.0 → lannotex-0.1.1}/scripts/build_windows.ps1 +0 -0
  35. {lannotex-0.1.0 → lannotex-0.1.1}/scripts/collect_notices.py +0 -0
  36. {lannotex-0.1.0 → lannotex-0.1.1}/scripts/verify_executable.py +0 -0
  37. {lannotex-0.1.0 → lannotex-0.1.1}/setup.cfg +0 -0
  38. {lannotex-0.1.0 → lannotex-0.1.1}/src/lannotex/__main__.py +0 -0
  39. {lannotex-0.1.0 → lannotex-0.1.1}/src/lannotex/app.py +0 -0
  40. {lannotex-0.1.0 → lannotex-0.1.1}/src/lannotex/canvas.py +0 -0
  41. {lannotex-0.1.0 → lannotex-0.1.1}/src/lannotex/cli.py +0 -0
  42. {lannotex-0.1.0 → lannotex-0.1.1}/src/lannotex/domain.py +0 -0
  43. {lannotex-0.1.0 → lannotex-0.1.1}/src/lannotex/home.py +0 -0
  44. {lannotex-0.1.0 → lannotex-0.1.1}/src/lannotex/models.py +0 -0
  45. {lannotex-0.1.0 → lannotex-0.1.1}/src/lannotex/py.typed +0 -0
  46. {lannotex-0.1.0 → lannotex-0.1.1}/src/lannotex/storage.py +0 -0
  47. {lannotex-0.1.0 → lannotex-0.1.1}/src/lannotex/team.py +0 -0
  48. {lannotex-0.1.0 → lannotex-0.1.1}/src/lannotex/theme.py +0 -0
  49. {lannotex-0.1.0 → lannotex-0.1.1}/src/lannotex/workers.py +0 -0
  50. {lannotex-0.1.0 → lannotex-0.1.1}/src/lannotex.egg-info/SOURCES.txt +0 -0
  51. {lannotex-0.1.0 → lannotex-0.1.1}/src/lannotex.egg-info/dependency_links.txt +0 -0
  52. {lannotex-0.1.0 → lannotex-0.1.1}/src/lannotex.egg-info/entry_points.txt +0 -0
  53. {lannotex-0.1.0 → lannotex-0.1.1}/src/lannotex.egg-info/requires.txt +0 -0
  54. {lannotex-0.1.0 → lannotex-0.1.1}/src/lannotex.egg-info/top_level.txt +0 -0
  55. {lannotex-0.1.0 → lannotex-0.1.1}/tests/test_cli.py +0 -0
  56. {lannotex-0.1.0 → lannotex-0.1.1}/tests/test_domain.py +0 -0
  57. {lannotex-0.1.0 → lannotex-0.1.1}/tests/test_storage.py +0 -0
  58. {lannotex-0.1.0 → lannotex-0.1.1}/tests/test_team.py +0 -0
  59. {lannotex-0.1.0 → lannotex-0.1.1}/tests/test_ui.py +0 -0
  60. {lannotex-0.1.0 → lannotex-0.1.1}/tests/test_workflows.py +0 -0
@@ -6,6 +6,15 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [0.1.1] — 2026-10-14
10
+
11
+ ### Changed
12
+
13
+ - **YOLO export is ready to train with Ultralytics:** `images/` (hard-linked when
14
+ possible, otherwise copied), matching `labels/`, and a `data.yaml` with class names.
15
+ Images that haven't been annotated yet are left out, so they don't become false
16
+ negatives.
17
+
9
18
  ## [0.1.0] — 2026-10-14
10
19
 
11
20
  First public release on PyPI: `pip install lannotex` or `uv tool install lannotex`.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: lannotex
3
- Version: 0.1.0
3
+ Version: 0.1.1
4
4
  Summary: Fast, offline-first image annotation for classifications, boxes, and polygons.
5
5
  Author: Lourdhu Raju
6
6
  Maintainer: Lourdhu Raju
@@ -133,7 +133,7 @@ Every shortcut can be remapped. See the [annotating guide](https://lourdhu02.git
133
133
  | **Annotate** | Bounding boxes · polygons with vertex drag, insert, and delete · multi-label image classes · "no target" negatives · 100-step undo/redo · zoom under the pointer, pan, arrow-key nudging · focus mode · light and dark themes |
134
134
  | **Stay safe** | SQLite projects with versioned migrations · recovery drafts and 700 ms autosave · transactional saves · geometry validation · backup and restore · relinking for moved images · EXIF orientation handled |
135
135
  | **Scale** | Virtualized image list (at most 1,024 records in memory) · background import and decoding · 96 MB preview cache · coordinates normalized to the original resolution |
136
- | **Export** | Labelme JSON · YOLO · COCO JSON · classification CSV · lossless native JSONL · each export reports anything it skipped |
136
+ | **Export** | Labelme JSON · ready-to-train YOLO (`images/`, `labels/`, `data.yaml`) · COCO JSON · classification CSV · lossless native JSONL · each export reports anything it skipped |
137
137
  | **Automate** | `lannotex export` and `lannotex analyze` run headless in CI, with no display needed |
138
138
  | **Collaborate** | Optional LAN host with per-reviewer tokens, background sync, revision conflicts you resolve explicitly, revocation, and an audit history |
139
139
 
@@ -181,8 +181,8 @@ hashes. There is no telemetry, no external AI service, and no automatic upload.
181
181
 
182
182
  ## Roadmap
183
183
 
184
- Next up: a ready-to-train YOLO layout (`images/`, `labels/`, `data.yaml`), more LabelMe
185
- shape types, VOC and YOLO-seg export, and number-key label selection. See the
184
+ Next up: more LabelMe shape types (points, lines, circles), VOC and YOLO-seg export, and
185
+ number-key label selection. See the
186
186
  [roadmap](https://lourdhu02.github.io/Lannotex/ROADMAP/) and the
187
187
  [measured performance](https://lourdhu02.github.io/Lannotex/PERFORMANCE/).
188
188
 
@@ -91,7 +91,7 @@ Every shortcut can be remapped. See the [annotating guide](https://lourdhu02.git
91
91
  | **Annotate** | Bounding boxes · polygons with vertex drag, insert, and delete · multi-label image classes · "no target" negatives · 100-step undo/redo · zoom under the pointer, pan, arrow-key nudging · focus mode · light and dark themes |
92
92
  | **Stay safe** | SQLite projects with versioned migrations · recovery drafts and 700 ms autosave · transactional saves · geometry validation · backup and restore · relinking for moved images · EXIF orientation handled |
93
93
  | **Scale** | Virtualized image list (at most 1,024 records in memory) · background import and decoding · 96 MB preview cache · coordinates normalized to the original resolution |
94
- | **Export** | Labelme JSON · YOLO · COCO JSON · classification CSV · lossless native JSONL · each export reports anything it skipped |
94
+ | **Export** | Labelme JSON · ready-to-train YOLO (`images/`, `labels/`, `data.yaml`) · COCO JSON · classification CSV · lossless native JSONL · each export reports anything it skipped |
95
95
  | **Automate** | `lannotex export` and `lannotex analyze` run headless in CI, with no display needed |
96
96
  | **Collaborate** | Optional LAN host with per-reviewer tokens, background sync, revision conflicts you resolve explicitly, revocation, and an audit history |
97
97
 
@@ -139,8 +139,8 @@ hashes. There is no telemetry, no external AI service, and no automatic upload.
139
139
 
140
140
  ## Roadmap
141
141
 
142
- Next up: a ready-to-train YOLO layout (`images/`, `labels/`, `data.yaml`), more LabelMe
143
- shape types, VOC and YOLO-seg export, and number-key label selection. See the
142
+ Next up: more LabelMe shape types (points, lines, circles), VOC and YOLO-seg export, and
143
+ number-key label selection. See the
144
144
  [roadmap](https://lourdhu02.github.io/Lannotex/ROADMAP/) and the
145
145
  [measured performance](https://lourdhu02.github.io/Lannotex/PERFORMANCE/).
146
146
 
@@ -5,7 +5,7 @@
5
5
  | Format | Contains | Use it for |
6
6
  | --- | --- | --- |
7
7
  | **Labelme JSON** | One JSON per image: boxes as `rectangle`, polygons, classes as `flags` | LabelMe and tools that read its format |
8
- | **YOLO boxes** | One `.txt` per image: `class cx cy w h`, normalized | YOLO detection training |
8
+ | **YOLO boxes** | Ready-to-train Ultralytics dataset: `images/`, `labels/`, `data.yaml` | YOLO detection training |
9
9
  | **COCO JSON** | One `coco.json` with boxes, polygon segmentations, and areas | Detection and instance segmentation |
10
10
  | **Classification CSV** | One row per image, one 0/1 column per class | Image classification |
11
11
  | **Native JSONL** | Every annotation with its ID and status | Lossless backup and round-trips |
@@ -24,10 +24,11 @@ Lannotex-export-1a2b3c4d/
24
24
  ├── classification.csv
25
25
  ├── images.jsonl
26
26
  ├── annotations.jsonl
27
- └── 00000001_street.json # per-image files (Labelme JSON / YOLO .txt)
27
+ └── 00000001_street.json # per-image files (Labelme JSON)
28
28
  ```
29
29
 
30
- Images are **referenced, not copied**: exported records point to the original files.
30
+ Images are **referenced, not copied**: exported records point to the original files. YOLO
31
+ is the exception, described below.
31
32
 
32
33
  ### What gets skipped
33
34
 
@@ -39,11 +40,30 @@ An image is left out of the export, and listed in `manifest.json`, if:
39
40
 
40
41
  Run **View → Analysis** or `lannotex analyze` beforehand to find these images.
41
42
 
42
- !!! note "Training with Ultralytics YOLO"
43
- The YOLO export writes label files named `<id>_<image name>.txt` plus `classes.json`.
44
- Ultralytics expects `images/` and `labels/` folders with matching file names and a
45
- `data.yaml`, so you currently have to arrange those yourself. A ready-to-train layout is
46
- planned.
43
+ ### YOLO: ready to train
44
+
45
+ The YOLO export is a complete [Ultralytics](https://docs.ultralytics.com/datasets/detect/)
46
+ dataset:
47
+
48
+ ```text
49
+ Lannotex-export-1a2b3c4d/
50
+ ├── data.yaml # path, train/val, class names
51
+ ├── images/00000001_street.jpg
52
+ └── labels/00000001_street.txt # class cx cy w h, normalized
53
+ ```
54
+
55
+ ```bash
56
+ yolo detect train data=Lannotex-export-1a2b3c4d/data.yaml model=yolo11n.pt
57
+ ```
58
+
59
+ - Images are **hard-linked** into `images/` when the export is on the same drive, so they
60
+ take no extra space. Otherwise they're copied. Your originals are never modified.
61
+ - Images marked **No target objects** get an empty label file, so YOLO learns them as
62
+ background.
63
+ - Images you haven't annotated yet are **left out**. If they were included, YOLO would
64
+ treat them as "nothing here".
65
+ - `train` and `val` point at the same images. Split them yourself for a real evaluation.
66
+ - If you move the export folder, update `path:` in `data.yaml`.
47
67
 
48
68
  ## Importing annotations
49
69
 
@@ -1,2 +1,2 @@
1
1
  """Lannotex: offline-first image annotation."""
2
- __version__ = "0.1.0"
2
+ __version__ = "0.1.1"
@@ -2,7 +2,9 @@
2
2
  from __future__ import annotations
3
3
  import csv
4
4
  import json
5
+ import os
5
6
  from pathlib import Path
7
+ import shutil
6
8
  import tempfile
7
9
  import uuid
8
10
  from . import __version__
@@ -76,6 +78,19 @@ def coco_record(image, annotations, labels):
76
78
  return {'images':[image],'categories':[{'id':i+1,'name':s} for i,s in enumerate(labels)],'annotations':output}
77
79
 
78
80
 
81
+ def link_or_copy(source, target):
82
+ try: os.link(source, target)
83
+ except OSError: shutil.copy2(source, target)
84
+
85
+
86
+ def yolo_data_yaml(root, labels):
87
+ names = '\n'.join(f' {i}: {json.dumps(name)}' for i, name in enumerate(labels))
88
+ return ('# Ultralytics YOLO dataset exported by Lannotex.\n'
89
+ '# Train: yolo detect train data=data.yaml model=yolo11n.pt\n'
90
+ "# Update 'path' if you move this folder. train and val use the same images; split them for real evaluation.\n"
91
+ f'path: {json.dumps(str(root))}\ntrain: images\nval: images\nnames:\n{names}\n')
92
+
93
+
79
94
  def export_project(root, destination, format_name, cancel, progress):
80
95
  """Stream a consistent DB snapshot; publish the completed directory by rename."""
81
96
  project = Project(root,create=False)
@@ -87,6 +102,8 @@ def export_project(root, destination, format_name, cancel, progress):
87
102
  try:
88
103
  labels = [r['name'] for r in project.labels()]
89
104
  atomic_text(output/'classes.json',json.dumps(labels,indent=2))
105
+ yolo = format_name == 'YOLO boxes'
106
+ if yolo: (output/'images').mkdir(); (output/'labels').mkdir()
90
107
  # Spool COCO arrays to disk, rather than keeping all annotations in RAM.
91
108
  with (output/'images.jsonl').open('w',encoding='utf-8') as ims, (output/'annotations.jsonl').open('w',encoding='utf-8') as anns, (output/'classification.csv').open('w',encoding='utf-8',newline='') as csvfile:
92
109
  writer = csv.writer(csvfile); writer.writerow(['image_id','image_path','status',*labels])
@@ -104,6 +121,10 @@ def export_project(root, destination, format_name, cancel, progress):
104
121
  summary['skipped'] += 1
105
122
  if len(summary['errors'])<100: summary['errors'].append(f"{row['path']}: {'; '.join(errors)}")
106
123
  continue
124
+ if yolo and row['status']=='new':
125
+ # YOLO reads an empty label file as "no objects"; never-annotated images would become false negatives.
126
+ summary['unlabeled'] += 1
127
+ continue
107
128
  summary['included'] += 1
108
129
  if row['status']=='new': summary['unlabeled'] += 1
109
130
  name = f"{row['id']:08d}_{Path(row['path']).stem}"
@@ -112,9 +133,11 @@ def export_project(root, destination, format_name, cancel, progress):
112
133
  ims.write(json.dumps(image)+'\n')
113
134
  if format_name == 'Labelme JSON':
114
135
  atomic_text(output/(name+'.json'),json.dumps(labelme_data(source,row['width'],row['height'],annotations,negative),indent=2))
115
- elif format_name == 'YOLO boxes':
136
+ elif yolo:
116
137
  lines = [yolo_line(a,labels.index(a.label)) for a in annotations if a.kind=='box']
117
- atomic_text(output/(name+'.txt'),'\n'.join(lines)+ ('\n' if lines else ''))
138
+ source_path = project.resolve(row['path'])
139
+ link_or_copy(source_path, output/'images'/(name+source_path.suffix.lower()))
140
+ atomic_text(output/'labels'/(name+'.txt'),'\n'.join(lines)+ ('\n' if lines else ''))
118
141
  summary['unsupported_annotations'] += sum(a.kind!='box' for a in annotations)
119
142
  elif format_name == 'COCO JSON':
120
143
  record = coco_record(image,annotations,labels)
@@ -138,9 +161,11 @@ def export_project(root, destination, format_name, cancel, progress):
138
161
  stream.write(line.strip()); first=False
139
162
  stream.write(sep)
140
163
  stream.write(json.dumps([{'id':i+1,'name':s} for i,s in enumerate(labels)])+'}')
141
- atomic_text(output/'manifest.json',json.dumps({'version':__version__,'format_version':1,'editable_local_export':True,'image_policy':'Referenced, not copied','summary':summary},indent=2))
164
+ policy = 'Hard-linked or copied into images/' if yolo else 'Referenced, not copied'
165
+ atomic_text(output/'manifest.json',json.dumps({'version':__version__,'format_version':1,'editable_local_export':True,'image_policy':policy,'summary':summary},indent=2))
142
166
  if not summary.get('cancelled'):
143
167
  final = destination/('Lannotex-export-'+uuid.uuid4().hex[:8]); output.rename(final); output=final
168
+ if yolo: atomic_text(output/'data.yaml', yolo_data_yaml(output.resolve(), labels))
144
169
  summary['path'] = str(output)
145
170
  return summary
146
171
  finally:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: lannotex
3
- Version: 0.1.0
3
+ Version: 0.1.1
4
4
  Summary: Fast, offline-first image annotation for classifications, boxes, and polygons.
5
5
  Author: Lourdhu Raju
6
6
  Maintainer: Lourdhu Raju
@@ -133,7 +133,7 @@ Every shortcut can be remapped. See the [annotating guide](https://lourdhu02.git
133
133
  | **Annotate** | Bounding boxes · polygons with vertex drag, insert, and delete · multi-label image classes · "no target" negatives · 100-step undo/redo · zoom under the pointer, pan, arrow-key nudging · focus mode · light and dark themes |
134
134
  | **Stay safe** | SQLite projects with versioned migrations · recovery drafts and 700 ms autosave · transactional saves · geometry validation · backup and restore · relinking for moved images · EXIF orientation handled |
135
135
  | **Scale** | Virtualized image list (at most 1,024 records in memory) · background import and decoding · 96 MB preview cache · coordinates normalized to the original resolution |
136
- | **Export** | Labelme JSON · YOLO · COCO JSON · classification CSV · lossless native JSONL · each export reports anything it skipped |
136
+ | **Export** | Labelme JSON · ready-to-train YOLO (`images/`, `labels/`, `data.yaml`) · COCO JSON · classification CSV · lossless native JSONL · each export reports anything it skipped |
137
137
  | **Automate** | `lannotex export` and `lannotex analyze` run headless in CI, with no display needed |
138
138
  | **Collaborate** | Optional LAN host with per-reviewer tokens, background sync, revision conflicts you resolve explicitly, revocation, and an audit history |
139
139
 
@@ -181,8 +181,8 @@ hashes. There is no telemetry, no external AI service, and no automatic upload.
181
181
 
182
182
  ## Roadmap
183
183
 
184
- Next up: a ready-to-train YOLO layout (`images/`, `labels/`, `data.yaml`), more LabelMe
185
- shape types, VOC and YOLO-seg export, and number-key label selection. See the
184
+ Next up: more LabelMe shape types (points, lines, circles), VOC and YOLO-seg export, and
185
+ number-key label selection. See the
186
186
  [roadmap](https://lourdhu02.github.io/Lannotex/ROADMAP/) and the
187
187
  [measured performance](https://lourdhu02.github.io/Lannotex/PERFORMANCE/).
188
188
 
@@ -1,7 +1,10 @@
1
1
  """Exporter primitives and headless project export."""
2
+ import json
2
3
  from pathlib import Path
3
4
  import threading
4
5
 
6
+ from PIL import Image
7
+
5
8
  from lannotex import __version__
6
9
  from lannotex.domain import Annotation
7
10
  from lannotex.exporters import coco_record, export_project, labelme_data, parse_labelme, yolo_line
@@ -61,3 +64,27 @@ def test_export_project_empty_creates_manifest(tmp_path):
61
64
  assert (out / "classes.json").exists()
62
65
  assert (out / "manifest.json").exists()
63
66
  assert (out / "images.jsonl").exists()
67
+
68
+
69
+ def test_yolo_export_is_ultralytics_ready(tmp_path):
70
+ src = tmp_path / "imgs"; src.mkdir()
71
+ Image.new("RGB", (200, 100)).save(src / "a.png")
72
+ Image.new("RGB", (50, 50)).save(src / "b.jpg")
73
+ Image.new("RGB", (50, 50)).save(src / "c.png")
74
+ root = tmp_path / "project"; p = Project(root); p.add_label("cat"); p.add_label("dog")
75
+ a = p.add_image(src / "a.png", 200, 100); b = p.add_image(src / "b.jpg", 50, 50); p.add_image(src / "c.png", 50, 50)
76
+ p.save_annotations(a, [Annotation("dog", "box", [.1, .2, .5, .6]), Annotation("cat", "polygon", [[0, 0], [1, 0], [1, 1]])])
77
+ p.save_annotations(b, [], negative=True)
78
+ p.close()
79
+
80
+ result = export_project(root, tmp_path / "out", "YOLO boxes", threading.Event(), lambda *args: None)
81
+ out = Path(result["path"])
82
+ assert result["included"] == 2 and result["unlabeled"] == 1 and result["unsupported_annotations"] == 1
83
+ images = sorted(f.name for f in (out / "images").iterdir())
84
+ labels = sorted(f.name for f in (out / "labels").iterdir())
85
+ assert [Path(n).stem for n in images] == [Path(n).stem for n in labels] and len(images) == 2
86
+ assert (out / "labels" / labels[0]).read_text() == "1 0.300000 0.400000 0.400000 0.400000\n"
87
+ assert (out / "labels" / labels[1]).read_text() == ""
88
+ data = (out / "data.yaml").read_text()
89
+ assert "train: images" in data and '0: "cat"' in data and '1: "dog"' in data
90
+ assert json.loads(data.split("path: ")[1].splitlines()[0]) == str(out.resolve())
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes