Skip to content

Conversation

@steven-murray
Copy link
Owner

@steven-murray steven-murray commented Feb 3, 2025

Fixes #37

Allows some fields to be multi-field capable, separated by ';'. In this case, the track gets added to each group.

Summary by Sourcery

Bug Fixes:

  • Fix a bug where tracks were only added to the first group when using multi-field values for grouping.

@steven-murray steven-murray self-assigned this Feb 3, 2025
@sourcery-ai
Copy link

sourcery-ai bot commented Feb 3, 2025

Reviewer's Guide by Sourcery

This pull request introduces multi-field support for the group_by function, allowing items to be grouped by multiple values within a single field, separated by ';'. The fields that support multiple values are: albumartist, artist, and genre.

Class diagram showing updated group_by function

classDiagram
    class group_by {
        +multifield_categories: list
        +group_by(category: str, items: list) dict
    }
    note for group_by "New multifield support for albumartist, artist, genre"
Loading

Flow diagram for multi-field grouping process

graph TD
    A[Start] --> B[Get item's category value]
    B --> C{Is category multi-field?}
    C -->|Yes| D[Split value by ';']
    C -->|No| E[Use value as is]
    D --> F[Strip whitespace]
    E --> G[Add item to group]
    F --> G
    G --> H{More items?}
    H -->|Yes| B
    H -->|No| I[End]
Loading

File-Level Changes

Change Details Files
Modified the group_by function to support multi-valued fields.
  • Added a list of categories that support multiple values.
  • Modified the loop to split the category value by ';' if it is a multi-valued field.
  • Added the item to each of the groups.
beetsplug/summarize.py
Added a test case to verify the multi-field functionality.
  • Added a new item with multiple artists.
  • Added a test case to verify that the item is added to each of the artist groups.
tests/test_summarize.py

Assessment against linked issues

Issue Objective Addressed Explanation
#37 Support multi-value fields for genres and artists
#37 Allow splitting multi-value fields by semicolon
#37 Enable seeing stats on multi-value fields

Possibly linked issues

  • Multi-value Field Support #37: The PR implements multi-value fields separated by semicolons. It addresses the issue by allowing multiple values for certain fields like albumartist, artist, and genre.

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!
  • Generate a plan of action for an issue: Comment @sourcery-ai plan on
    an issue to generate a plan of action for it.

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@steven-murray steven-murray added the enhancement New feature or request label Feb 3, 2025
Copy link

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @steven-murray - I've reviewed your changes and they look great!

Here's what I looked at during the review
  • 🟡 General issues: 1 issue found
  • 🟢 Security: all looks good
  • 🟡 Testing: 3 issues found
  • 🟢 Complexity: all looks good
  • 🟢 Documentation: all looks good

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment on lines +121 to +126
def group_by(category: str, items):
"""Group a list of items by a category.
If the category is one that supports multiple values, split them by ";" and add
the item to each of the groups.
"""
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: Consider handling edge cases where 'cat' is None or an empty string

The current implementation might create groups with empty keys or raise exceptions for None values. Consider adding validation or explicit handling for these cases.

Suggested change
def group_by(category: str, items):
"""Group a list of items by a category.
If the category is one that supports multiple values, split them by ";" and add
the item to each of the groups.
"""
def group_by(category: str | None, items: list) -> dict:
"""Group a list of items by a category.
If the category is one that supports multiple values, split them by ";" and add
the item to each of the groups.
Args:
category: The category to group by. If None or empty string, returns empty dict.
items: List of items to group.
Returns:
A dictionary mapping category values to lists of items.
"""
if not category: # Handles None and empty string
return {}

Comment on lines +37 to +45
lib.add(
MockItem(
"song4",
2003,
"artist3; artist4",
"album4",
700,
"so many lyrics in this song",
)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (testing): Suggest adding more test cases for multi-field handling with edge cases.

It would be beneficial to add tests for edge cases like empty strings, strings with only delimiters, and combinations of valid and invalid multi-field values. For example, consider cases like 'artist1;;artist2', ';artist1;artist2;', ' ', and '' to ensure the function handles these scenarios correctly.

Suggested implementation:

    lib.add(MockItem("song1", 2000, "artist1", "album1", 128, "lyrics1"))
    lib.add(MockItem("song2", 2001, "artist2", "album2", 256, "lyrics2"))
    lib.add(MockItem("song3", 2002, "artist3", "album3", 512, "lyrics3"))
    lib.add(
        MockItem(
            "song4",
            2003,
            "artist3; artist4",
            "album4",
            700,
            "so many lyrics in this song",
        )
    )
    # Edge cases for multi-field handling
    lib.add(
        MockItem(
            "song5",
            2004,
            "artist1;;artist2",  # Double delimiter
            "album5",
            800,
            "lyrics5",
        )
    )
    lib.add(
        MockItem(
            "song6",
            2005,
            ";artist1;artist2;",  # Leading/trailing delimiters
            "album6",
            900,
            "lyrics6",
        )
    )
    lib.add(
        MockItem(
            "song7",
            2006,
            " ",  # Just whitespace
            "album7",
            1000,
            "lyrics7",
        )
    )
    lib.add(
        MockItem(
            "song8",
            2007,
            "",  # Empty string
            "album8",
            1100,
            "lyrics8",
        )
    )
    lib.add(
        MockItem(
            "song9",
            2008,
            " artist1 ; artist2 ",  # Whitespace around delimiters
            "album9",
            1200,
            "lyrics9",
        )
    )

    return lib

You'll need to:

  1. Add corresponding assertions in the test functions to verify these edge cases are handled correctly
  2. Ensure the library's parsing logic properly handles these edge cases (empty strings, multiple delimiters, whitespace)
  3. Update any relevant documentation to describe the expected behavior for these edge cases

Comment on lines +100 to +101
assert "artist3 | 2" in txt # in the multi-field
assert "artist4 | 1" in txt # in the multi-field
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (testing): Consider using more precise assertions.

Instead of checking if a substring exists in the output, it's better to parse the output and assert on the specific values. This makes the test less brittle and provides more informative error messages when it fails. For example, you could split the output by lines and then by '|' to check the counts for each artist.

"so many lyrics in this song",
)
)

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (testing): Missing tests for other multifield_categories.

The description mentions that multiple fields are now supported. The tests only cover the artist field. Add tests for albumartist and genre as well to ensure complete coverage of the new functionality.

Suggested implementation:

    lib.add(
        MockItem(
            "song4",
            2003,
            "artist3; artist4",
            "album4",
            700,
            "so many lyrics in this song",
        )
    )

    # Add items with multiple albumartists
    lib.add(
        MockItem(
            "song5",
            2004,
            "artist5",
            "album5",
            800,
            "lyrics5",
            albumartist="albumartist1; albumartist2"
        )
    )

    # Add items with multiple genres
    lib.add(
        MockItem(
            "song6",
            2005,
            "artist6",
            "album6",
            900,
            "lyrics6",
            genre="rock; pop"
        )
    )

    return lib


    assert "2000 |" in txt
def test_show_summary_artist(lib):
    stats = "count"
    txt = sm.show_summary(lib, "query", category="artist", stats=stats, reverse=False)

    assert "artist1 | 1" in txt
    assert "artist2 | 1" in txt
    assert "artist3 | 2" in txt  # in the multi-field
    assert "artist4 | 1" in txt  # in the multi-field

def test_show_summary_albumartist(lib):
    stats = "count"
    txt = sm.show_summary(lib, "query", category="albumartist", stats=stats, reverse=False)

    assert "albumartist1 | 1" in txt  # in the multi-field
    assert "albumartist2 | 1" in txt  # in the multi-field

def test_show_summary_genre(lib):
    stats = "count"
    txt = sm.show_summary(lib, "query", category="genre", stats=stats, reverse=False)

    assert "rock | 1" in txt  # in the multi-field
    assert "pop | 1" in txt   # in the multi-field

Note: The MockItem class constructor might need to be updated to accept albumartist and genre parameters if they're not already supported. You may need to add these fields to the MockItem class definition if they don't exist.

@steven-murray steven-murray merged commit 41588ac into main Feb 3, 2025
28 checks passed
@steven-murray steven-murray deleted the multi-fields branch February 3, 2025 18:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Multi-value Field Support

2 participants