Skip to content

spanner.py backward compatible changes#1807

Merged
mscuthbert merged 11 commits into
cuthbertLab:masterfrom
gregchapman-dev:gregc/pendingSpannerAssignmentWithOffset
May 13, 2026
Merged

spanner.py backward compatible changes#1807
mscuthbert merged 11 commits into
cuthbertLab:masterfrom
gregchapman-dev:gregc/pendingSpannerAssignmentWithOffset

Conversation

@gregchapman-dev
Copy link
Copy Markdown
Contributor

New features in spanner.py: (1) Let pending spanner element assignments have an associated required offset and clientInfo (if not specified, behaves as before). (2) new API insertFirstSpannedElement (3) new API popPendingSpannedElements. Also a fix that saves/restores spanner element offset/activeSite around operations that clear them.

…ts have an associated required offset and clientInfo (if not specified, behaves as before). (2) new API insertFirstSpannedElement (3) new API popPendingSpannedElements. Also a fix that saves/restores spanner element offset/activeSite around operations that clear them.
@gregchapman-dev
Copy link
Copy Markdown
Contributor Author

This is the second split-out PR from PR #1768

@coveralls
Copy link
Copy Markdown

coveralls commented Jul 26, 2025

Coverage Status

coverage: 93.069% (+0.001%) from 93.068% — gregchapman-dev:gregc/pendingSpannerAssignmentWithOffset into cuthbertLab:master

@gregchapman-dev
Copy link
Copy Markdown
Contributor Author

All merged, and it looks like the tests are passing. Ready for review.

@gregchapman-dev
Copy link
Copy Markdown
Contributor Author

Argh. Gotta test those new APIs that no-one is calling yet. Hang on.

Copy link
Copy Markdown
Member

@mscuthbert mscuthbert left a comment

Choose a reason for hiding this comment

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

Hi Greg -- can you talk through your proposed contribution with another music21 user to help get down on paper what exactly the benefit to the library of this contribution is? I feel like I've tried many times to understand what is happening and I still don't see it, and I need to get to other projects until I do. Thanks.

Comment thread music21/spanner.py Outdated
Comment thread music21/_version.py Outdated
Comment thread music21/spanner.py Outdated
Comment thread music21/spanner.py Outdated
Comment thread music21/spanner.py Outdated
Comment thread music21/spanner.py Outdated
@gregchapman-dev
Copy link
Copy Markdown
Contributor Author

Maybe I should discuss this with @jacobtylerwalls, since he has been in the MusicXML reader a lot.

@gregchapman-dev
Copy link
Copy Markdown
Contributor Author

gregchapman-dev commented Aug 12, 2025

I've tried to explain carefully in the doctests exactly what is intended here, in terms of how these APIs have been used in the past (which still works) and how they can be used in the future (and why).

I restored the old doctests to show that they still pass (although I tweaked the order of calls a bit to match the order of the "old-style" calls that come from xmlToM21.py). Then I added the new doctests, and enhanced them (and their comments) to show how a parser can use the new parameters to deal with the fact that sometimes there is no "next note" that is at the correct offset to start the spanner, so a SpannerAnchor should be used instead.

The next PR will be the one that changes xmlToM21.py to take advantage of the new-style calls, to handle <direction> with <offset> by inserting a SpannerAnchor at the correct offset.

@mscuthbert
Copy link
Copy Markdown
Member

make it staffKey: int|None -- now it makes sense why we might only want to free up spanned elements on one staff. Making something too hypothetical doesn't help me get why we want to add this complexity to the system.

Just please show that the way things were working before will still work -- I don't normally need to know the offset of the pending assignment in order to get it. But if there are multiple pending I can free just one by offset? Just show that -- then it's a new feature.

@gregchapman-dev
Copy link
Copy Markdown
Contributor Author

gregchapman-dev commented Aug 13, 2025

Ooops, I was editing my comment while you were commenting on my previous comment: Here's my new one again:

I've tried to explain carefully in the doctests exactly what is intended here, in terms of how these APIs have been used in the past (which still works) and how they can be used in the future (and why).

I restored the old doctests to show that they still pass (although I tweaked the order of calls a bit to match the order of the "old-style" calls that come from xmlToM21.py). Then I added the new doctests, and enhanced them (and their comments) to show how a parser can use the new parameters to deal with the fact that sometimes there is no "next note" that is at the correct offset to start the spanner, so a SpannerAnchor should be used instead.

The next PR will be the one that changes xmlToM21.py to take advantage of the new-style calls, to handle <direction> with <offset> by inserting a SpannerAnchor at the correct offset.

@gregchapman-dev
Copy link
Copy Markdown
Contributor Author

I think this is ready for re-review now (assuming the tests pass, which they did locally).

@gregchapman-dev
Copy link
Copy Markdown
Contributor Author

Oops, forgot to change the version number(s). All ready now.

@gregchapman-dev
Copy link
Copy Markdown
Contributor Author

Hopefully the new doctests and description will make the benefit of this new feature clear. I am adding a feature that xmlToM21.py will use soon to import accurately <direction>s that have <offset>s.

@gregchapman-dev
Copy link
Copy Markdown
Contributor Author

Oh wow, changing version from 9.7.2a7 to 9.7.3 lowered coverage by 3 lines, because "a7" was not parsed. Before I made that change, coverage was actually increased (a very little) by this PR.

@mscuthbert
Copy link
Copy Markdown
Member

Closing and reopening for new tests, etc. (after resolving conflicts)

@mscuthbert
Copy link
Copy Markdown
Member

Hi Greg -- I worked my way through the PR again and it is a significant improvement that will greatly enhance getting spanners from MusicXML parsing correct.

I've accepted the offsetInScore path, but in the last passes, I've removed staffKey completely from spanner.py. That offset is used to filter pending assignments but staffKey is not - ended up confusing me and the spanner.py code too much. But PendingAssignementRef is now a frozen dataclass and is returned from setPendingSpannedElementAssignment which offers an easy path to using staff keys. For the MusicXML parsing branch I suggest doing this:

self.pendingAssignmentRefIdToStaff = {}
...
ref = bundle.setPendingAssignmentRef(spanner, 'Note', offsetInScore)
self.pendingAssignmentRefIdToStaff[id(ref)] = staffKey

Let me know if that works -- merging this now, and we can get other changes in a fresh PR.

Copy link
Copy Markdown
Member

@mscuthbert mscuthbert left a comment

Choose a reason for hiding this comment

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

Approving!

Comment thread music21/spanner.py Outdated
Now set up su1 to get the next note assigned to it. Stash off the staffKey (1) that
should be used for the SpannerAnchor, should a SpannerAnchor be needed.

>>> sb.setPendingSpannedElementAssignment(su1, 'Note', 0.0, staffKey=1)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

eventually all of these should take in an actual Class/type object instead of str.

@mscuthbert mscuthbert merged commit 7f3be08 into cuthbertLab:master May 13, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants