Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Clear cache when adding notes w/o sort #1357

Merged
merged 15 commits into from
Aug 9, 2022
Merged

Clear cache when adding notes w/o sort #1357

merged 15 commits into from
Aug 9, 2022

Conversation

mscuthbert
Copy link
Member

This was failing:

>>> c = chord.Chord('C4 E4 G4')
>>> c.isConsonant()
True

>>> c.add('C#4', runSort=False)
>>> c.isConsonant()
True

The cache was only being cleared during runSort=True, which is the default. But needs to happen either side.

Also caches the sort status, so repeated Chord.sort(inPlace=True) should be much faster.

@coveralls
Copy link

coveralls commented Aug 6, 2022

Coverage Status

Coverage decreased (-0.008%) to 93.092% when pulling 2c2b866 on chordCache_add into 83b7020 on master.

@mscuthbert
Copy link
Member Author

Requesting review from @jacobtylerwalls -- I think this is an improvement, but it makes one thing cached (chord's sort status) that requires better informing from pitches and notes when one of them changes. It might need some more cases.

Copy link
Member

@jacobtylerwalls jacobtylerwalls left a comment

Choose a reason for hiding this comment

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

Great, this is an improvement. I see why you wanted extra eyes.

Existing issue -- only one client is possible, so you can have situations like this. Not for this PR, but just mentioning:

>>> n = note.Note('F')
>>> c1 = chord.Chord([n])
>>> c2 = chord.Chord([n])
>>> c1.sortAscending(inPlace=True)
>>> c2.sortAscending(inPlace=True)
>>> n.transpose(6, inPlace=True)
>>> c2._cache
{}
>>> c1._cache
{'isSortedAscendingDiatonic': True}

Comment on lines 1819 to 1821
elif '_offsetDict' in self.__dict__:
newOffsetDict2: t.Dict[int, t.Tuple[OffsetQLSpecial, base.Music21Object]] = {}
setattr(new, '_offsetDict', newOffsetDict2)
Copy link
Member

Choose a reason for hiding this comment

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

This is trivial, but do you want to take the opportunity to simplify this? AFAICT _offsetDict in self.__dict__ will always be true, so this case and the case above amount to just self._offsetDict = {}.

music21/pitch.py Outdated
self._client: t.Optional['Pitch'] = None
self.client: t.Optional['music21.note.Note'] = None
Copy link
Member

Choose a reason for hiding this comment

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

This and the one below for Pitch is worth calling out in the release notes. I have code that would break if _chordAttached became public, and so I figure the same could apply here. I know private stuff can break at any time, so I'm not suggesting a deprecation cycle, but at the least just calling out in the release.

Copy link
Member Author

Choose a reason for hiding this comment

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

_client will remain private.

Copy link
Member Author

Choose a reason for hiding this comment

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

And ACK -- that was right before.

@@ -3989,6 +4025,7 @@ def semiClosedPosition(self, *, forceOctave=None, inPlace=False, leaveRedundantP
newRemainingPitches.append(p)
remainingPitches = newRemainingPitches

c2.clearCache()
Copy link
Member

Choose a reason for hiding this comment

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

The octave setter informs client, so I think you're okay--but belt and suspenders is fine.

@@ -2863,6 +2872,7 @@ def step(self, usrStr: StepName) -> None:
self.spellingIsInferred = False
else:
raise PitchException(f'Cannot make a step out of {usrStr!r}')
self.informClient()
Copy link
Member

Choose a reason for hiding this comment

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

great!

@mscuthbert
Copy link
Member Author

you're right -- maybe better to keep ._client private and just disable pylint any time we need to look at other._client.

@mscuthbert
Copy link
Member Author

>>> n = note.Note('F')
>>> c1 = chord.Chord([n])
>>> c2 = chord.Chord([n])
>>> c1.sortAscending(inPlace=True)
>>> c2.sortAscending(inPlace=True)
>>> n.transpose(6, inPlace=True)
>>> c2._cache
{}
>>> c1._cache
{'isSortedAscendingDiatonic': True}

oh... that is a thing. Need to consider a bit more.

The original plan when Chris Ariza and I designed the sites system was that things like ._chordAttached would be a site for an object -- that sites wouldn't just be Streams that they were in but other contexts, including things like interpretive elements (tuning systems, etc.) --so that there were sites and "locations" (Streams) which are the only things (besides None) that we're storing in Sites right now. Maybe that is the better option, since we have a lot of mechanisms for informing sites.

The same thing about having only one client for an object goes with Pitch objects as well.

Copy link
Member Author

@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.

fixing the mess made last time.

@mscuthbert mscuthbert merged commit 89d861e into master Aug 9, 2022
@mscuthbert mscuthbert deleted the chordCache_add branch January 3, 2024 20:12
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