rekordbox-edit 0.4.0.dev22__tar.gz → 0.4.0.dev23__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.
- {rekordbox_edit-0.4.0.dev22 → rekordbox_edit-0.4.0.dev23}/CHANGELOG.md +2 -1
- {rekordbox_edit-0.4.0.dev22 → rekordbox_edit-0.4.0.dev23}/PKG-INFO +1 -1
- {rekordbox_edit-0.4.0.dev22 → rekordbox_edit-0.4.0.dev23}/pyproject.toml +1 -1
- {rekordbox_edit-0.4.0.dev22 → rekordbox_edit-0.4.0.dev23}/rekordbox_edit/commands/edit.py +8 -2
- {rekordbox_edit-0.4.0.dev22 → rekordbox_edit-0.4.0.dev23}/tests/commands/test_edit.py +101 -0
- {rekordbox_edit-0.4.0.dev22 → rekordbox_edit-0.4.0.dev23}/uv.lock +1 -1
- {rekordbox_edit-0.4.0.dev22 → rekordbox_edit-0.4.0.dev23}/.agent-style/RULES.md +0 -0
- {rekordbox_edit-0.4.0.dev22 → rekordbox_edit-0.4.0.dev23}/.agent-style/claude-code.md +0 -0
- {rekordbox_edit-0.4.0.dev22 → rekordbox_edit-0.4.0.dev23}/.github/actions/commitizen-bump/action.yml +0 -0
- {rekordbox_edit-0.4.0.dev22 → rekordbox_edit-0.4.0.dev23}/.github/actions/commitizen-bump/commitizen-bump.sh +0 -0
- {rekordbox_edit-0.4.0.dev22 → rekordbox_edit-0.4.0.dev23}/.github/actions/install/action.yml +0 -0
- {rekordbox_edit-0.4.0.dev22 → rekordbox_edit-0.4.0.dev23}/.github/actions/lint/action.yml +0 -0
- {rekordbox_edit-0.4.0.dev22 → rekordbox_edit-0.4.0.dev23}/.github/actions/test/action.yml +0 -0
- {rekordbox_edit-0.4.0.dev22 → rekordbox_edit-0.4.0.dev23}/.github/workflows/cd.yml +0 -0
- {rekordbox_edit-0.4.0.dev22 → rekordbox_edit-0.4.0.dev23}/.github/workflows/ci.yml +0 -0
- {rekordbox_edit-0.4.0.dev22 → rekordbox_edit-0.4.0.dev23}/.github/workflows/publish.yml +0 -0
- {rekordbox_edit-0.4.0.dev22 → rekordbox_edit-0.4.0.dev23}/.github/workflows/release.yml +0 -0
- {rekordbox_edit-0.4.0.dev22 → rekordbox_edit-0.4.0.dev23}/.gitignore +0 -0
- {rekordbox_edit-0.4.0.dev22 → rekordbox_edit-0.4.0.dev23}/.pre-commit-config.yaml +0 -0
- {rekordbox_edit-0.4.0.dev22 → rekordbox_edit-0.4.0.dev23}/AGENTS.md +0 -0
- {rekordbox_edit-0.4.0.dev22 → rekordbox_edit-0.4.0.dev23}/CLAUDE.md +0 -0
- {rekordbox_edit-0.4.0.dev22 → rekordbox_edit-0.4.0.dev23}/CONTRIBUTING.md +0 -0
- {rekordbox_edit-0.4.0.dev22 → rekordbox_edit-0.4.0.dev23}/LICENSE +0 -0
- {rekordbox_edit-0.4.0.dev22 → rekordbox_edit-0.4.0.dev23}/Makefile +0 -0
- {rekordbox_edit-0.4.0.dev22 → rekordbox_edit-0.4.0.dev23}/README.md +0 -0
- {rekordbox_edit-0.4.0.dev22 → rekordbox_edit-0.4.0.dev23}/codecov.yml +0 -0
- {rekordbox_edit-0.4.0.dev22 → rekordbox_edit-0.4.0.dev23}/rekordbox_edit/__init__.py +0 -0
- {rekordbox_edit-0.4.0.dev22 → rekordbox_edit-0.4.0.dev23}/rekordbox_edit/_click.py +0 -0
- {rekordbox_edit-0.4.0.dev22 → rekordbox_edit-0.4.0.dev23}/rekordbox_edit/cli.py +0 -0
- {rekordbox_edit-0.4.0.dev22 → rekordbox_edit-0.4.0.dev23}/rekordbox_edit/commands/__init__.py +0 -0
- {rekordbox_edit-0.4.0.dev22 → rekordbox_edit-0.4.0.dev23}/rekordbox_edit/commands/convert.py +0 -0
- {rekordbox_edit-0.4.0.dev22 → rekordbox_edit-0.4.0.dev23}/rekordbox_edit/commands/search.py +0 -0
- {rekordbox_edit-0.4.0.dev22 → rekordbox_edit-0.4.0.dev23}/rekordbox_edit/logger.py +0 -0
- {rekordbox_edit-0.4.0.dev22 → rekordbox_edit-0.4.0.dev23}/rekordbox_edit/query.py +0 -0
- {rekordbox_edit-0.4.0.dev22 → rekordbox_edit-0.4.0.dev23}/rekordbox_edit/utils.py +0 -0
- {rekordbox_edit-0.4.0.dev22 → rekordbox_edit-0.4.0.dev23}/renovate.json5 +0 -0
- {rekordbox_edit-0.4.0.dev22 → rekordbox_edit-0.4.0.dev23}/ruff.toml +0 -0
- {rekordbox_edit-0.4.0.dev22 → rekordbox_edit-0.4.0.dev23}/tests/__init__.py +0 -0
- {rekordbox_edit-0.4.0.dev22 → rekordbox_edit-0.4.0.dev23}/tests/commands/__init__.py +0 -0
- {rekordbox_edit-0.4.0.dev22 → rekordbox_edit-0.4.0.dev23}/tests/commands/test_convert.py +0 -0
- {rekordbox_edit-0.4.0.dev22 → rekordbox_edit-0.4.0.dev23}/tests/commands/test_search.py +0 -0
- {rekordbox_edit-0.4.0.dev22 → rekordbox_edit-0.4.0.dev23}/tests/conftest.py +0 -0
- {rekordbox_edit-0.4.0.dev22 → rekordbox_edit-0.4.0.dev23}/tests/test_logger.py +0 -0
- {rekordbox_edit-0.4.0.dev22 → rekordbox_edit-0.4.0.dev23}/tests/test_query.py +0 -0
- {rekordbox_edit-0.4.0.dev22 → rekordbox_edit-0.4.0.dev23}/tests/test_utils.py +0 -0
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
## v0.4.0.
|
|
1
|
+
## v0.4.0.dev23 (2026-05-17)
|
|
2
2
|
|
|
3
3
|
|
|
4
|
+
- feat(edit): add --multi to allow batch edits past single-track guard
|
|
4
5
|
- feat(edit): add --match for literal find/replace within field value
|
|
5
6
|
- Introduces a _compute_new_value helper and --match option so that
|
|
6
7
|
rbe edit can replace a substring of the current field value instead of
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: rekordbox-edit
|
|
3
|
-
Version: 0.4.0.
|
|
3
|
+
Version: 0.4.0.dev23
|
|
4
4
|
Summary: Tools for managing and modifying a RekordBox library en-masse
|
|
5
5
|
Project-URL: Homepage, https://github.com/jviall/rekordbox-edit
|
|
6
6
|
Project-URL: Repository, https://github.com/jviall/rekordbox-edit
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "rekordbox-edit"
|
|
7
|
-
version = "0.4.0.
|
|
7
|
+
version = "0.4.0.dev23"
|
|
8
8
|
description = "Tools for managing and modifying a RekordBox library en-masse"
|
|
9
9
|
authors = [{ name = "James Viall", email= "jamesviall@pm.me"}]
|
|
10
10
|
license = "MIT"
|
|
@@ -73,6 +73,11 @@ def _compute_new_value(
|
|
|
73
73
|
metavar="PATTERN",
|
|
74
74
|
help="Find this literal string within the field value and replace only that portion",
|
|
75
75
|
)
|
|
76
|
+
@click.option(
|
|
77
|
+
"--multi",
|
|
78
|
+
is_flag=True,
|
|
79
|
+
help="Allow editing more than one track (required when filters match multiple tracks)",
|
|
80
|
+
)
|
|
76
81
|
@track_ids_argument
|
|
77
82
|
@click.argument(
|
|
78
83
|
"field",
|
|
@@ -82,6 +87,7 @@ def edit_command(
|
|
|
82
87
|
field: str,
|
|
83
88
|
replace_value: str,
|
|
84
89
|
match_pattern: str | None,
|
|
90
|
+
multi: bool,
|
|
85
91
|
dry_run: bool,
|
|
86
92
|
yes: bool,
|
|
87
93
|
interactive: bool,
|
|
@@ -157,10 +163,10 @@ def edit_command(
|
|
|
157
163
|
logger.info("No changes to make.")
|
|
158
164
|
return
|
|
159
165
|
|
|
160
|
-
if len(edits) > 1:
|
|
166
|
+
if len(edits) > 1 and not multi:
|
|
161
167
|
raise click.UsageError(
|
|
162
168
|
f"Found {len(edits)} tracks that would be edited. "
|
|
163
|
-
"Refine your filters,
|
|
169
|
+
"Refine your filters, use --dry-run to inspect, or pass --multi to edit all."
|
|
164
170
|
)
|
|
165
171
|
|
|
166
172
|
print_track_info([t for t, _ in edits])
|
|
@@ -427,3 +427,104 @@ class TestEditCommandUnicode:
|
|
|
427
427
|
|
|
428
428
|
assert result.exit_code == 0
|
|
429
429
|
mock_db.session.commit.assert_not_called()
|
|
430
|
+
|
|
431
|
+
|
|
432
|
+
class TestEditCommandPhase4:
|
|
433
|
+
"""Phase 4: --multi flag to allow batch edits past the single-track guard."""
|
|
434
|
+
|
|
435
|
+
@patch("rekordbox_edit.commands.edit.confirm")
|
|
436
|
+
@patch("rekordbox_edit.commands.edit.get_filtered_content")
|
|
437
|
+
@patch("rekordbox_edit.commands.edit.Rekordbox6Database")
|
|
438
|
+
def test_multi_allows_editing_multiple_tracks(
|
|
439
|
+
self, mock_db_class, mock_gfc, mock_confirm, make_djmd_content_item
|
|
440
|
+
):
|
|
441
|
+
"""--multi bypasses the single-track guard and edits all matched tracks."""
|
|
442
|
+
tracks = [
|
|
443
|
+
make_djmd_content_item(Title="Track A (feat. X)"),
|
|
444
|
+
make_djmd_content_item(Title="Track B (feat. Y)"),
|
|
445
|
+
]
|
|
446
|
+
mock_db, mock_result = _make_db_and_result(tracks)
|
|
447
|
+
mock_db_class.return_value = mock_db
|
|
448
|
+
mock_gfc.return_value = mock_result
|
|
449
|
+
mock_confirm.return_value = True
|
|
450
|
+
|
|
451
|
+
from click.testing import CliRunner
|
|
452
|
+
result = CliRunner().invoke(
|
|
453
|
+
edit_command,
|
|
454
|
+
["Title", "--match", "feat.", "--replace", "ft.", "--multi"],
|
|
455
|
+
)
|
|
456
|
+
|
|
457
|
+
assert result.exit_code == 0
|
|
458
|
+
assert tracks[0].Title == "Track A (ft. X)"
|
|
459
|
+
assert tracks[1].Title == "Track B (ft. Y)"
|
|
460
|
+
mock_db.session.commit.assert_called_once()
|
|
461
|
+
|
|
462
|
+
@patch("rekordbox_edit.commands.edit.get_filtered_content")
|
|
463
|
+
@patch("rekordbox_edit.commands.edit.Rekordbox6Database")
|
|
464
|
+
def test_without_multi_still_aborts_on_multiple(
|
|
465
|
+
self, mock_db_class, mock_gfc, make_djmd_content_item
|
|
466
|
+
):
|
|
467
|
+
"""Without --multi, the single-track guard still aborts on multiple matches."""
|
|
468
|
+
tracks = [
|
|
469
|
+
make_djmd_content_item(Title="Track A"),
|
|
470
|
+
make_djmd_content_item(Title="Track B"),
|
|
471
|
+
]
|
|
472
|
+
mock_db, mock_result = _make_db_and_result(tracks)
|
|
473
|
+
mock_db_class.return_value = mock_db
|
|
474
|
+
mock_gfc.return_value = mock_result
|
|
475
|
+
|
|
476
|
+
from click.testing import CliRunner
|
|
477
|
+
result = CliRunner().invoke(
|
|
478
|
+
edit_command, ["Title", "--replace", "New", "--yes"]
|
|
479
|
+
)
|
|
480
|
+
|
|
481
|
+
assert result.exit_code != 0
|
|
482
|
+
mock_db.session.commit.assert_not_called()
|
|
483
|
+
|
|
484
|
+
@patch("rekordbox_edit.commands.edit.confirm")
|
|
485
|
+
@patch("rekordbox_edit.commands.edit.get_filtered_content")
|
|
486
|
+
@patch("rekordbox_edit.commands.edit.Rekordbox6Database")
|
|
487
|
+
def test_multi_with_yes_skips_confirm(
|
|
488
|
+
self, mock_db_class, mock_gfc, mock_confirm, make_djmd_content_item
|
|
489
|
+
):
|
|
490
|
+
"""--multi --yes edits multiple tracks without prompting."""
|
|
491
|
+
tracks = [
|
|
492
|
+
make_djmd_content_item(Title="Track A"),
|
|
493
|
+
make_djmd_content_item(Title="Track B"),
|
|
494
|
+
]
|
|
495
|
+
mock_db, mock_result = _make_db_and_result(tracks)
|
|
496
|
+
mock_db_class.return_value = mock_db
|
|
497
|
+
mock_gfc.return_value = mock_result
|
|
498
|
+
|
|
499
|
+
from click.testing import CliRunner
|
|
500
|
+
result = CliRunner().invoke(
|
|
501
|
+
edit_command,
|
|
502
|
+
["Title", "--replace", "New", "--multi", "--yes"],
|
|
503
|
+
)
|
|
504
|
+
|
|
505
|
+
assert result.exit_code == 0
|
|
506
|
+
mock_confirm.assert_not_called()
|
|
507
|
+
mock_db.session.commit.assert_called_once()
|
|
508
|
+
|
|
509
|
+
@patch("rekordbox_edit.commands.edit.confirm")
|
|
510
|
+
@patch("rekordbox_edit.commands.edit.get_filtered_content")
|
|
511
|
+
@patch("rekordbox_edit.commands.edit.Rekordbox6Database")
|
|
512
|
+
def test_multi_single_track_still_works(
|
|
513
|
+
self, mock_db_class, mock_gfc, mock_confirm, make_djmd_content_item
|
|
514
|
+
):
|
|
515
|
+
"""--multi with only one matching track works fine (guard is not inverted)."""
|
|
516
|
+
track = make_djmd_content_item(Title="Only Track")
|
|
517
|
+
mock_db, mock_result = _make_db_and_result([track])
|
|
518
|
+
mock_db_class.return_value = mock_db
|
|
519
|
+
mock_gfc.return_value = mock_result
|
|
520
|
+
mock_confirm.return_value = True
|
|
521
|
+
|
|
522
|
+
from click.testing import CliRunner
|
|
523
|
+
result = CliRunner().invoke(
|
|
524
|
+
edit_command,
|
|
525
|
+
["Title", "--replace", "New Title", "--multi"],
|
|
526
|
+
)
|
|
527
|
+
|
|
528
|
+
assert result.exit_code == 0
|
|
529
|
+
assert track.Title == "New Title"
|
|
530
|
+
mock_db.session.commit.assert_called_once()
|
|
File without changes
|
|
File without changes
|
{rekordbox_edit-0.4.0.dev22 → rekordbox_edit-0.4.0.dev23}/.github/actions/commitizen-bump/action.yml
RENAMED
|
File without changes
|
|
File without changes
|
{rekordbox_edit-0.4.0.dev22 → rekordbox_edit-0.4.0.dev23}/.github/actions/install/action.yml
RENAMED
|
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
|
{rekordbox_edit-0.4.0.dev22 → rekordbox_edit-0.4.0.dev23}/rekordbox_edit/commands/__init__.py
RENAMED
|
File without changes
|
{rekordbox_edit-0.4.0.dev22 → rekordbox_edit-0.4.0.dev23}/rekordbox_edit/commands/convert.py
RENAMED
|
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
|